#154 Polymorphic Association
Mar 23, 2009 | 8 minutes | Active Record, Routing
Polymorphic associations can be perplexing. In this episode I show you how to set it up in Active Record and then move to the controller and view layer.
- Download:
- source codeProject Files in Zip (191 KB)
- mp4Full Size H.264 Video (13.8 MB)
- m4vSmaller H.264 Video (9.32 MB)
- webmFull Size VP8 Video (25.7 MB)
- ogvFull Size Theora Video (20 MB)
There is a newer version of this episode, see the revised episode.
Resources
bash
script/generate nifty_scaffold comment content:text commentable_id:integer commentable_type:string
rake db:migrate
script/generate nifty_scaffold comment content:text commentable_id:integer commentable_type:string rake db:migrate
ruby
class Comment < ActiveRecord::Base
belongs_to :commentable, :polymorphic => true
end
class Article < ActiveRecord::Base
has_many :comments, :as => :commentable
end
class Photo < ActiveRecord::Base
has_many :comments, :as => :commentable
#...
end
class Event < ActiveRecord::Base
has_many :comments, :as => :commentable
end
# comments_controller
def index
@commentable = find_commentable
@comments = @commentable.comments
end
def create
@commentable = find_commentable
@comment = @commentable.comments.build(params[:comment])
if @comment.save
flash[:notice] = "Successfully created comment."
redirect_to :id => nil
else
render :action => 'new'
end
end
private
def find_commentable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
class Comment < ActiveRecord::Base belongs_to :commentable, :polymorphic => true end class Article < ActiveRecord::Base has_many :comments, :as => :commentable end class Photo < ActiveRecord::Base has_many :comments, :as => :commentable #... end class Event < ActiveRecord::Base has_many :comments, :as => :commentable end # comments_controller def index @commentable = find_commentable @comments = @commentable.comments end def create @commentable = find_commentable @comment = @commentable.comments.build(params[:comment]) if @comment.save flash[:notice] = "Successfully created comment." redirect_to :id => nil else render :action => 'new' end end private def find_commentable params.each do |name, value| if name =~ /(.+)_id$/ return $1.classify.constantize.find(value) end end nil end
routes.rb
map.resources :articles, :has_many => :comments
map.resources :photos, :has_many => :comments
map.resources :events, :has_many => :comments
map.resources :articles, :has_many => :comments map.resources :photos, :has_many => :comments map.resources :events, :has_many => :comments
comments/index.html.erb
<div id="comments">
<% for comment in @comments %>
<div class="comment">
<%=simple_format comment.content %>
</div>
<% end %>
</div>
<h2>New Comment</h2>
<% form_for [@commentable, Comment.new] do |f| %>
<p>
<%= f.label :content %><br />
<%= f.text_area :content %>
</p>
<p><%= f.submit "Submit" %></p>
<% end %>
<div id="comments"> <% for comment in @comments %> <div class="comment"> <%=simple_format comment.content %> </div> <% end %> </div> <h2>New Comment</h2> <% form_for [@commentable, Comment.new] do |f| %> <p> <%= f.label :content %><br /> <%= f.text_area :content %> </p> <p><%= f.submit "Submit" %></p> <% end %>

