我在调试这个问题时遇到了困难,我正想寻求帮助。但我已经设法找出原因,并希望分享我的发现,以防其他人遇到同样的问题。 [也许有人可以解释为什么它会这样工作]
设置
假设我有两个 Mongoid-Documents,Customer
和 Order
,具有 1:n 关系。此外,Customer
有一个 after_save
回调,用于将文档更改与外部 API 同步:
class Customer
include Mongoid::Document
has_many :orders
after_save do
puts "synchronizing customer" # <- not my actual code
end
end
class Order
include Mongoid::Document
belongs_to :customer
validates_presence_of :customer
end
一切都按预期进行。创建和更新客户会导致 after_save
回调被触发,而创建订单则不会。
更改
过了一段时间,客户
需要一个具有默认值的新字段:
class Customer
# ...
field :premium, type: Boolean, default: false
end
问题
但是突然之间,事情变得很奇怪。进行此更改后,创建(或更新)订单也会导致客户被保存! (我注意到这一点是因为我的日志 - 同步运行没有明显的原因)
c = Customer.last
c.orders.create
synchronizing customer # <- what the?
#=> #<Order _id: 575a995aab265d730b8bddba ...>
奇怪的是,这种情况只发生在现有客户身上,而且只发生一次。
原因
漫长而乏味的调试 session 显示,Order
的 belongs_to
关系具有 autosave
标志:
Order.relations['customer'].autosave?
#=> true
它是通过存在验证启用的,事实上,Mongoid 的 documentation随手记下:
Note that autosave functionality will automatically be added to a relation when using
accepts_nested_attributes_for
or validating presence of the relation.
但是autosave
仅保存已更改的文档,那么更改从何而来?显然,我的带有默认值的新 premium
字段引入了微妙的变化:
c = Customer.first # a customer from before the change without "premium" attribute
c.changed?
#=> true
c.changes
#=> {"premium"=>[nil, false]}
解决方案
毕竟,修复是相当微不足道的。我只需在我的 belongs_to
关系上显式禁用自动保存即可:
class Order
include Mongoid::Document
belongs_to :customer, autosave: false
validates_presence_of :customer
end
开放式问题
但问题仍然存在:为什么 Mongoid 的“存在”验证会启用自动保存?这怎么可能是期望的默认行为?请赐教。
最佳答案
看来,这种自动保存功能已被有意添加到 Mongoid 3.0 中,以便其行为与 ActiveRecord 保持一致。看一下这两个问题:
- validates_presence_of association should enable autosave
- Behavior of :autosave not consistent with ActiveRecord
第二期链接到 ActiveRecord doc确实看起来表现相同,让我们特别引用以下声明:
Note that
autosave: false
is not same as not declaring:autosave
. When the:autosave
option is not present then new association records are saved but the updated association records are not saved.
这是一个link to the source code Mongoid 功能本身。
此外,从所有这些来源来看,事实证明您的解决方案是完美的,您确实应该具体声明 :autosave => false
来禁用此功能。
关于ruby-on-rails - 为什么 Mongoid 的 "presence"验证启用自动保存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37746804/