Побудувати проти нового в Rails 3


125

У Rails 3 Docs , то buildметод асоціацій описується як такий же , як newметод, але з автоматичним присвоєнням зовнішнього ключа. Прямо з документів:

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

Я читав подібне деінде.

Однак, коли я використовую new(наприклад , some_firm.clients.newбез яких - або параметрів), нового клієнта firm_idасоціація буде створена автоматично. Я зараз дивлюсь на результати прямо в консолі!

Я щось пропускаю? Документи трохи застаріли (малоймовірно)? Яка різниця між buildі new?


3
Люди, які шукають швидкої відповіді, перевіряють другий вниз: "побудувати" - це лише псевдонім для "нового"
ivanreese

Відповіді:


208

Ви трохи неправильно читаєте документи. some_firm.client.newстворює новий Clientоб'єкт з колекції клієнтів, і тому він може автоматично встановити firm_idна some_firm.id, в той час як документи закликають Client.new, що не має знання про ід яких - або фірм взагалі, тому потребує firm_idпередана їй.

Єдина відмінність між some_firm.clients.newі, some_firm.clients.buildздається, полягає в тому, що buildтакож додає новоствореного клієнта до 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">] 

Якщо ви створюєте об'єкт через асоціацію, buildслід віддавати перевагу newтому, що збірка зберігає ваш об’єкт пам’яті some_firm(у цьому випадку) у послідовному стані навіть до того, як будь-які об’єкти будуть збережені в базі даних.


8
Використання some_firm.client.newтакож додає клієнт до some_firm.clients, і виклик saveна some_firmв результаті помилки перевірки , що вказує , що clientє неприпустимим. Якщо обидва newі buildдодати нового клієнта до some_firmколекції клієнтів, що buildробити newце не робить? Мені шкода, що тут щільно!
ClosureCowboy

1
+1 Я отримав ваш результат з 3.0.4. Я хотів би, якби хтось із 3.0.3 міг підтвердити, що я не божевільний.
Закриття Cowboy

41
@henrym Схоже, що в 3.2.6 client.new і clients.build схожі тим, що вони додають новий об'єкт у колекцію. Я хотів додати коментар для тих, хто натрапив на це під час Googling, як і я
hubbard

11
Схоже, різниці між ними немає в Rails 3.2.3
Aditya Kapoor

4
Ця відповідь не відповідає правилам для Rails> 3.2.13, де "build" - це лише псевдонім для "new". Дивіться відповідь @ HatemMahmoud нижче.
Андреас

91

buildце лише псевдонім для new:

alias build new

Повний код можна знайти: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation.rb#L74


13
alias build newстаном на рейки
3.2.13

7
Це стосується лише деяких асоціацій / відносин. Наприклад, сингулярні асоціації мають абсолютно різні визначення для buildта build_#{association}. Дивіться тут і тут .
coreyward

1
Це все-таки вірно Rails 4?
fatman13

1
ось звіт про помилку ... який говорить про те, що якщо ви використовували нове, як Restaurant.customers.new, як спосіб залучити нового клієнта, пов’язаного з рестораном, не додаючи його до restaurant.customers, використовувати скопійований ... наприклад ресторан .customers.scoped.new
користувач3334690

11

Ви правильно, побудова та нові функції мають однаковий ефект від встановлення зовнішнього ключа, коли вони викликаються через асоціацію. Я вважаю, що документація написана таким чином, щоб пояснити, що новий об'єкт Клієнта інстанціюється на відміну від нового активного запису. Це той самий ефект, який викликав би .new на клас у Ruby. Тобто в документації з’ясовується, що виклик побудови на асоціації - це те саме, що створити новий об’єкт (виклик .new) та передати зовнішні ключі до цього об’єкта. Ці команди еквівалентні:

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

Я вважаю, що причина .build існує в тому, що Firm.first.clients.new може бути інтерпретований так, що ви створюєте новий об'єкт відносин has_many, а не власне клієнта, тому виклик .build - це спосіб уточнити це.


Таким чином , вони є еквівалентними. Ось, безумовно, це здається. Дякую!
Закриття Cowboy

5
Це неправильно. Перші два еквівалентні в пізніших версіях Rails (схоже, на момент публікації їх не було). Але останній має суттєву різницю в тому, що Firm.first.clients не міститиме нового клієнта.
tybro0103

4

buildvs new:

в основному нові і будувати такі ж , але будують магазини об'єкт в пам'яті ,

наприклад:

для нового:

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

Для побудови:

Firm.first.clients.build

Тут клієнти зберігаються в пам'яті, при збереженні фірми пов'язані записи також.


2

Model.new

Tag.new post_id: 1буде інстанціювати тег своїм post_idнабором.

@ model.models.new

@post.tags.buildзробить те саме І Ідентифікований тег буде @post.tagsще до його збереження.

Це означає, що @post.saveбуде збережено і тег @post, і щойно побудований тег (якщо припустити: встановлено інверсійний_of). Це чудово, тому що Rails перевірить обидва об'єкти перед збереженням, і жоден із них не буде збережено, якщо жоден з них не виконає перевірку.

models.new vs models.build

@post.tags.buildі @post.tags.newє рівнозначними (принаймні з рейок 3.2).


як щодо цього 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:?
ア レ ッ ク ス
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.