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?


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.


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


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.


Więc są 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.


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).


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:?
— ア レ ッ ク ス
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.