简体   繁体   中英

Adding Comments to multiple models

Im trying to add comments to my topics model the same way you can add comments to posts on my app. i currently have to partials for comments _comment.html.erb and _form.html.erb

_comment :

<%= content_tag :div, class: 'media', id: "comment-#{comment.id}" do %>
<div class= "media">
  <div class= "media-body">
    <small>
      <%= comment.user.name %> commented <%= time_ago_in_words(comment.created_at) %> ago
      <% if user_is_authorized_for_comment?(comment) %>
      | <%= link_to "Delete", [comment.post, comment], method: :delete %>
      <% end %>
    </small>
    <p> <%= comment.body %></p>
  </div>
</div>
<% end %>

_form :

<h4>Add a comment</h4>
<%= form_for [post, comment] do |f| %>
  <div class="form-group">
    <%= f.label :body, class: 'sr-only' %>
    <%= f.text_field :body, class: 'form-control', placeholder: "Enter a new comment" %>
  </div>
  <%= f.submit "Submit Comment", class: 'btn btn-default pull-right' %>
<% end %>

my topic show is :

#DISPLAY Topic comments here
<h3> Comments</h3>
<%= render @topic.comments %>
</div>
<% if current_user %>
<%= render 'comments/form', comment: Comment.new, post: @post %>
<% end %>
#------

comment controller :

  def create
    @post = Post.find(params[:post_id])
    comment = @post.comments.new(comment_params)
    comment.user = current_user

    if comment.save
      flash[:notice] = "Comment saved successfully."
      redirect_to [@post.topic, @post]
    else
      flash[:alert] = "Comment failed to save."
      redirect_to [@post.topic, @post]
    end
  end

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

    if comment.destroy
      flash[:notice] = "Comment was deleted"
      redirect_to [@post.topic, @post]
    end
  end

i have updated the routes for topic comments :

  resources :topics do
    resources :posts, except: [:index]
    resources :comments, only: [:create, :destroy]
  end

my question is do i need to create a separate partial to add comments to topics or can i update my _comment partial to work for both post and topic comments . and how can i accomplish this ?

Models

You'll need a polymorphic association on the Comment model:

#app/models/comment.rb
class Comment < ActiveRecord::Base
   belongs_to :commentable, polymorphic: true
end

#app/models/topic.rb
class Topic < ActiveRecord::Base
   has_many :comments, as: :commentable
end

#app/models/post.rb
class Post < ActiveRecord::Base
   has_many :comments, as: :commentable
end

Controllers

This will allow you to save the comments for your various models, the controllers / flow coming secondary:

#config/routes.rb
resources :topics, :posts do
   resources :comments, only: [:create, :destroy] #-> url.com/topics/:topic_id/comments
end

#app/controllers/comments_controller.rb
class CommentsController < ApplicationController
  def create
    id = params[:post_id] || params[:topic_id]
    if params[:post_id]
      @parent = Post.find id
    elsif params[:topic_id]
      @parent = Topic.find id
    end

    @comment = @parent.comments.find params[:id]
    @comment.save
  end

  def destroy
    @parent  = params[:post_id] || params[:topic_id]
    @comment = @parent.comments.new comment_params
    @comment.destroy
  end

  private

  def comment_params
    params.require(:comment).permit(:x, :y)
  end 
end 

Because you're passing the data to the comments controller, you'll only need to evaluate which @parent you're working with.


Views

For your views, you need to pass locals to your _form partial:

#app/views/posts/show.html.erb
<%= render "comments/form", locals: {parent: @post} %>

#app/views/comments/_form.html.erb
<%= form_for [parent, parent.comments.new] do |f| %>

I had this road-block as well and here is what I came up with that passed. I must first give @Richard Peck applause for getting my wheels turning, so thank you :).

Models

Did not implement a polymorphic association . Stuck with has_many and belongs_to , nothing more

Partials

_comment.html.erb

Set up the delete partial to accept "parent" as a local

<div class="media">
  <div class="media-body">
    <small>
      <%= comment.user.name %>
      commented
      <%= time_ago_in_words(comment.created_at) %>
      ago
      <% if user_is_authorized_for_comment_via_post?(comment) %>
      |
      <%= link_to "Delete", [parent, comment], method: :delete %>
      <% end %>
    </small>
    <p>
      <%= comment.body %>
    </p>
  </div>
</div>

_form.html.erb

same idea as _comment.html.erb, see above

<h4>Add a comment</h4>


  <%= form_for [parent, comment] do |f| %>
    <div class="form-group">
      <%= f.label :body, class: 'sr-only' %>
      <%= f.text_field :body, class: 'form-control', placeholder: "Enter a new comment" %>
    </div>

  <%= f.submit "Submit Comment", class: 'btn btn-default pull-right' %>

<% end %>

Setting up CommentController

...
  def create

    # upon clicking on create, determine what param id is passed
    if params[:post_id]
      # if it is a post id, set instance of post id as @parent
      @parent = Post.find(params[:post_id])
    elsif params[:topic_id]
      # if it is a topic id, set instance of topic id as @parent
      @parent = Topic.find(params[:topic_id])
    end

    # create instance as @comment.  Build/create
    # comment belonging to @parent (Topic or Post)
    @comment = @parent.comments.build(comment_params)
    # The comment must be associated to the current user.
    # A comment must have a user, and value of user within instance of @comment
    # is currently nil.  Set user id as current user
    @comment.user = current_user

    # save comment to database
    if @comment.save
      # direction of save through if and elsif
      # Redirection depends on the comment's parent.
      # .is_a? method determines if it is of a certain class.  Here, is @parent
      # of class Post?  Is @parents is the same parent id passed through params?
      if @parent.is_a?(Post) # template error with this included: (== params[:post_id])
        flash[:notice] = 'Comment saved successfully'
        redirect_to [@parent.topic, @parent]
      # if not part of the class Post, is it a Topic?  If so, save here and
      # redirect to the topic after save
      elsif @parent.is_a?(Topic)
        flash[:notice] = 'Comment saved successfully'
        redirect_to @parent
       end
    end
  end




  def destroy
    comment = Comment.find(params[:id])
    # @topic = Topic.find(params[:topic_id])
    # topic_comment = @topic.comments.find(params[:id])

    # @post = Post.find(params[:post_id])
    # post_comment = @post.comments.find(params[:id])

    if comment.destroy
      flash[:notice] = 'Comment was deleted'
      redirect_to :back
    else
      flash[:alert] = "Comment counld't be deleted. Try again"
      redirect_to :back
    end
  end
...

Passing in Comments from topic/show and post/show

topic/show

Note: notice how locals are passed into the controller from here

    ...
       <div class="row">
          <%= render 'comments/form', comment: Comment.new, parent: @topic  %>
       </div>
         <% @topic.comments.each do |comment| %>
           <%= render partial: 'comments/comment', locals: { parent:    @topic, comment: comment } %>
         <% end %>
...

post/show

  <% if current_user %>
    <% @post.comments.each do |comment| %>
      <%= render partial: 'comments/comment', locals: { parent: @post, comment: comment } %>
    <% end %>
  <% end %>
  <% if current_user %>
    <%= render 'comments/form', comment: Comment.new, parent: @post %>
  <% end %>

Hope this helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM