Build vs new in Rails 3

125

In den Rails 3- Dokumenten wird die buildMethode für Zuordnungen als dieselbe wie die newMethode beschrieben, jedoch mit der automatischen Zuweisung des Fremdschlüssels. Direkt aus den Dokumenten:

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

Ich habe anderswo ähnlich gelesen.

Allerdings, wenn ich verwende new(zB some_firm.clients.newohne Parameter), die der neuen Client - firm_idVerband wird automatisch erstellt. Ich starre gerade auf die Ergebnisse in der Konsole!

Vermisse ich etwas Sind die Dokumente etwas veraltet (unwahrscheinlich)? Was ist der Unterschied zwischen buildund new?

ClosureCowboy
quelle
3
Leute, die nach einer schnellen Antwort suchen, überprüfen die zweite unten: "build" ist nur ein Alias ​​für "new"
ivanreese

Antworten:

208

Sie lesen die Dokumente leicht falsch. some_firm.client.newein neues schafft ClientObjekt aus der Kunden - Sammlung, und so kann er automatisch die eingestellte firm_idzu some_firm.id, während die Dokumente fordern , Client.newdie überhaupt keine Kenntnis von Firm - ID hat, so ist es , die Bedürfnisse firm_idan sie übergeben.

Der einzige Unterschied zwischen some_firm.clients.newund some_firm.clients.buildscheint darin zu bestehen, dass buildder neu erstellte Client auch zur clientsSammlung hinzugefügt wird:

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

Wenn Sie ein Objekt über eine Zuordnung builderstellen , sollten Sie es vorziehen, newda der Build Ihr In-Memory-Objekt some_firm(in diesem Fall) in einem konsistenten Zustand hält, noch bevor Objekte in der Datenbank gespeichert wurden.

Henrym
quelle
8
Mit some_firm.client.newfügt auch den Client some_firm.clientsund ruft saveauf some_firmin einem Validierungsfehler führte darauf hinweist , dass clientwar ungültig. Wenn beides newund buildder neue Client zur some_firmClient-Sammlung hinzugefügt wird , was macht builddas newnicht? Es tut mir leid, dass ich hier dicht bin!
ClosureCowboy
1
+1 Ich habe Ihr Ergebnis mit 3.0.4 erhalten. Ich würde mich freuen, wenn jemand mit 3.0.3 bestätigen könnte, dass ich nicht verrückt bin.
ClosureCowboy
41
@henrym Es sieht so aus, als ob in 3.2.6 clients.new und clients.build ähnlich sind, da beide das neue Objekt zur Sammlung hinzufügen. Ich wollte einen Kommentar für jeden hinzufügen, der beim Googeln darauf gestoßen ist, wie ich es getan habe
Hubbard
11
Es sieht so aus, als gäbe es keinen Unterschied zwischen ihnen in Rails 3.2.3
Aditya Kapoor
4
Diese Antwort ist nicht korrekt für Rails> 3.2.13, wobei 'build' nur ein Alias ​​für 'new' ist. Siehe die Antwort von @ HatemMahmoud unten.
Andreas
91

buildist nur ein Alias ​​für new:

alias build new

Den vollständigen Code finden Sie unter: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation.rb#L74

Hatem Mahmoud
quelle
13
alias build newab Schienen 3.2.13
fontno
7
Dies gilt nur für einige Assoziationen / Beziehungen. Singuläre Assoziationen haben zum Beispiel völlig unterschiedliche Definitionen für buildund build_#{association}. Sehen Sie hier und hier .
Coreyward
1
Gilt das noch für Rails 4?
Fatman13
1
Hier ist der Fehlerbericht ... der vorschlägt, wenn Sie neu wie restaurant.customers.new verwenden, um einen neuen Kunden mit dem Restaurant in Verbindung zu bringen, ohne ihn an restaurant.customers anzuhängen, um Scoped zu verwenden ... wie beispielsweise restaurant .customers.scoped.new
user3334690
11

Sie haben Recht, der Build und die neuen Funktionen haben den gleichen Effekt wie das Festlegen des Fremdschlüssels, wenn sie über eine Zuordnung aufgerufen werden. Ich glaube, der Grund, warum die Dokumentation so geschrieben ist, besteht darin, zu verdeutlichen, dass ein neues Client-Objekt instanziiert wird, im Gegensatz zu einer neuen aktiven Datensatzbeziehung. Dies ist der gleiche Effekt, den das Aufrufen von .new für eine Klasse in Ruby haben würde. Das heißt, in der Dokumentation wird klargestellt, dass das Aufrufen von Build für eine Zuordnung dasselbe ist, indem ein neues Objekt erstellt wird (Aufruf von .new) und die Fremdschlüssel an dieses Objekt übergeben werden. Diese Befehle sind alle gleichwertig:

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

Ich glaube, der Grund, warum .build existiert, ist, dass Firm.first.clients.new so interpretiert werden kann, dass Sie ein neues has_many-Beziehungsobjekt anstelle eines tatsächlichen Clients erstellen. Der Aufruf von .build ist daher eine Möglichkeit, dies zu klären.

Pan Thomakos
quelle
Sie sind also gleichwertig. So scheint es definitiv. Danke dir!
ClosureCowboy
5
Das ist nicht richtig. Die ersten beiden sind in späteren Versionen von Rails gleichwertig (zum Zeitpunkt der Veröffentlichung waren sie es nicht). ABER der letzte hat einen signifikanten Unterschied darin, dass Firm.first.clients den neuen Client nicht enthält.
Tybro0103
4

buildvs new:

Meistens sind Neu und Build gleich, aber Build speichert Objekte im Speicher .

z.B:

für neue:

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

Zum Bauen:

Firm.first.clients.build

Hier werden Clients im Speicher gespeichert, wenn sie sicher gespeichert werden, werden auch zugehörige Datensätze gespeichert.

Sarwan Kumar
quelle
2

Model.new

Tag.new post_id: 1instanziiert ein Tag mit seinem post_idSet.

@ model.models.new

@post.tags.buildmacht dasselbe UND das instanziierte Tag wird @post.tagsnoch vor dem Speichern angezeigt .

Dies bedeutet @post.save, dass sowohl das @post als auch das neu erstellte Tag gespeichert werden (vorausgesetzt: inverse_of ist gesetzt). Dies ist großartig, da Rails beide Objekte vor dem Speichern validiert und keines gespeichert wird, wenn eines von beiden die Validierung nicht besteht.

models.new vs models.build

@post.tags.buildund @post.tags.newsind gleichwertig (zumindest seit Rails 3.2).

tybro0103
quelle
wie wäre es damit 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:?
レ ッ ク ス