Reputation: 1283
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
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
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