4

我正在使用 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!

但是,我一直将其用作教程和参考的 The Pragmatic Programmers' Agile Web Development with Rails, Second Edition说:

如果父对象存在于数据库中,则将子对象添加到集合中会自动保存该子对象。

这里似乎有矛盾。我想知道的是:

  • 如果我这样做some_user.assignments.buildAssignment对象是否保存?
  • 如果我这样做some_user.assignments << Assignment.newAssignment对象是否保存?
  • 如果我这样做some_user.assignments << Assignment.create了,是进行了两次数据库调用,还是仅进行了一次?如果我Assignment在创建对象和添加对象之间修改对象会some_user.assignments怎样?
  • 如果我save!Assignment对象User尚未保存在数据库中,会发生什么?

PS我不只是User#assignments.create用于所有事情的原因是因为它不允许我将初始化外包给外部方法,而我希望能够做到这一点。我也不想多次访问数据库。

4

1 回答 1

19

注意:下面所有的控制台测试都是在 Rails 3 中运行的。在 Rails 1 中你可能会得到不同的输出,你必须自己运行测试来比较。

如果您想了解 Active Record 幕后发生的事情,那么使用方便的 rails 控制台是非常有价值的。以下是未保存对象的情况:

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,是否保存了 Assignment 对象?

没有

如果我执行 some_user.assignments << Assignment.new,是否保存了 Assignment 对象?

不,这正是 assignments.build 所做的,没有区别。

如果我执行 some_user.assignments << Assignment.create,是进行了两次数据库调用,还是仅进行了一次?

只是任务。

如果我在创建分配对象和将其添加到 some_user.assignments 之间修改它会怎样?

不明白,对不起。

如果我保存会发生什么!一个分配对象,其相应的用户尚未保存在数据库中?

它在没有 user_id 的情况下保存到数据库中。然后,当您对用户调用 save 时,将向分配发出更新命令以添加用户 ID。这是在控制台中:

u = User.new(:name => "John 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

希望这可以帮助。

于 2012-06-01T19:35:29.187 回答