..

Polymorphic Associations Rails4

Polymorphism: As per Wiki, it is the provision of a single interface to entities of different types.

Polymorphic Associations (in Rails’ terms): With polymorphic associations, a model can belong to more than one other model, on a single association.

For example (in this blog), we will have a Comment model that belongs to either a Post model or a Forum model.

First, we generate our Comment model. Below command will generate model, migration and test.

rails g model Comment commentable_type:string commentable_id:integer user_id:integer body:text

then rake db:migrate

Now we will define our models as shown below:

class Comment < ActiveRecord::Base
  belongs_to :commentable, polymorphic: true
end
 
class Post < ActiveRecord::Base
  has_many :comments, as: :commentable
end
 
class Forum < ActiveRecord::Base
  has_many :comments, as: :commentable
end

Alright, that would be all for modeling. Lets go to Controllers:

We create comments_controller.rb for all models we want to use this polymorphic association. So for our example, we create

controllers > posts > comments_controller.rb controllers > forums > comments_controller.rb

Sample code for posts > comments_controller.rb

class Posts::CommentsController < ApplicationController
  before_action :authenticate_user!
  before_action :set_post

  # Create comment for post
  def create
    @comment = @post.comments.new(comment_params)
    @comment.user = current_user
    @comment.save
    redirect_to @post, notice: "Comment added successfully"
  end

  private
  
  def set_post
    @post = Post.find(params[:post_id])
  end

  def comment_params
    params.require(:comment).permit(:body)
  end
end

Similarly you can add for all the models using this polymorphic association. (You may create one comments_controller and put all common code in there).

Lets add routes for the comments at config/routes.rb

resources :posts do
  resources :comments, module: :posts
end
resources :forums do
  resource :comments, module: :forums
end

Okay, most of our setup is ready. Lets add code to view all comments and form to add one.

<h3>Comments</h3>
<% @post.comments.each do |comment| %>
  <div class="well right">
    <%= comment.body %>
  </div>
<% end %>
<%= form_for [@post, Comment.new] do |f| %>
  <div class="form-group">
    <%= f.text_area :body, class: "form-control" %>
  </div>
  <%= f.submit class: "btn btn-primary" %>
<% end %>

Alright, thats it. We have setup our polymorphic association.