Cu1ture
Cu1ture

Reputation: 1283

Stop new @comment for comment form displaying on show page in @comments - Rails

Hi I am quite new to Rails and am just setting up comments for my Shop_Profile model. I am using the acts_as_commentable gem to allow for polymorphic comments. I am allowing comments on the profile Show page so am displaying the list of comments and the new comment form on the same page.

My Show Action in the ShopProfilesController looks like this:

def show
    @comments = @shop_profile.comments
    @comment = @shop_profile.comments.new
  end

And I am rendering the comment form and comments in the show view with:

<% if user_signed_in? %>
    <%= render 'comments/form' %>
<% end %>

<%= render @comments %>

My Create action on my comment controller is:

def create
    @comment = @user.comments.build(comment_params)
    @commentable = Comment.find_commentable(params[:comment][:commentable_type], params[:comment][:commentable_id])

    if @comment.save
      redirect_to @commentable
    end
  end

and my _comment partial is:

<p>
  <strong>Title:</strong>
  <%= comment.title %>
</p>

<p>
  <strong>Comment:</strong>
  <%= comment.comment %>
</p>

<p>
  <small>By:</small>
  <%= comment.user.username %>
</p>

The new @comment for the form keeps getting included in the @comments and is thus causing an error "undefined method `username' for nil:NilClass" because the new @commentn has no user_id. How can I display my @comments without including this new @comment for the form_for?

Thanks for any help

Upvotes: 1

Views: 225

Answers (2)

joelparkerhenderson
joelparkerhenderson

Reputation: 35453

You're creating an additional comment in your collection, and that new comment doesn't have an associated user yet, and isn't saved in the database yet.

If you want the new comment to be skipped entirely, you can do this:

<%= render @comments.reject{|c| c == @comment } %>

If you want the new comment to show up, but skip the "By" section, you can do this:

<% if comment != @comment %>
  <p>
    <small>By:</small>
    <%= comment.user.username %>
 </p>
<% end %>

Upvotes: 1

Nick Veys
Nick Veys

Reputation: 23939

Unfortunately (in this case) new/build adds the built object to the association's collection. So you'll need to declare your intent that you only want items stored in the database for the @comments collection.

You have two options I know of off the top of my head:

def show
  @comment = @shop_profile.comments.new
  @comments = @shop_profile.comments(true)
end

This forces the @comments to be loaded cleanly, so it will only contain the original list. Unfortunately you're hitting the database twice for the same list, that's silly.

Even better, I think, for this would be to do:

def show
  @comments = @shop_profile.comments.to_a
  @comment = @shop_profile.comments.new
end

So now you detatch the @comments collection from the active record association by making it an array, so the new call later on won't modify anything you still are holding on to.

Upvotes: 1

Related Questions