为什么Mongoid"存在"验证启用自动保存?

时间:2016-06-10 11:13:27

标签: ruby-on-rails validation mongoid autosave

我很难调试这个,我正要求帮忙。但我已设法确定原因,并希望分享我的发现,以防其他人遇到同样的问题。 [也许有人可以解释为什么它按照它的方式工作]

设置

我们说我有两个Mongoid-Documents,CustomerOrder,关系为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回调并且不会创建订单。

更改

过了一会儿,Customer需要一个具有默认值的新字段:

class Customer
  # ...
  field :premium, type: Boolean, default: false
end

问题

但突然间,事情变得奇怪了。在此更改之后,创建(或更新)订单会导致客户也被保存! (我注意到这是因为我的日志 - 同步运行没有明显的原因)

c = Customer.last
c.orders.create
synchronizing customer  # <- what the?
#=> #<Order _id: 575a995aab265d730b8bddba ...>

奇怪的是,这只发生在现有客户身上,而且只发生一次。

原因

漫长而乏味的调试会话显示Order的{​​{1}}关系有一个belongs_to标记:

autosave

它是通过在线验证启用的,事实上,Mongoid的documentation随便注意到它:

  

请注意,在使用Order.relations['customer'].autosave? #=> true 或验证关系存在时,自动保存功能会自动添加到关系中。

但是accepts_nested_attributes_for只保存了一个文件,如果它被更改了,那么这个变化来自哪里?显然,我的新autosave字段具有默认值,引入了一个微妙的变化:

premium

解决方案

毕竟,修复工作非常简单。我只需要在我的c = Customer.first # a customer from before the change without "premium" attribute c.changed? #=> true c.changes #=> {"premium"=>[nil, false]} 关系中明确禁用自动保存:

belongs_to

打开问题

但问题仍然存在:为什么Mongoid&#34;存在&#34;验证启用自动保存?这怎么可能是理想的默认行为?请赐教。

1 个答案:

答案 0 :(得分:2)

似乎自动启用自动保存已故意添加到Mongoid 3.0 ,以便其行为与ActiveRecord 一致。看看这两个问题:

第二个问题链接到ActiveRecord doc,它确实表现得一样,让我们​​特别引用以下声明:

  

请注意,autosave: false与未声明:autosave不同。如果:autosave选项不存在,则会保存新的关联记录,但不会保存更新的关联记录。

这是Mongoid功能本身的link to the source code

此外,从所有这些来源可以看出,您的解决方案非常完美,您确实应该明确指出:autosave => false来禁用此功能