Build vs new no Rails 3

125

Nos documentos do Rails 3 , o buildmétodo para associações é descrito como sendo o mesmo que o newmétodo, mas com a atribuição automática da chave estrangeira. Diretamente dos documentos:

Firm#clients.build (similar to Client.new("firm_id" => id))

Eu li similar em outro lugar.

No entanto, quando eu uso new(por exemplo, some_firm.clients.newsem nenhum parâmetro), a firm_idassociação do novo cliente é criada automaticamente. Estou olhando os resultados agora no console!

Estou esquecendo de algo? Os documentos estão um pouco desatualizados (improvável)? Qual é a diferença entre builde new?

Encerramento
fonte
3
Pessoas que procuram uma resposta rápida, verifique o 2º abaixo: "build" é apenas um pseudônimo para "new"
ivanreese

Respostas:

208

Você está interpretando mal os documentos um pouco. some_firm.client.newé a criação de um novo Clientobjeto da coleção clientes, e por isso pode automaticamente definir o firm_idque some_firm.id, ao passo que os documentos estão chamando Client.newque não tem conhecimento de ID de qualquer empresa em tudo, por isso precisa do firm_idpassado para ele.

A única diferença entre some_firm.clients.newe some_firm.clients.buildparece ser que buildtambém adiciona o cliente recém-criado à clientscoleção:

henrym:~/testapp$ rails c
Loading development environment (Rails 3.0.4)
r:001 > (some_firm = Firm.new).save # Create and save a new Firm
#=> true 
r:002 > some_firm.clients           # No clients yet
#=> [] 
r:003 > some_firm.clients.new       # Create a new client
#=> #<Client id: nil, firm_id: 1, created_at: nil, updated_at: nil> 
r:004 > some_firm.clients           # Still no clients
#=> [] 
r:005 > some_firm.clients.build     # Create a new client with build
#=> #<Client id: nil, firm_id: 1, created_at: nil, updated_at: nil> 
r:006 > some_firm.clients           # New client is added to clients 
#=> [#<Client id: nil, firm_id: 1, created_at: nil, updated_at: nil>] 
r:007 > some_firm.save
#=> true 
r:008 > some_firm.clients           # Saving firm also saves the attached client
#=> [#<Client id: 1, firm_id: 1, created_at: "2011-02-11 00:18:47",
updated_at: "2011-02-11 00:18:47">] 

Se você estiver criando um objeto por meio de uma associação, builddeve ter preferência sobre newcomo a build mantém seu objeto na memória some_firm(neste caso) em um estado consistente mesmo antes de qualquer objeto ter sido salvo no banco de dados.

henrym
fonte
8
Usando some_firm.client.newtambém acrescenta que o cliente some_firm.clients, e chamando saveon some_firmresultou em um erro de validação, indicando que clientera inválido. Se ambos newe buildadicionar o novo cliente à some_firmcoleção de clientes, o buildque newisso não faz? Sinto muito por ser densa, aqui!
ClosureCowboy
1
+1 Recebi seu resultado com 3.0.4. Eu adoraria que alguém com 3.0.3 pudesse confirmar que eu não sou louco.
ClosureCowboy
41
@henrym Parece que no 3.2.6 clients.new e customers.build são semelhantes, pois ambos adicionam o novo objeto à coleção. Eu queria adicionar um comentário a qualquer um que me deparei com este, enquanto pesquisando como eu fiz
Hubbard
11
Parece que não há diferença entre eles no Rails 3.2.3 #
Aditya Kapoor
4
Esta resposta não está correta para o Rails> 3.2.13, onde 'build' é apenas um alias para 'new'. Veja a resposta de @ HatemMahmoud abaixo.
Andreas
91

buildé apenas um alias para new:

alias build new

Pode encontrar o código completo: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation.rb#L74

Hatem Mahmoud
fonte
13
alias build newa partir dos trilhos 3.2.13
fontno 13/13
7
Isso é verdade apenas para algumas associações / relações. Associações singulares, por exemplo, têm definições totalmente diferentes para builde build_#{association}. Veja aqui e aqui .
coreyward
1
Isso ainda é verdade Rails 4?
precisa saber é o seguinte
1
aqui está o relatório de erros ... que sugere se você estava usando novos como restaurant.customers.new, como uma maneira de obter um novo cliente associado ao restaurante sem anexá-lo ao restaurant.customers, para usar o escopo ... como restaurant .customers.scoped.new
user3334690
11

Você está correto, a construção e as novas funções têm o mesmo efeito de definir a chave estrangeira, quando são chamadas por meio de uma associação. Acredito que a razão pela qual a documentação seja escrita dessa maneira é esclarecer que um novo objeto Cliente está sendo instanciado, em oposição a um novo relacionamento de registro ativo. Esse é o mesmo efeito que chamar .new em uma classe teria em Ruby. Ou seja, a documentação está esclarecendo que a criação de chamada em uma associação é a mesma coisa, está criando um novo objeto (chamando .new) e passando as chaves estrangeiras para esse objeto. Estes comandos são todos equivalentes:

Firm.first.clients.build
Firm.first.clients.new
Client.new(:firm_id => Firm.first.id)

Acredito que a razão .build existe é que Firm.first.clients.new pode ser interpretado como significando que você está criando um novo objeto has_many, em vez de um cliente real, então chamar .build é uma maneira de esclarecer isso.

Pan Thomakos
fonte
Então eles são equivalentes. Definitivamente é o que parece. Obrigado!
ClosureCowboy
5
Isso não está correto. Os dois primeiros são equivalentes nas versões posteriores do Rails (parece que no momento da publicação não eram). MAS, o último tem uma diferença significativa, pois o Firm.first.clients não conterá o novo cliente.
tybro0103
4

buildvs new:

principalmente novo e compilação são iguais, mas compilação armazena objetos na memória ,

por exemplo:

para novos:

Client.new(:firm_id=>Firm.first.id)

Para construção:

Firm.first.clients.build

Aqui, os clientes são armazenados na memória. Quando salvos com firmeza, os registros associados também são salvos.

Sarwan Kumar
fonte
2

Model.new

Tag.new post_id: 1instanciará uma tag com seu post_idconjunto.

@ model.models.new

@post.tags.buildfaz o mesmo E a tag instanciada estará presente @post.tagsmesmo antes de ser salva.

Isso significa @post.saveque salvará o @post e a tag recém-criada (assumindo: inverse_of está definido). Isso é ótimo porque o Rails validará os dois objetos antes de salvar e nenhum será salvo se um deles falhar na validação.

models.new vs models.build

@post.tags.builde @post.tags.newsão equivalentes (pelo menos desde o Rails 3.2).

tybro0103
fonte
que tal isso The only difference between some_firm.clients.new and some_firm.clients.build seems to be that build also adds the newly-created client to the clients collection:?
アレックス