Рубин на рельсах. Как использовать метод Active Record .build в отношении: принадлежит к отношению?

129

Мне не удалось найти какую-либо документацию по методу .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. Где найти документацию по этому методу?

Спасибо

stellard
источник
Что касается документации, см. Руководства по Rails «Методы, добавленные пользователем belongs_to» и «Методы, добавленные пользователем has_one» . Дополнительную техническую документацию можно найти в документации API: belongs_toи has_one.
Деннис

Ответы:

148

Где это задокументировано:

Из документации API под ассоциацией has_many в " Module ActiveRecord :: Associations :: 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, который вы можете вызвать для коллекции)

Как рельсы достаточно умны? Это волшебство (точнее, я просто не знаю, очень хотелось бы узнать!)

BushyMark
источник
4
@BushyMark: он использует method_missing или metaporgramming, чтобы добавить эти методы с помощью define_method.
Федерико
@Federico, где пропущен метод?
awilkening
1
@ alock27 То же, как ActiveRecord использует метод недостающую для find_by_emailи find_by_column_nameметодов. Он преобразует переданный вами метод в строку, анализирует ее и пытается сопоставить с именами столбцов вашей таблицы.
bigpotato
@edmund Спасибо за ваш комментарий. Для ясности, я понимаю, как работает method_missing. Я пытался найти фактическое расположение файла, в котором отсутствует этот конкретный метод.
awilkening
@ alock27, если вы спрашиваете, потому что хотите узнать, как это определяется, вам следует проверить Metaprogramming Ruby. Но если вы действительно ищете реальное местоположение, вы, вероятно, можете найти исходный код в Google.
MCB
48
@article = user.articles.build(:title => "MainTitle")
@article.save
nehpets
источник
>> d.tags.build (: number => "123456") >> d.save # => true Не то же самое?
antiqe