2011-02-10 14 views
115

In Rails 3 docs, il metodo build per associazioni è descritto come il metodo new, ma con l'assegnazione automatica della chiave esterna. Direttamente dai documenti:Build vs new in Rails 3

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

Ho letto simile altrove.

Tuttavia, quando uso new (ad esempio some_firm.clients.new senza alcun parametro), l'associazione firm_id nuovo cliente è creato automaticamente. Sto guardando i risultati adesso nella console!

Mi manca qualcosa? I documenti sono un po 'obsoleti (improbabile)? Qual è la differenza tra build e new?

+3

Persone in cerca di una risposta rapida, controllare il 2 ° verso il basso: "costruire" è solo un alias per "nuovo" – ivanreese

risposta

199

Stai leggendo male i documenti. some_firm.client.new sta creando un nuovo oggetto Client dalla raccolta di client e pertanto può impostare automaticamente lo firm_id su some_firm.id, mentre i documenti chiamano Client.new che non ha alcuna conoscenza dell'ID di un'azienda, quindi è necessario passarlo a firm_id.

L'unica differenza tra some_firm.clients.new e some_firm.clients.build sembra essere che build aggiunge anche il cliente appena creato per la collezione clients:

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 si sta creando un oggetto attraverso un'associazione, build dovrebbe essere preferito su new come build mantiene il tuo oggetto in memoria, some_firm (in questo caso) in uno stato coerente prima ancora che qualsiasi oggetto sia stato salvato nel database.

+6

Usando 'some_firm.client.new' aggiunge anche il cliente a' some_firm.clients', e chiamando 'save' su' some_firm' ha provocato un errore di convalida che indica che 'Client' non era valido. Se sia 'new' che' build' aggiungono il nuovo client alla raccolta client 'some_firm', cosa fa' build' fa che 'new' non fa? Mi dispiace per essere denso, qui! – ClosureCowboy

+0

Ho aggiunto un esempio per il mio post per essere più chiara la differenza tra il 'build' e' new'. Per quanto riguarda l'errore di convalida, suppongo che il modello del cliente abbia bisogno di più dati prima che possa essere salvato (ad esempio un campo nome che non può essere nullo)? In tal caso, dovresti ancora impostare gli attributi prima di salvare. – henrym

+0

Grazie per questi dettagli. Al momento sto guardando un comportamento diverso, anche se sono ancora in 3.0.3 (aggiornerò e controllerò di nuovo tra un momento). In 'r: 004',' clients' per te è una collezione vuota; per me, contiene il client 'new'. Pan Thomakos ha descritto lo stesso comportamento. E l'errore di convalida per l'utente ha detto: '{: client => [ "non è valido"]}' – ClosureCowboy

11

Si è corretto, la generazione e le nuove funzioni hanno lo stesso effetto di impostare la chiave esterna, quando vengono chiamate attraverso un'associazione. Credo che la ragione per cui la documentazione è scritta in questo modo è di chiarire che un nuovo oggetto Client viene istanziato, al contrario di una nuova relazione record attiva. Questo è lo stesso effetto che la chiamata di .new su una classe avrebbe in Ruby. Ciò vuol dire che la documentazione sta chiarendo che chiamare build su un'associazione è la stessa cosa è creare un nuovo oggetto (chiamando .new) e passare 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 la ragione esiste .build è che Firm.first.clients.new potrebbe essere interpretato nel senso che si sta creando un nuovo oggetto rapporto has_many, piuttosto che un cliente vero e proprio, quindi chiamare .build è un modo per chiarirlo.

+0

Così * 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 fossero). MA, l'ultimo ha una differenza significativa in quanto Firm.first.clients non conterrà il nuovo client. – tybro0103

85

build è solo un alias per new:

alias build new 

codice completo può essere trovato: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation.rb

+12

'alias build new' come di rails 3.2.13 – fontno

+7

Questo è vero solo per alcune associazioni/relazioni. Le associazioni singolari, ad esempio, hanno definizioni completamente diverse per 'build' e' build _ # {association} '. Vedi [qui] (https://github.com/rails/rails/blob/master/activerecord/lib/active_record/associations/singular_association.rb#L28) e [qui] (https://github.com/rails/ rotaie/blob/master/ActiveRecord/lib/active_record/associazioni/costruttore/singular_association.rb # L17). – coreyward

+1

È ancora valido per 'Rails 4'? – fatman13

3

accumulo vs nuovo:

in gran parte nuovo e costruire sono gli stessi, ma la costruzione di negozi oggetto in memoria ,

ad es.

per il nuovo:

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

Per costruire:

Firm.first.clients.build 

Qui i clienti vengono salvati nella memoria, quando Salva ferma, record associati vengono salvati anche.

2

Model.new

Tag.new post_id: 1 sarà un'istanza di un tag con il suo post_id set.

@ model.models.new

@post.tags.build fa lo stesso E Tag istanziato sarà in @post.tags ancor prima di essere salvato.

Ciò significa che @post.save salverà sia il @post sia il tag di nuova costruzione (assumendo che sia impostato inverse_of). Questo è ottimo perché Rails convaliderà entrambi gli oggetti prima di salvare, e nessuno dei due verrà salvato se uno di essi fallisce la convalida.

models.new vs models.build

@post.tags.build e @post.tags.new sono equivalenti (almeno dal Rails 3.2).

+0

come su questo? L'unica differenza tra some_firm .clients.new e some_firm.clients.build sembrano essere che build aggiunge anche il client appena creato alla raccolta dei client: '? –