How to Add Polymorphic Comments to Feed?

半腔热情 提交于 2019-12-11 02:48:15

问题


I'm trying to allow users to add and see comments directly on their activities feed, instead of having to go to a show page, which is what I got up to with this railscast episode: http://railscasts.com/episodes/154-polymorphic-association-revised.

I created the activities feed from scratch.

Below is one of the attempt's I made. I added the logic directly into the index action:

class ActivitiesController < ApplicationController
    def index
      @activities = Activity.order("created_at desc").where(current_user.following_ids)
      @activity = Activity.find(params[:id])
      @commentable = @activity
      @comments = @commentable.comments
      @comment = Comment.new
    end
end

which tells me: ActiveRecord::RecordNotFound in ActivitiesController#index Couldn't find Activity with 'id'=

I attempted to render the comments partials directly in the activities index:

<% @activities.each do |activity| %>
  <%= link_to activity.user.name, activity.user %>
  <%= render "activities/#{activity.trackable_type.underscore}/#{activity.action}", activity: activity %>

  <%= render "comments/comments" %>
  <%= render "comments/form" %>
<% end %>

comments/comments & comments/form

<% @comments.each do |comment| %>
  <%= User.find(comment.user_id).name %>
  <%= simple_format comment.content %>
<% end %>

<%= form_for [@commentable, @comment] do |f| %>
  <%= f.text_area :content, rows: 4, class: 'form-control', placeholder: 'Enter Comment' %>
  <%= button_tag(type: 'submit', class: "btn") do %>
    <span class="glyphicon glyphicon-plus"></span> Comment
  <% end %>
<% end %>

activity.rb

class Activity < ActiveRecord::Base
  belongs_to :user
  has_many :comments, as: :commentable
  belongs_to :trackable, polymorphic: true
end

Thank you for your expertise!

UPDATE

comments_controller.rb

class CommentsController < ApplicationController
    before_action :load_commentable
  before_action :set_comment, only: [:show, :edit, :update, :destroy, :like]
  before_action :logged_in_user, only: [:create, :destroy]

    def index
        @comments = @commentable.comments
    end

    def new
        @comment = @commentable.comments.new
    end

    def create
        @comment = @commentable.comments.new(comment_params)
        if @comment.save
            redirect_to @commentable, notice: "comment created."
        else
            render :new
        end
    end

    def edit
        @comment = current_user.comments.find(params[:id])
    end

    def update
        @comment = current_user.comments.find(params[:id])
        if @comment.update_attributes(comment_params)
            redirect_to @commentable, notice: "Comment was updated."
        else
            render :edit
        end
    end

    def destroy
        @comment = current_user.comments.find(params[:id])
        @comment.destroy
        redirect_to @commentable, notice: "comment destroyed."
    end

  def like
    @comment = Comment.find(params[:id])
    @comment_like = current_user.comment_likes.build(comment: @comment)
    if @comment_like.save
            @comment.increment!(:likes)
        flash[:success] = 'Thanks for liking!'
    else
        flash[:error] = 'Two many likes'
      end  
        redirect_to(:back)
  end

private
  def set_comment
    @comment = Comment.find(params[:id])
  end

    def load_commentable
        resource, id = request.path.split('/')[1, 2]
        @commentable = resource.singularize.classify.constantize.find(id)
    end

    def comment_params
        params[:comment][:user_id] = current_user.id
        params.require(:comment).permit(:content, :commentable, :user_id, :like)
    end
end

schema

create_table "activities", force: true do |t|
  t.integer  "user_id"
  t.string   "action"
  t.integer  "trackable_id"
  t.string   "trackable_type"
  t.datetime "created_at",     null: false
  t.datetime "updated_at",     null: false
end

add_index "activities", ["trackable_id"], name: "index_activities_on_trackable_id"
add_index "activities", ["user_id"], name: "index_activities_on_user_id"

                   activities GET    /activities(.:format)                                        activities#index
                              POST   /activities(.:format)                                        activities#create
                 new_activity GET    /activities/new(.:format)                                    activities#new
                edit_activity GET    /activities/:id/edit(.:format)                               activities#edit
                     activity GET    /activities/:id(.:format)                                    activities#show
                              PATCH  /activities/:id(.:format)                                    activities#update
                              PUT    /activities/:id(.:format)                                    activities#update
                              DELETE /activities/:id(.:format)                                    activities#destroy

回答1:


You can do as following:

# activites/index.html.erb
<% @activities.each do |activity| %>
  # etc.

  <%= render "comments/comments", comments: activity.comments %>
  <%= render "comments/form" %>
<% end %>

# comments/_comments.html.erb
<% comments.each do |comment| %>
  # your code to display each comment
<% end %>

You can see that I passed an argument to the render method:

render "comments/comments", comments: activity.comments

It will give to the _comments partial the local variable comments which will be equal to activity.comments.


You can even do the almost-same-thing with the form partial:

# activites/index.html.erb
<%= render "comments/form", new_comment: Comment.new(commentable_id: activity.id, commentable_type: activity.class.model_name) %>

# comments/_form.html.erb
<% form_for new_comment do |f| %>

Also, a good practice in Ruby on Rails is to not create several instance variables @like_this_one. Keep it to the minimum because it can be confusing. I will add that your variable naming is important too.

The following:

@activity = Activity.find(params[:id])
@commentable = @activity
@comments = @commentable.comments

Could be refactored as:

@activity = Activity.find(params[:id])

And then in your views you could access to the comments by doing:

@activity.comments


来源:https://stackoverflow.com/questions/29778140/how-to-add-polymorphic-comments-to-feed

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!