将child设置为“nil”时,Rails / ActiveRecord has_one关联行为

时间:2017-01-10 19:37:23

标签: ruby-on-rails ruby activerecord

我的同事和我注意到一些关于ActiveRecord has_one关联的事情,这些关联感觉错误/危险并且似乎不容易记录。

假设我们有这个设置:

class User < ApplicationRecord
  has_one :subscription
end

class Subscription < ApplicationRecord
  belongs_to :user
end

没有“依赖:销毁”

> user = User.create(name: "Bob")
> user.subscription = Subscription.create(provider: "Stripe")

> user.subscription = nil

   (0.1ms)  begin transaction
  SQL (0.4ms)  UPDATE "subscriptions" SET "user_id" = ?, "updated_at" = ? WHERE "subscriptions"."id" = ?  [["user_id", nil], ["updated_at", 2017-01-10 19:24:56 UTC], ["id", 2]]
   (2.0ms)  commit transaction

使用“dependent:destroy”

class User < ApplicationRecord
  has_one :subscription, dependent: :destroy
end


> user = User.create(name: "Bob")
> user.subscription = Subscription.create(provider: "Stripe")

> user.subscription = nil

   (0.1ms)  begin transaction
    SQL (1.1ms)  DELETE FROM "subscriptions" WHERE "subscriptions"."id" = ?  [["id", 1]]
   (0.7ms)  commit transaction

这是预期的行为吗?我真的很惊讶,在没有显式调用savedestroyupdate等情况下完成了SQL调用。我也对dependant: destroy改变行为的原因感到困惑在这种情况下。

这应该发生,如果是这样,它是否记录在任何地方? dependant: destroy版本似乎特别危险。

这是使用Rails 5以及几个版本的Rails 4测试的。

2 个答案:

答案 0 :(得分:2)

来自guide

  

4.2.5何时保存对象?

     

将对象分配给has_one关联时,该对象为   自动保存(以更新其外键)。此外,   任何被替换的对象也会自动保存,因为它   外键也会改变。

     

如果这些保存中的任何一个由于验证错误而失败,那么   赋值语句返回false,赋值本身就是   取消。

     

如果父对象(声明has_one关联的对象)是   未保存(即new_record?返回true)然后是子对象   没有保存。它们将在保存父对象时自动生成。

     

如果要在没有的情况下将对象分配给has_one关联   保存对象,使用association.build方法。

答案 1 :(得分:1)

这是预期的行为吗?

是。 Rails docs on has_one associations

中的一个示例
  

帐户#受益人=(受益人)(类似于beneficiary.account_id =   帐户ID; beneficiary.save)

至于dependent: :destroy,来自相同的文档:

  

:destroy导致关联对象也被销毁

因此SQL DELETE查询。