Ruby on Rails. ¿Cómo uso el método Active Record .build en un: pertenece a una relación?

128

No he podido encontrar ninguna documentación sobre el método .build en Rails (actualmente estoy usando 2.0.2).

A través de la experimentación, parece que puede usar el método de compilación para agregar un registro a una has_manyrelación antes de que cualquiera de los registros se haya guardado.

Por ejemplo:

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

Esto guardará tanto el perro como la etiqueta con las claves externas correctamente. Esto no parece funcionar en una belongs_torelación.

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

También he intentado

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

La clave foránea Dogno está configurada en este caso debido al hecho de que en el momento en que se guarda, la nueva persona no tiene una identificación porque aún no se ha guardado.

Mis preguntas son:

  1. ¿Cómo funciona Build para que Rails sea lo suficientemente inteligente como para descubrir cómo guardar los registros en el orden correcto?

  2. ¿Cómo puedo hacer lo mismo en una belongs_torelación?

  3. ¿Dónde puedo encontrar documentación sobre este método?

Gracias

Stellard
fuente
Con respecto a la documentación, consulte las Guías de Rails "Métodos agregados por belongs_to" y "Métodos agregados por has_one" . Se puede encontrar más documentación técnica en los documentos de API: belongs_toy has_one.
Dennis

Respuestas:

147

Donde está documentado:

De la documentación de la API bajo la asociación has_many en " Módulo ActiveRecord :: Asociaciones :: ClassMethods "

collection.build (atributos = {}, ...) Devuelve uno o más objetos nuevos del tipo de colección que han sido instanciados con atributos y vinculados a este objeto a través de una clave foránea, pero que aún no se han guardado. Nota: ¡Esto solo funciona si ya existe un objeto asociado, no si es nulo!

La respuesta para construir en la dirección opuesta es una sintaxis ligeramente alterada. En tu ejemplo con los perros,

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")

o incluso

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

También puede usar create_dog para que se guarde instantáneamente (al igual que el método "crear" correspondiente al que puede llamar en la colección)

¿Cómo son los rieles lo suficientemente inteligentes? Es mágico (o más exactamente, simplemente no lo sé, ¡me encantaría descubrirlo!)

BushyMark
fuente
44
@BushyMark: utiliza method_missing o metaporgramming para agregar esos métodos con define_method.
Federico
@Federico, ¿dónde se define el método que falta?
despertar
1
@ alock27 Igual que la forma en ActiveRecord utiliza el método faltante para sus find_by_emaily find_by_column_namemétodos. Convierte el método que pasa en una cadena y lo disecciona e intenta asociarlo con los nombres de columna de su tabla.
bigpotato
@edmund Gracias por tu comentario. Para ser claros, entiendo cómo funciona method_missing. Estaba tratando de localizar la ubicación real del archivo que define este método en particular que falta.
Despertar el
@ alock27 si está preguntando porque quiere ver cómo se define, debe consultar Metaprogramming Ruby. Pero si realmente está buscando la ubicación real, probablemente podría buscar el código fuente en Google.
MCB
48
@article = user.articles.build(:title => "MainTitle")
@article.save
nehpets
fuente
>> d.tags.build (: number => "123456") >> d.save # => true ¿No es lo mismo?
antiqe