Build vs new in Rails 3


125

Nei documenti di Rails 3 , il buildmetodo per le associazioni è descritto come lo stesso del newmetodo, ma con l'assegnazione automatica della chiave esterna. Direttamente dai documenti:

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

Ho letto simili altrove.

Tuttavia, quando utilizzo new(ad es. some_firm.clients.newSenza parametri), viene automaticamente creata l' firm_idassociazione del nuovo cliente . Sto fissando i risultati proprio ora nella console!

Mi sto perdendo qualcosa? I documenti sono un po 'obsoleti (improbabili)? Qual è la differenza tra builde new?


3
Le persone in cerca di una risposta rapida, controllano la seconda in basso: "build" è solo un alias per "new"
ivanreese

Risposte:


208

Stai leggendo male i documenti. some_firm.client.newsta creando un nuovo Clientoggetto dalla raccolta di client e quindi può impostare automaticamente il firm_idto some_firm.id, mentre i documenti chiamano Client.newche non ha alcuna conoscenza dell'ID di nessuna società, quindi deve essere firm_idpassato ad esso.

L'unica differenza tra some_firm.clients.newe some_firm.clients.buildsembra essere che buildaggiunge anche il client appena creato alla clientsraccolta:

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 stai creando un oggetto attraverso un'associazione, builddovrebbe essere preferito rispetto a newcome build mantiene l'oggetto in memoria, some_firm(in questo caso) in uno stato coerente anche prima che qualsiasi oggetto sia stato salvato nel database.


8
Utilizzando some_firm.client.newaggiunge anche il cliente a some_firm.clients, e chiamando savesul some_firmprovocato un errore di convalida che indica che clientè stato valido. Se entrambi newe buildaggiungono il nuovo client alla some_firmraccolta client, cosa non buildfa questo new? Mi dispiace per essere denso, qui!
ClosureCowboy,

1
+1 Ho ricevuto il tuo risultato con 3.0.4. Mi piacerebbe se qualcuno con 3.0.3 potesse confermare che non sono pazzo.
ClosureCowboy,

41
@henrym Sembra che in 3.2.6 i client.new e i client.build siano simili in quanto entrambi aggiungono il nuovo oggetto nella raccolta. Volevo aggiungere un commento per chiunque si fosse imbattuto in questo mentre cercavo su Google come me
hubbard,

11
Sembra che non ci siano differenze tra loro in Rails 3.2.3
Aditya Kapoor,

4
Questa risposta non è corretta per Rails> 3.2.13, dove 'build' è solo un alias per 'new'. Vedi la risposta di @ HatemMahmoud di seguito.
Andreas,

91

buildè solo un alias per new:

alias build new

È possibile trovare il codice completo: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation.rb#L74


13
alias build newa partire dalle rotaie 3.2.13
fontno,

7
Questo è vero solo per alcune associazioni / relazioni. Le associazioni singolari, ad esempio, hanno definizioni completamente diverse per builde build_#{association}. Vedi qui e qui .
coreyward

1
Questo è ancora vero per Rails 4?
fatman13

1
ecco la segnalazione di bug ... che suggerisce se stavi usando nuovi come restaurant.customers.new, come modo per ottenere un nuovo cliente associato al ristorante senza aggiungerlo a restaurant.customers, per usare scoped ... come restaurant .customers.scoped.new
user3334690

11

Hai ragione, le funzioni build e new hanno lo stesso effetto dell'impostazione della chiave esterna, quando vengono chiamate attraverso un'associazione. Credo che il motivo per cui la documentazione sia scritta in questo modo sia per chiarire che un nuovo oggetto Client viene istanziato, al contrario di una nuova relazione di record attiva. Questo è lo stesso effetto che chiamare Ruby su una classe avrebbe in Ruby. Vale a dire che la documentazione chiarisce che chiamare build su un'associazione è lo stesso creando un nuovo oggetto (chiamando .new) e passando le chiavi esterne a quell'oggetto. Questi comandi sono tutti equivalenti:

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

Credo che il motivo per cui .build esiste sia che Firm.first.clients.new potrebbe essere interpretato nel senso che stai creando un nuovo oggetto relazione has_many, piuttosto che un client reale, quindi chiamare .build è un modo per chiarire questo.


Quindi sono equivalenti. Questo è sicuramente quello che sembra. Grazie!
ClosureCowboy,

5
Questo non è corretto I primi due sono equivalenti nelle versioni successive di Rails (sembra che al momento della pubblicazione non lo fossero). MA, l'ultimo ha una differenza significativa nel fatto che Firm.first.clients non conterrà il nuovo client.
tybro0103,

4

buildvs new:

per lo più nuovi e build sono uguali ma build memorizza oggetti in memoria ,

per esempio:

per i nuovi:

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

Per costruire:

Firm.first.clients.build

Qui i client vengono archiviati in memoria, quando vengono salvati i dati associati vengono salvati.


2

Model.new

Tag.new post_id: 1istanzerà un tag con il suo post_idset.

@ model.models.new

@post.tags.buildfa lo stesso E il Tag istanziato sarà presente @post.tagsanche prima di essere salvato.

Ciò significa @post.saveche salverà sia il tag @post sia il tag appena costruito (supponendo che sia impostato inverse_of). Questo è fantastico perché Rails convaliderà entrambi gli oggetti prima di salvarli e nessuno dei due verrà salvato se uno di essi fallisce la convalida.

models.new vs models.build

@post.tags.builde @post.tags.newsono equivalenti (almeno da Rails 3.2).


che ne dici di questo 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:?
ア レ ッ ク ス
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.