#154 Polymorphic Association (revised)
May 19, 2012 | 11 minutes | Active Record, Routing
A polymorphic association allows a model to belong_to different types of other models. Here I show how to make a single comment model belong to articles, photos, and events.
- Download:
- source codeProject Files in Zip (321 KB)
- mp4Full Size H.264 Video (19.5 MB)
- m4vSmaller H.264 Video (11.6 MB)
- webmFull Size VP8 Video (14.8 MB)
- ogvFull Size Theora Video (24.4 MB)
terminal
rails g model comment content:text commentable_id:integer commentable_type rake db:migrate rails g controller comments index new
migrations/create_comments.rb
def change create_table :comments do |t| t.text :content t.belongs_to :commentable, polymorphic: true t.timestamps end add_index :comments, [:commentable_id, :commentable_type] end
models/comment.rb
class Comment < ActiveRecord::Base attr_accessible :content belongs_to :commentable, polymorphic: true end
models/article.rb
class Article < ActiveRecord::Base attr_accessible :content, :name has_many :comments, as: :commentable end
routes.rb
resources :articles do resources :comments end resources :photos do resources :comments end resources :events do resources :comments end
comments_controller.rb
class CommentsController < ApplicationController before_filter :load_commentable def index @comments = @commentable.comments end def new @comment = @commentable.comments.new end def create @comment = @commentable.comments.new(params[:comment]) if @comment.save redirect_to @commentable, notice: "Comment created." else render :new end end private def load_commentable resource, id = request.path.split('/')[1, 2] @commentable = resource.singularize.classify.constantize.find(id) end # alternative option: # def load_commentable # klass = [Article, Photo, Event].detect { |c| params["#{c.name.underscore}_id"] } # @commentable = klass.find(params["#{klass.name.underscore}_id"]) # end end
comments/index.html.erb
<%= link_to "New Comment", [:new, @commentable, :comment] %>
comments/_form.html.erb
<%= form_for [@commentable, @comment] do |f| %>
articles_controller.rb
def show @article = Article.find(params[:id]) @commentable = @article @comments = @commentable.comments @comment = Comment.new end