Reputation: 11336
I imagine a query like this.
Movie.find_or_create_by_title(title: 'foo').photos.find_or_create_by_name(name: 'bar')
The given query will create the Photo
object but will not consider its parent Movie
.
=> #<Photo id: 3, movie_id: nil …
Is there any way I can pass the movie to it?
Update: The reason I try to "save both at once" is because I have a validation in place that requires a Movie to have at least one photo. See: https://stackoverflow.com/a/12962317/471313
Upvotes: 5
Views: 2968
Reputation: 1296
I'm using the updated Rails 3.2 syntax for find_or_create_by
since it will be deprecated in Rails 4.0. The important thing is to have the accepts_nested_attributes_for
in your Movie model like so:
class Movie < ActiveRecord::Base
has_many :photos
accepts_nested_attributes_for :photos
end
This allows you to specify a key in your model attributes with the form <relation-name>_attributes
, in your case photo_attributes
.
@movie = Movie.where(:title => 'foo').first_or_create :director => 'Steven Speilberg',
:photos_attributes => [{
:caption => "Thrilling!"
}]
@movie.save
After this, you just save the parent model, and that will automatically save the child models, again in your case photos. It is necessary to save the parent first because the child needs to know what id to put into the child record. So after @movie
is saved, it will then place it's id in the movie_id
field on the photos record. It can't save the child before the parent because then it doesn't know what id to use.
If you're using a Rails version before 3.2, it will look something like this:
@movie = Movie.find_or_create_by_title "W00t!", :director => 'Steven Speilberg',
:photos_attributes => [{
:caption => "Thrilling!"
}]
Upvotes: 4
Reputation: 14740
movie = Movie.where(title: 'foo').first
if movie.nil?
movie = Movie.new(title: 'foo')
movie.photos.build(name: 'bar')
movie.save
else
movie.photos.create(name: 'bar')
end
Upvotes: 0