Ruby on Rails. How do I use the Active Record .build method in a :belongs to relationship?
Asked Answered
T

2

144

I have been unable to find any documentation on the .build method in Rails (i am currently using 2.0.2).

Through experimentation it seems you can use the build method to add a record into a has_many relationship before either record has been saved.

For example:

class Dog < ActiveRecord::Base
  has_many :tags
  belongs_to :person
end

class Person < ActiveRecord::Base
  has_many :dogs
end

# rails c
d = Dog.new
d.tags.build(:number => "123456")
d.save # => true

This will save both the dog and tag with the foreign keys properly. This does not seem to work in a belongs_to relationship.

d = Dog.new
d.person.build # => nil object on nil.build

I have also tried

d = Dog.new
d.person = Person.new
d.save # => true

The foreign key in Dog is not set in this case due to the fact that at the time it is saved, the new person does not have an id because it has not been saved yet.

My questions are:

  1. How does build work so that Rails is smart enough to figure out how to save the records in the right order?

  2. How can I do the same thing in a belongs_to relationship?

  3. Where can I find any documentation on this method?

Thank you

Trotyl answered 23/4, 2009 at 21:23 Comment(1)
Regarding documentation, see the Rails Guides "Methods added by belongs_to" and "Methods Added by has_one". More technical documentation can be found in the API docs: belongs_to and has_one.Fustanella
K
157

Where it is documented:

From the API documentation under the has_many association in "Module ActiveRecord::Associations::ClassMethods"

collection.build(attributes = {}, …) Returns one or more new objects of the collection type that have been instantiated with attributes and linked to this object through a foreign key, but have not yet been saved. Note: This only works if an associated object already exists, not if it‘s nil!

The answer to building in the opposite direction is a slightly altered syntax. In your example with the dogs,

Class Dog
   has_many :tags
   belongs_to :person
end

Class Person
  has_many :dogs
end

d = Dog.new
d.build_person(:attributes => "go", :here => "like normal")

or even

t = Tag.new
t.build_dog(:name => "Rover", :breed => "Maltese")

You can also use create_dog to have it saved instantly (much like the corresponding "create" method you can call on the collection)

How is rails smart enough? It's magic (or more accurately, I just don't know, would love to find out!)

Kabuki answered 24/4, 2009 at 2:17 Comment(6)
@BushyMark: it uses method_missing or metaporgramming to add those methods with define_method.Playroom
@Playroom where is the method missing defined?Shih
@alock27 Same as how ActiveRecord uses method missing for your find_by_email and find_by_column_name methods. It converts the method you pass to a string and dissects it and tries to match it with your table's column names.Kist
@edmund Thanks for your comment. To be clear, I understand how method_missing works. I was trying to locate the actual location of the file that defines this particular method missing.Shih
@alock27 if you're asking because you want to look into how it's defined you should check out Metaprogramming Ruby. But if you really are looking for the actual location you could probably Google for the source code.Pily
Some observations: - Most online tutorials will put has_many, belongs_to in models which never worked for me. - In reality, along with editing models,we need to MODIFY THE CONTROLLERS as well,Hectic
A
52
@article = user.articles.build(:title => "MainTitle")
@article.save
Alfreda answered 15/12, 2010 at 16:1 Comment(1)
>> d.tags.build(:number => "123456") >> d.save # => true Not the same?Immerge

© 2022 - 2024 — McMap. All rights reserved.