Ruby on Rails. Como uso o método .build do Active Record em um: pertence ao relacionamento?

128

Não consegui encontrar nenhuma documentação sobre o método .build no Rails (atualmente estou usando o 2.0.2).

Por meio da experimentação, parece que você pode usar o método de construção para adicionar um registro a um has_manyrelacionamento antes que qualquer registro seja salvo.

Por exemplo:

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

Isso salvará o cão e a etiqueta com as chaves estrangeiras corretamente. Isso não parece funcionar em um belongs_torelacionamento.

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

Eu também tentei

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

A chave estrangeira Dognão está definida neste caso devido ao fato de que, no momento em que é salva, a nova pessoa não possui um ID porque ainda não foi salva.

Minhas perguntas são:

  1. Como a construção funciona para que o Rails seja inteligente o suficiente para descobrir como salvar os registros na ordem certa?

  2. Como posso fazer a mesma coisa em um belongs_torelacionamento?

  3. Onde posso encontrar alguma documentação sobre esse método?

Obrigado

stellard
fonte
Em relação à documentação, consulte os Guias do Rails "Métodos adicionados por belongs_to" e "Métodos adicionados por has_one" . Mais documentação técnica pode ser encontrada nos documentos da API: belongs_toe has_one.
Dennis

Respostas:

147

Onde está documentado:

Na documentação da API sob a associação has_many em " Módulo ActiveRecord :: Associations :: ClassMethods "

collection.build (attribute = {},…) Retorna um ou mais novos objetos do tipo de coleção que foram instanciados com atributos e vinculados a esse objeto por meio de uma chave estrangeira, mas ainda não foram salvos. Nota: Isso funciona apenas se um objeto associado já existir, não se for nulo!

A resposta para construir na direção oposta é uma sintaxe ligeiramente alterada. No seu exemplo com os cães,

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

ou mesmo

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

Você também pode usar o create_dog para salvá-lo instantaneamente (assim como o método "create" correspondente, que você pode chamar na coleção)

Como os trilhos são inteligentes o suficiente? É mágico (ou mais precisamente, eu simplesmente não sei, adoraria descobrir!)

BushyMark
fonte
4
@BushyMark: usa method_missing ou metaporgramming para adicionar esses métodos com define_method.
Federico
@Federico Onde está o método ausente definido?
awilkening
1
@ alock27 O mesmo que o ActiveRecord usa o método que falta para você find_by_emaile find_by_column_namemétodos. Ele converte o método que você passa para uma string e a disseca e tenta combiná-lo com os nomes das colunas da sua tabela.
Bigpotato
Obrigado por seu comentário. Para ser claro, eu entendo como method_missing funciona. Eu estava tentando localizar o local real do arquivo que define esse método específico ausente.
awilkening
@ alock27 se você está perguntando porque quer ver como está definido, você deve conferir Metaprogramming Ruby. Mas se você realmente está procurando a localização real, provavelmente pode procurar no Google o código-fonte.
25413 MCB
48
@article = user.articles.build(:title => "MainTitle")
@article.save
nehpets
fonte
>> d.tags.build (: number => "123456") >> d.save # => true Não é o mesmo?
Antiqe