问题
I have something like this in my show action:
def show
@blog = Blog.find(params[:id])
@new_comment = @blog.comments.build
end
Now in the view I do two things:
- I render the
_form.html.erbfor theCommentso that the user can add a comment to this blog - I want to be able to iterate over the existing comments for this blog in order to display them.
I am having problems with number 2. The issue is that as I iterate over the associated comments with this:
<% @blog.comments.each do |comment| %>
It is grabbing that @new_comment while iterating over the associated blogs. How can I exclude that built-but-not-yet-persisted @new_comment?
It would be nice if something like @blog.comments.each_with_id worked, or even @blog.comments.persisted.each. Ultimately I only want to iterate over the persisted comments associated to this blog.
I would prefer not to have to nest a conditional that asks if the comment is persisted?. I'm hoping there is an iterator out there for my current situation that just grabs the persisted records.
回答1:
How about if you create the new comment without using the association to the blog instance? Then it won't show up when you iterate through @blog.comments.
def show
@blog = Blog.find(params[:id])
@new_comment = Comment.new(blog: @blog)
end
回答2:
in your view loop, you can skip if comment.new_record?
<% @blog.comments.each do |comment| %>
<% next if comment.new_record? %>
EDIT per your comment:
if you dont want filter out during the iteration, you can reject new records before iterating. however, i wouldn't recommend this approach, as youre creating an entirely new array of records for little reason. Your performance shoundnt really take a hit assuming blogs dont have thousands of comments, but its still not a great practice.
<% @blog.comments.reject(&:new_record?).each do |comment| %>
if you truly want to separate the logic from the view and controller, you can make another variable entirely dedicated to blog comments, prior to building a new one, so that its not included during the iteration.
# controller
def show
@blog = Blog.find(params[:id])
@current_comments = @blog.comments
@new_comment = @blog.comments.build
end
#view
<% @current_comments.each do |comment| %>
for what its worth, i'd still recommend the first apprach
回答3:
You could add a class method to your Comment model such as this:
def self.persisted
reject { |comment| comment.new_record? }
end
Then call
@blog.comments.persisted
The downside is that it's not after this you don't have an ActiveRecord::Relation anymore and might break your scopes chaining. Make sure you're using it last in your ActiveRecord queries.
来源:https://stackoverflow.com/questions/36754188/rails-iterate-over-only-the-persisted-records-associated-to-an-object