Rails iterate over only the persisted records associated to an object

蹲街弑〆低调 提交于 2019-12-08 08:45:20

问题


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:

  1. I render the _form.html.erb for the Comment so that the user can add a comment to this blog
  2. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!