views:

43

answers:

2

I have a parent and child model relationship. In the child's migration.rb, the child model's columns each have default values (except the parent_id column).

When I make a new parent object, how can I make it so that a child object is created and saved into its table with the data from the default values along with the parent_id?

I'm thinking that it will have to do with something like an after_create on the parent model, but I'm not sure how to set it up.

+3  A: 

Revised: I revised the answer to use before_create and building, not creating, the associated models. The ActiveRecord machinery then takes care of saving the associated models once the parent is saved.

I even tested this code!

# in your Room model...
has_many :doors

before_create :build_main_door

private

def build_main_door
  # Build main door instance. Will use default params. One param (:main) is
  # set explicitly. The foreign key to the owning Room model is set
  doors.build(:main => true)
  true # Always return true in callbacks as the normal 'continue' state
end

####### has_one case:

# in your Room model...
has_one :door
before_create :build_main_door
private
def build_main_door
  # Build main door instance. Will use default params. One param (:main) is
  # set explicitly. The foreign key to the owning Room model is set
  build_door(:main => true)
  true # Always return true in callbacks as the normal 'continue' state
end

Added...

The build method is added by the owning model's machinery by the has_many statement. Since the example uses has_many :doors (model name Door), the build call is doors.build

See the docs for has_many and has_one to see all of the additional methods that are added.

# If the owning model has
has_many :user_infos   # note: use plural form

# then use
user_infos.build(...) # note: use plural form

# If the owning model has
has_one :user_info     # note: use singular form

# then use
build_user_info(...) # note: different form of build is added by has_one since
                     # has_one refers to a single object, not to an 
                     # array-like object (eg user_infos) that can be 
                     # augmented with a build method

Rails 2.x introduced the autosave option for associations. I don't think it applies to the above (I'm using default). Autosave testing results.

Larry K
The child model in my example is called "user_info", when I try to do `user_info.create(:main => true)` it errors and says `undefined method \`create' for nil:NilClass`
Reti
actually, the model is technically called `userInfo`
Reti
Try `UserInfo.create`
zetetic
UserInfo.create is not correct in this situation since it will not automagically handle the foreign-key to the owning model. Use either user_infos.create or create_user_info as shown in answer.@Reti: the model should be UserInfo, not userInfo. If the model name is really userInfo then you have a deeper problem to fix (best) or workaround.
Larry K
A: 

You didnt specify (or I overread it) what kind of relationship you are using. If you are using a one-to-one relationship, such as "has_one" create wont work. In this case you have to use something like this:

in parent.rb

has_one :child
before_create  {|parent| parent.build_child(self)}

after_create might work as well, havent tested that.

while in child.rb

belongs_to :parent

I was struggling with this quite a bit when setting up a user model in my current application.

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html You can see that has_one does not support parent.build or parent.create

Hope this helps. Im new to Ruby myself and slowly starting to make my way through the Ruby jungle. A nice journey but easy to get lost in. :)

Stefano