Question

I have items, that each have multiple (threaded) comments.
The threading is done via a parent key, that points towards another comment.

I just can't get the create action to work properly, I got it far enough to submit into the database, but it didn't have item_id and parent_id set.

I tried form_for [@item, @comment] instead of form_for :comment, url: item_comments_path( @item ) but it didn't help either.

When I look at comment_params in the create action I get this:

Parameters: {"utf8"=>"✓", "comment"=>{"body"=>"examplecommentgoeshere"}, "parent_id"=>"4", "commit"=>"Create Comment", "item_id"=>"4"}

Can anyone help?

Models:

class Item < ActiveRecord::Base
  belongs_to :user
  has_many :comments, dependent: :destroy
  has_many :images,   as: :item,
                      dependent: :destroy

  validates :title,       presence: true,
                          allow_blank: false
  validates :description, presence: true,
                          allow_blank: false
  validates :user,        presence: true,
                          allow_blank: false
  validates :layout,        presence: true
end


class Comment < ActiveRecord::Base
  belongs_to :user
  belongs_to :item
  has_many :responses,  class_name: "Comment",
                        foreign_key: "parent_id",
                        dependent: :destroy
  has_one :image,       as: :item,
                        dependent: :destroy
  belongs_to :parent,   class_name: "Comment"

  validates :body,      presence: true,
                        allow_blank: false,
                        length: { minimum: 10 }
end

Comment Controller:

class CommentsController < ApplicationController
  before_filter :findParent
  before_filter :find, only: [:update, :destroy, :show]
  before_filter :is_logged_in?, only: [:create, :update, :destroy]
  before_filter :has_permission?, only: [:update, :destroy]

  def new
    @comment = Comment.new
  end

  def create
    logger.debug comment_params.inspect
    @comment = current_user.comments.build(comment_params)

    if @comment.save
      redirect_to @item
    else
      logger.debug @comment.errors.inspect
      session[:errorbj] = @comment
      redirect_to @item
    end
  end
  [...]
  private
  def comment_params
    params.require(:comment).permit(:body, :parent)
  end

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

  private
  def findParent
    @item = Item.find params[:item_id]
  end

Item View:

<p>
<h3>Add a comment:</h3>
  <%= render partial: 'comments/form', locals: { parent: @item } %>
</p>

Partial comments/form:

<%= form_for :comment, url: item_comments_path( @item ) do |f| %>
  <p>
    <%= f.label :body %><br>
    <%= f.text_area :body %>
  </p>

  <p>
    <%= f.label :image %><br>
    &lt;nope&gt;
  </p>

  <%= hidden_field_tag :parent_id, parent.id %>
  <p>
    <%= f.submit %>
  </p>
<% end %>

From another stackoverflow thread I concluded that the only way to create an object in a multi-association is to do something along the lines of this:

@comment = current_user.comments.build( comment_params.join( { parent_id: <parent.id> } ) )

Other stackoverflow posts however said not to do

@item = Item.new( item_params.join( { user_id: current_user.id } )

So is there really no better way?

Was it helpful?

Solution 2

It turns out this is much easier than it seemed.

This is how I ended up doing it:

class CommentsController < ApplicationController
  before_filter :findParent, only: [:create]
  [...]
  def create
    @comment = current_user.comments.build(comment_params)
    @comment.item = @item
    if @comment.save
      redirect_to @item
    else
      session[:errorbj] = @comment
      redirect_to @item
    end
  end

OTHER TIPS

i think there are a lot of errors in your code. i hope that i can put that into a form that might help you figure out the fix by yourself:

  • use form_for [@item, @comment]
  • findParent should be find_parent
  • findParent should set a @parent
  • findParent should find a Comment
  • the new action should initialize with a parent @comment = Comment.new parent: @parent
  • hidden_field_tag :parent_id, parent.id should be form.hidden_field :parent
  • the parent association should be set via comment_params
  • you don't need the Rails.logger statement, its all in logs/development.log
  • don't put objects into the session
  • why is there item and image?

learn more about debugging! http://nofail.de/2013/10/debugging-rails-applications-in-development/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top