01 июн. 2012 г., 21:10 отTaymon

Когда сохраняются объекты Active Record в отношениях has_many?

Я использую Rails 1.2.3 (да, я знаю), и я не совсем понимаю, какhas_many работает в отношении постоянства объекта.

В качестве примера я буду использовать это в качестве своего объявления:

class User < ActiveRecord::Base
    has_many :assignments
end

class Assignment < ActiveRecord::Base
    belongs_to :user
end

Насколько я понимаю, это создает, среди прочего, методUser#assignments.build, который создаетAssignment объект которогоuser_id является получающим экземпляромid (и чьи другие поля соответствуют указанным в аргументе), но не сохраняет этот объект в базе данных. Объект можно сохранить позже, вызвавAssignment#save!.

Однако, Прагматичные Программисты & apos;Agile Web Development with Rails, Second Edition, который я использовал в качестве учебного пособия и справочника, говорит:

If the parent object exists in the database, then adding a child object to a collection automatically saves that child.

Кажется, здесь есть противоречие. Я хотел бы знать следующее:

If I do some_user.assignments.build, is the Assignment object saved? If I do some_user.assignments << Assignment.new, is the Assignment object saved? If I do some_user.assignments << Assignment.create, are two database calls made, or just one? What about if I modify the Assignment object between creating it and adding it to some_user.assignments? What happens if I save! an Assignment object whose corresponding User has not yet been saved in the database?

Постскриптум Причина, по которой я не просто используюUser#assignments.create ибо все потому, что он не позволяет мне перебирать инициализацию для внешнего метода, что я хотел бы иметь возможность делать. Я также не хочу совершать многократные поездки в базу данных.

Ответы на вопрос(1)

02 июн. 2012 г., 01:35 отroflmao

ПРИМЕЧАНИЕ: Все приведенные ниже тесты консоли выполняются в Rails 3. Возможно, вы получите другой вывод в Rails 1, вам придется запускать тесты самостоятельно для сравнения.

Если у вас есть удобная консоль для рельсов, она очень полезна, если вы хотите понять, что происходит за кулисами с Active Record. Вот что происходит с несохраненным объектом:

u = User.new
#<User id: nil, name: nil, created_at: nil, updated_at: nil> 

u.assignments.build(:name => "example")
#<Assignment id: nil, name: "example", user_id: nil, created_at: nil, updated_at: nil>

u.save
#SQL (0.2ms)  INSERT INTO `users` (`created_at`, `name`, `updated_at`) VALUES ('2012-06-01 19:25:45', NULL, '2012-06-01 19:25:45')
#SQL (0.2ms)  INSERT INTO `assignments` (`created_at`, `name`, `updated_at`, `user_id`) VALUES ('2012-06-01 19:25:45', 'example', '2012-06-01 19:25:45', 1)

Как видите, оба сохраняются одновременно с сохранением нового пользователя. Теперь давайте попробуем сценарий два:

u = User.create!(:name => "test")
#SQL (0.2ms)  INSERT INTO `users` (`created_at`, `name`, `updated_at`) VALUES ('2012-06-01 19:27:21', 'test', '2012-06-01 19:27:21')
#<User id: 2, name: "test", created_at: "2012-06-01 19:27:21", updated_at: "2012-06-01 19:27:21"> 

u.assignments.build(:name => "example")
#<Assignment id: nil, name: "example", user_id: 2, created_at: nil, updated_at: nil>

Итак, из этого мы можем сделать вывод:

Если я сделаю some_user.assignments.build, объект Назначения сохранен?

Не

Если я выполняю some_user.assignments << Assignment.new, сохраняется ли объект Assignment?

No. Это именно то, что делает assignments.build, без разницы.

Если я выполняю some_user.assignments << Assignment.create, сделаны два вызова базы данных или только один?

Просто задания.

А если я изменю объект Assignment между его созданием и добавлением в some_user.assignments?

Не понимаю, простите

Что произойдет, если я сохраню! объект назначения, соответствующий пользователь которого еще не был сохранен в базе данных?

Он сохраняется в базе данных без идентификатора пользователя. Когда вы затем вызываете команду save для своего пользователя, в назначение назначается команда обновления для добавления идентификатора пользователя. Вот это в консоли:

u = User.new(:name => "Joh,n Doe")
#<User id: nil, name: "John Doe", created_at: nil, updated_at: nil> 

a = Assignment.new(:name => "test")
#<Assignment id: nil, name: "test", user_id: nil, created_at: nil, updated_at: nil> 

u.assignments << a
#[#<Assignment id: nil, name: "test", user_id: nil, created_at: nil, updated_at: nil>] 

a.save!
#SQL (0.2ms)  INSERT INTO `assignments` (`created_at`, `name`, `updated_at`, `user_id`) VALUES ('2012-06-01 19:33:24', 'test', '2012-06-01 19:33:24', NULL)

a.user_id
#nil 

u.save!
#INSERT INTO `users` (`created_at`, `name`, `updated_at`) VALUES ('2012-06-01 19:33:36', 'John Doe', '2012-06-01 19:33:36')
#UPDATE `assignments` SET `user_id` = 3, `updated_at` = '2012-06-01 19:33:36' WHERE `assignments`.`id` = 3

Надеюсь это поможет

ВАШ ОТВЕТ НА ВОПРОС