Katie H
Katie H

Reputation: 2293

Comments on multiple models

Within my rails app, I currently have comments setup to work with my posts model, which is functioning properly. How do I add comments to my books model?

Here is what I have so far:

Here is what I have in my schema for the comments:

 create_table "comments", force: true do |t|
    t.text     "body"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.integer  "user_id"
    t.integer  "post_id"
    t.integer  "book_id"
  end

In my user model:

class User < ActiveRecord::Base
  has_many :comments
  acts_as_voter
end

In my post model:

class Post < ActiveRecord::Base
  has_many :comments
end

In my book model:

class Book < ActiveRecord::Base
  has_many :comments
end

In my comment model:

class Comment < ActiveRecord::Base
  belongs_to :post
  belongs_to :book
  belongs_to :user
  acts_as_votable
end

In my comments controller:

class CommentsController < ApplicationController
  def create
    post.comments.create(new_comment_params) do |comment|
      comment.user = current_user
    end
    respond_to do |format|
    format.html {redirect_to post_path(post)}
    end
  end


  def upvote
  @post = Post.find(params[:post_id])
  @comment = @post.comments.find(params[:id])
  @comment.liked_by current_user

  respond_to do |format|
        format.html {redirect_to @post}
    end
end


  private

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

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

end

In my routes file:

resources :posts do
    resources :comments do
    member do
      put "like", to: "comments#upvote"
    end
  end
  end

In my view:

<% @post.comments.each do |comment| %>
  <%= comment.body  %>

  <% if user_signed_in? && (current_user != comment.user) && !(current_user.voted_for? comment) %>

<%= link_to “up vote”, like_post_comment_path(@post, comment), method: :put %>

<%= comment.votes.size %>

<% else %>

<%= comment.votes.size  %></a>

<% end %>
<% end %>


<br />


<%= form_for([@post, @post.comments.build]) do |f| %>

  <p><%= f.text_area :body, :cols => "80", :rows => "10" %></p>

  <p><%= f.submit “comment” %></p>

<% end %>

What do I add to my comments controller to get comments working on both posts and books? What do I add to my routes file?

Thanks in advance for any help.

Upvotes: 2

Views: 1209

Answers (1)

Nick Veys
Nick Veys

Reputation: 23939

You don't want to specify each type of object that can hold Comment objects. That creates a headache of if-elsif-else blocks all over the place. Instead, you want things to be Commentable, and they all will have .comments on them.

This is called a polymorphic association in Active Record. So you would have your models something like:

class Comment < ActiveRecord::Base
  belongs_to :commentable, polymorphic: true
end

class Post < ActiveRecord::Base
  has_many :comments, as: :commentable
end

class Book < ActiveRecord::Base
  has_many :comments, as: :commentable
end

And modify your database accordingly, it's all in the linked article. Now when you build a Comment object for a form, it will have pre-populated a commentable_id and commentable_type, which you can toss in hidden fields. Now it doesn't matter what the Comment is associated with, you always treat it the same.

I'd leave User as a separate association, since it's not really the same idea.

Upvotes: 10

Related Questions