Рубін на рейках. Як використовувати метод Active Record .build в: відносини?


128

Мені не вдалося знайти жодної документації щодо методу .build в Rails (я зараз використовую 2.0.2).

Завдяки експериментуванню, здається, ви можете використовувати метод збирання, щоб додати запис у has_manyвідносини, перш ніж будь-який запис був збережений.

Наприклад:

class Dog < ActiveRecord::Base
  has_many :tags
  belongs_to :person
end

class Person < ActiveRecord::Base
  has_many :dogs
end

# rails c
d = Dog.new
d.tags.build(:number => "123456")
d.save # => true

Це дозволить зберегти як собаку, так і теги за допомогою іноземних ключів належним чином. Схоже, це не працює у belongs_toстосунках.

d = Dog.new
d.person.build # => nil object on nil.build

Я також спробував

d = Dog.new
d.person = Person.new
d.save # => true

Іноземний ключ у Dogцьому випадку не встановлений через те, що під час його збереження нова особа не має ідентифікатора, оскільки її ще не збережено.

Мої запитання:

  1. Як працює побудова, щоб Rails був досить розумним, щоб зрозуміти, як зберегти записи в потрібному порядку?

  2. Як я можу зробити те саме у belongs_toвідносинах?

  3. Де я можу знайти будь-яку документацію щодо цього методу?

Дякую


Щодо документації, дивіться посібники з рейок "Методи, додані belongs_to" та "Методи, додані has_one" . Більше технічної документації можна знайти в документах API: belongs_toта has_one.
Денніс

Відповіді:


147

Де це задокументовано:

З документації API під асоціацією has_many в " Модулі ActiveRecord :: Асоціації :: ClassMethods "

collection.build (attributes = {}, ...) Повертає один або декілька нових об'єктів типу колекції, які були інстанціровані атрибутами та пов'язані з цим об'єктом за допомогою іноземного ключа, але ще не збережені. Примітка. Це працює лише в тому випадку, якщо асоційований об'єкт вже існує, а не якщо він нульовий!

Відповідь на побудову у зворотному напрямку - трохи змінений синтаксис. У вашому прикладі з собаками,

Class Dog
   has_many :tags
   belongs_to :person
end

Class Person
  has_many :dogs
end

d = Dog.new
d.build_person(:attributes => "go", :here => "like normal")

або навіть

t = Tag.new
t.build_dog(:name => "Rover", :breed => "Maltese")

Ви також можете скористатися create_dog, щоб миттєво його зберегли (подібно до відповідного методу "create", який ви можете зателефонувати в колекцію)

Як рейки досить розумні? Це магія (або точніше, я просто не знаю, хотілося б дізнатися!)


4
@BushyMark: він використовує method_missing або metaporgramming, щоб додати ці методи за допомогою методу define_method.
Федеріко

@Federico де визначений метод відсутності?
дивовижне

1
@ alock27 Те саме, що ActiveRecord використовує відсутній для вас метод find_by_emailта find_by_column_nameметоди. Він перетворює метод, який ви передаєте, у рядок і розтинає його і намагається співставити його з іменами стовпців таблиці.
bigpotato

@edmund Дякуємо за ваш коментар. Щоб було зрозуміло, я розумію, як працює method_missing. Я намагався знайти фактичне розташування файлу, який визначає відсутність цього конкретного методу.
дивовижне

@ alock27, якщо ви запитуєте, оскільки ви хочете вивчити, як це визначено, ви повинні перевірити метапрограмування Ruby. Але якщо ви дійсно шукаєте фактичне місцезнаходження, ви, можливо, могли б отримати Google для вихідного коду.
MCB

48
@article = user.articles.build(:title => "MainTitle")
@article.save

>> d.tags.build (: number => "123456") >> d.save # => true Не те саме?
antiqe
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.