stackow1
stackow1

Reputation: 311

How to display all comments?

Please help me to display all the comments for certain thread.

I use the following gems: 'awesome_nested_set', 'acts_as_commentable_with_threading'

For example, I create scaffold 'message'. And I try for certain message unit make comments thread.

MessagesController:

def show
  # to display all comments
  @all_comments = @message.comment_threads  
  p '-----------------'
  p @all_comments
  p @all_comments.count

  # for form new comment
  @message = Message.find(params[:id])
  @user_who_commented = current_user
  @comment = Comment.build_from( @message, @user_who_commented.id, "Hey guys this is my comment!" )      
end

views/messages/show.html.erb:

<p>
  <strong>message Title:</strong>
  <%= @message.title %>
</p>

<p>
  <strong>message Body:</strong>
  <%= @message.body %>
</p>

<%= render 'comments/form' %>

<% @all_comments.each do |comment| %>
  <div>
    <%= @comment.title %>
    <%= @comment.body %>
  </div>
<% end %>

schema:

create_table "comments", force: :cascade do |t|
  t.integer  "commentable_id"
  t.string   "commentable_type"
  t.string   "title"
  t.text     "body"
  t.string   "subject"
  t.integer  "user_id",          null: false
  t.integer  "parent_id"
  t.integer  "lft"
  t.integer  "rgt"
  t.datetime "created_at"
  t.datetime "updated_at"
end

in this table after add new comment i(and gem) filled via create-action fields:

title,
body,
user_id,
lft,
rgt

CommentsController:

def create
  comment = Comment.new(comment_params)
  comment.user = current_user
  comment.save

  if comment.update_attributes(user: current_user)
    redirect_to messages_path, notice: 'Comment was successfully created.' 
  else
    render :new 
  end
end

def new
  @comment = Comment.new
end

The form to add a new message worked ok, but all comments for certain messages are not displayed.

ps: log:

Started GET "/messages/1" for 127.0.0.1 at 2015-10-23 14:09:47 +0300
Processing by MessagesController#show as HTML
  Parameters: {"id"=>"1"}
  Message Load (0.1ms)  SELECT  "messages".* FROM "messages" WHERE "messages"."id" = ? LIMIT 1  [["id", 1]]
"-----------------"
  Comment Load (0.1ms)  SELECT "comments".* FROM "comments" WHERE "comments"."commentable_id" = ? AND "comments"."commentable_type" = ?  [["commentable_id", 1], ["commentable_type", "Message"]]
#<ActiveRecord::Associations::CollectionProxy []>
   (0.1ms)  SELECT COUNT(*) FROM "comments" WHERE "comments"."commentable_id" = ? AND "comments"."commentable_type" = ?  [["commentable_id", 1], ["commentable_type", "Message"]]
0
  CACHE (0.0ms)  SELECT  "messages".* FROM "messages" WHERE "messages"."id" = ? LIMIT 1  [["id", "1"]]
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ?  ORDER BY "users"."id" ASC LIMIT 1  [["id", 2]]
  Rendered comments/_form.html.erb (1.0ms)
  Rendered messages/show.html.erb within layouts/application (1.9ms)
Completed 200 OK in 40ms (Views: 34.5ms | ActiveRecord: 0.4ms)

Upvotes: 1

Views: 521

Answers (1)

Richard Peck
Richard Peck

Reputation: 76774

Why are you outputting in the show action?

You should only be defining @instance_variables and passing them to the view for rendering:


#config/routes.rb
resources :users do
   resources :comments, only: [:show, :create]
end

#app/controllers/messages_controller.rb
class MessagesController < ApplicationController
    def show
        @message = Message.find params[:id]
    end
end

#app/views/messages/show.html.erb
<%= @message.title %>
<%= render @message.comments if @message.comments.any? %>

#app/views/messages/_comment.html.erb
<% comment.title %>
<% comment.body %>

This will output the top-level comments.

If you wanted nested comments, I'd highly recommend using acts_as_tree. This gives you access to "child" objects (set with a parent column in your table), which allows you to do the following:

<%= render @message.comments if @message.comments.any? %>

#app/views/messages/_comment.html.erb
<%= render comment.children if comment.children.any? %>

Notes

1. Vars

When you run a loop (<% @message.comments.each do |comment| %>), you need to use the local variable within the block:

@message.comments.each do |comment|
   comment.title
   comment.body
end

You're currently using @comment.title -- should be comment.title

-

2. Comment Creation

You can make comment creation through a form embedded in the messages#show view:

#app/views/messages/show.html.erb
<%= render "comments/new" %>

You'd have to make sure you set your @comment variable:

#app/controllers/messages_controller.rb
class MessagesController < ApplicationController
   def show
      @message = Message.find params[:id]
      @comment = Comment.new
   end
end 

#app/controllers/comments_controller.rb
class CommentsController < ApplicationController
   def create
      @comment = Comment.new comment_params
   end

   private

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

You're doing this already, of course - I think it could be cleared up a lot.

-

3. Migration

Finally, you're using a polymorphic association in your table. This should not be used in this case; you should have a standard foreign_key as follows:

enter image description here

create_table "comments", force: :cascade do |t|
  t.integer  "message_id"
  t.string   "title"
  t.text     "body"
  t.string   "subject"
  t.integer  "user_id",          null: false
  t.integer  "parent_id"
  t.datetime "created_at"
  t.datetime "updated_at"
end

This would allow for the following:

#app/models/message.rb
class Message < ActiveRecord::Base
   has_many :comments
end

#app/models/comment.rb
class Comment < ActiveRecord::Base
   belongs_to :message
   belongs_to :user

   acts_as_tree
end

Upvotes: 2

Related Questions