Buduj a nowe w Rails 3

125

Na szynach 3 Dokumenty The buildSposób związków jest opisana jako taka sama jak newsposób, ale z automatycznego przypisywania obcego klucza. Prosto z dokumentacji:

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

Czytałem podobne gdzie indziej.

Jednak gdy używam new(np. some_firm.clients.newBez żadnych parametrów), automatycznie tworzone jestfirm_id skojarzenie nowego klienta . Patrzę teraz na wyniki w konsoli!

Czy coś mi brakuje? Czy dokumenty są nieco nieaktualne (mało prawdopodobne)? Jaka jest różnica między buildi new?

Zamknięcie Cowboy
źródło
3
Osoby szukające szybkiej odpowiedzi, sprawdź drugą poniżej: „build” to po prostu alias dla „new”
ivanreese

Odpowiedzi:

208

Lekko źle odczytujesz dokumenty. some_firm.client.newtworzy nowy Clientobiekt z kolekcji klientów, więc może automatycznie ustawić firm_idto some_firm.id, podczas gdy wzywają dokumenty, Client.newktóre nie mają żadnej wiedzy o identyfikatorze żadnej firmy, więc wymaga firm_idprzekazania do niego.

Jedyną różnicą między some_firm.clients.newi some_firm.clients.buildwydaje się być to, że builddodaje również nowo utworzonego klienta do clientskolekcji:

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

Jeśli tworzysz obiekt przez skojarzenie, buildpowinno być preferowane, newponieważ kompilacja utrzymuje obiekt w pamięci some_firm(w tym przypadku) w spójnym stanie, nawet zanim jakiekolwiek obiekty zostaną zapisane w bazie danych.

henrym
źródło
8
Korzystanie some_firm.client.newrównież dodaje do klienta some_firm.clients, i wzywając savena some_firmspowodowało błędu walidacji wskazując, że clientbył nieprawidłowy. Jeśli oba newi builddodasz nowego klienta do some_firmkolekcji klientów, czego to buildnie newdaje? Przepraszam, że jestem gęsty!
ClosureCowboy
1
+1 Otrzymałem Twój wynik z 3.0.4. Chciałbym, żeby ktoś z 3.0.3 mógł potwierdzić, że nie jestem szalony.
ClosureCowboy,
41
@henrym Wygląda na to, że w 3.2.6 client.new i clients.build są podobne, ponieważ oba dodają nowy obiekt do kolekcji. Chciałem dodać komentarz dla każdego, kto natknął się na to podczas Googlingu tak jak ja
hubbard
11
Wygląda na to, że nie ma między nimi różnicy w Railsach 3.2.3
Aditya Kapoor
4
Ta odpowiedź nie jest poprawna dla Railsów> 3.2.13, gdzie „build” jest po prostu aliasem „new”. Zobacz odpowiedź @ HatemMahmoud poniżej.
Andreas
91

buildto tylko alias dla new:

alias build new

Pełny kod można znaleźć: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation.rb#L74

Hatem Mahmoud
źródło
13
alias build newjak z szyn 3.2.13
fontno
7
Dotyczy to tylko niektórych skojarzeń / relacji. Na przykład pojedyncze stowarzyszenia mają zupełnie inne definicje dla buildi build_#{association}. Zobacz tutaj i tutaj .
coreyward
1
Czy to nadal prawda Rails 4?
fatman13
1
tutaj jest raport o błędzie ... który sugeruje, czy używasz nowego, takiego jak restaurant.customers.new, jako sposobu na uzyskanie nowego klienta powiązanego z restauracją bez dołączania go do restauracji. klienci, aby użyć zakresu ... np. restauracja .customers.scoped.new
user3334690
11

Masz rację, kompilacja i nowe funkcje mają taki sam efekt, jak ustawienie klucza obcego, gdy są wywoływane przez skojarzenie. Uważam, że dokumentacja została napisana w ten sposób, aby wyjaśnić, że tworzona jest instancja nowego obiektu klienta, w przeciwieństwie do nowej relacji aktywnego rekordu. Jest to ten sam efekt, który wywołanie .new w klasie miałoby w Rubim. Oznacza to, że dokumentacja wyjaśnia, że ​​wywołanie build na asocjacji jest tym samym, co utworzenie nowego obiektu (wywołanie .new) i przekazanie kluczy obcych do tego obiektu. Te polecenia są równoważne:

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

Uważam, że powodem istnienia .build jest to, że Firm.first.clients.new może być interpretowane jako oznaczające, że tworzysz nowy obiekt relacji has_many, a nie rzeczywistego klienta, więc wywołanie .build jest sposobem na wyjaśnienie tego.

Pan Thomakos
źródło
Więc równoważne. Zdecydowanie tak się wydaje. Dziękuję Ci!
ClosureCowboy
5
To nie jest poprawne. Pierwsze dwa są równoważne w późniejszych wersjach Railsów (wygląda na to, że w momencie wysyłania nie były). ALE, ten ostatni ma znaczącą różnicę w tym, że Firm.first.clients nie będzie zawierał nowego klienta.
tybro0103
4

buildvs new:

głównie nowe i budowane są takie same, ale build przechowuje obiekt w pamięci ,

na przykład:

dla nowych:

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

Do budowy:

Firm.first.clients.build

Tutaj klienci są przechowywani w pamięci, podczas zapisywania firmy zapisywane są również powiązane rekordy.

Sarwan Kumar
źródło
2

Model.new

Tag.new post_id: 1utworzy wystąpienie tagu z jego post_idzestawem.

@ model.models.new

@post.tags.buildrobi to samo ORAZ utworzony Tag będzie w nim @post.tagsjeszcze przed zapisaniem.

Oznacza to, @post.saveże zapisze zarówno @post, jak i nowo utworzony tag (zakładając, że ustawione jest: inverse_of). Jest to świetne, ponieważ Railsy sprawdzą poprawność obu obiektów przed zapisaniem i żaden nie zostanie zapisany, jeśli któryś z nich nie przejdzie walidacji.

models.new vs models.build

@post.tags.buildi @post.tags.newsą równoważne (przynajmniej od Railsów 3.2).

tybro0103
źródło
co powiesz na to 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:?
ア レ ッ ク ス