Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails: How do I get only the saved models with .collection?

I have a model Post that has_many of model Comment.

On a Posts show action, there is a list of Comments found with @comments = @post.comments.

I also have a form for creating new Comments. The form has its object created with @comment = @post.comments.build.

This all works for listing and successfully creating comments.

The problem occurs when there is an error when the comment is submitted. The errors are shown in the same form (so, on Post#show) via render "posts/show". In this case, I have to set @comments = @post.comments again, but this time the list of comments includes the not-yet-saved comment that the user is trying to create.

I solved it by using @post.comments.all, which only gives me the saved models, but Rails complains that this is deprecated in Rails 4.

How do I remove the unsaved comment from the list of comments I get from @post.comments?

like image 226
jumoel Avatar asked Sep 17 '13 07:09

jumoel


People also ask

What does .save do in Ruby?

. save is an “Instance Method”, it returns either true or false depending on whether the object was saved successfully to the database or not. If the model is new, a record gets created in the database, otherwise the existing record gets updated.

What is Active Record in Ruby?

1 What is Active Record? Active Record is the M in MVC - the model - which is the layer of the system responsible for representing business data and logic. Active Record facilitates the creation and use of business objects whose data requires persistent storage to a database.


3 Answers

I ran into a similar issue with a Rails 5 application. This seemed like the most straightforward approach:

@comment = @post.comments.build
@comments = @post.comments.where.not(id: nil)
like image 61
allknowingfrog Avatar answered Oct 19 '22 12:10

allknowingfrog


You could add a scope to the comment model to find only database rows instead of in memory data, for example:

class Comment < ActiveRecord::Base
  scope :by_post, ->(post) { where(post: post) }
end

called by: @comments = Comment.by_post(@post)

like image 21
Matt Avatar answered Oct 19 '22 12:10

Matt


The most efficient way imho is just to ignore the new record in the view, instead of retrieving all comments again.

So in your view you will do something like:

= f.simple_fields_for :comments do |c|
  - unless c.object.new_record? 
    = render 'comment_fields', :f => c
like image 1
nathanvda Avatar answered Oct 19 '22 13:10

nathanvda