In polymorphic associations, a model can belong to more than one model, on a single association.
Here is an example where a model is associated with two other models in Rails3. For example we have Events and Article model which have comments. So the “Comment” model is common between the “Event” and “Article” model. Here are the steps to implement the polymorphic association between these three models.
Step#1
Let’s create a resource “Comment” by rails generator.
rails g scaffold Comment content:text
Step#2
Add associations in the models as below
Comment model:
class Comment < ActiveRecord::Base attr_accessible :commentable_id, :commentable_type, :content belongs_to :commentable, :polymorphic => true #Now, it is acted as polymorphic end
Event model:
class Event < ActiveRecord::Base attr_accessible :name has_many :comments, :as => :commentable end
Article model:
class Article < ActiveRecord::Base attr_accessible :name has_many :comments, :as => :commentable end
Step#3
Add the following attributes in the migration files of the comment model
Look for newly created file under “db/migrate” folder
class CreateComments < ActiveRecord::Migration def change create_table :comments do |t| t.text :content t.references :commentable, :polymorphic => true t.timestamps end end end
Then execute rake db: migrate in the command line
Step#4
Add nested resources inside the “config/routes.rb” file
resources :events do resources :comments end resources :articles do resources :comments end
Step#5
Add link to add new comments in view page of article and events as follows
In “/app/views/events/show.html.erb”
<%= link_to 'New comment', new_event_comment_path(@event) %>
In /app/views/articles/show.html.erb
<%= link_to 'New comment', new_article_comment_path(@article) %>
Step#6
Changing the form_for tag in new comment page
In “/app/views/comments/_form.html.erb”
Before
<%= form_for (@comment) do |f| %>
After
<%= form_for [@commentable, @comment] do |f| %>
Add following codes in both “Articles” & “Events” controllers to get the comments individually
In “/app/controllers/events_controller.rb”
def show @event = Event.find(params[:id]) @comments= @event.comments #added to view all the comments for the selected event respond_to do |format| format.html # show.html.erb format.json { render json: @event } end end
In “/app/controllers/articles_controller.rb”
def show @article = Article.find(params[:id]) @comments= @article.comments #added to view all the comments for the selected article respond_to do |format| format.html # show.html.erb format.json { render json: @article } end end
Step#8
Add the following codes to “Comments” controller to creating a comment
In “/app/controllers/comments_controller.rb”
class CommentsController < ApplicationController def new @commentable = find_commentable @comment = Comment.new 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 end
Now the comment model will work as a polymorphic association between article and event model.