Say I have a basic Rails app with a basic one-to-many relationship where each comment belongs to an article:
$ rails blog
$ cd blog
$ script/generate model article name:string
$ script/generate model comment article:belongs_to body:text
Now I add in the code to create the associations, but I also want to be sure that when I create a comment, it always has an article:
class Article < ActiveRecord::Base
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :article
validates_presence_of :article_id
end
So now let's say I'd like to create an article with a comment all at once:
$ rake db:migrate
$ script/console
If you do this:
>> article = Article.new
=> #<Article id: nil, name: nil, created_at: nil, updated_at: nil>
>> article.comments.build
=> #<Comment id: nil, article_id: nil, body: nil, created_at: nil, updated_at: nil>
>> article.save!
You'll get this error:
ActiveRecord::RecordInvalid: Validation failed: Comments is invalid
Which makes sense, because the comment has no page_id yet.
>> article.comments.first.errors.on(:article_id)
=> "can't be blank"
So if I remove the validates_presence_of :article_id
from comment.rb
, then I could do the save, but that would also allow you to create comments without an article id. What's the typical way of handling this?
UPDATE: Based on Nicholas' suggestion, here's a implementation of save_with_comments that works but is ugly:
def save_with_comments
save_with_comments!
rescue
false
end
def save_with_comments!
transaction do
comments = self.comments.dup
self.comments = []
save!
comments.each do |c|
c.article = self
c.save!
end
end
true
end
Not sure I want add something like this for every one-to-many association. Andy is probably correct in that is just best to avoid trying to do a cascading save and use the nested attributes solution. I'll leave this open for a while to see if anyone has any other suggestions.