保存子对象失败时,防止保存父对象

时间:2014-09-05 20:10:45

标签: ruby-on-rails activerecord

我有两个相关的类:

class Purchase < ActiveRecord::Base
  has_many :actions

  before_create do |p|
    self.actions.build
  end
end

class Action < ActiveRecord::Base
  belongs_to :purchase

  before_save do |a|
    false
  end
end

Action类中的块阻止它保存。我在想Purchase.create会失败,因为它无法保存子对象。但是虽然它没有保存Action,但它会提交Purchase。当子对象出错时,如何防止保存父对象?

4 个答案:

答案 0 :(得分:0)

尝试在Purchase class:

中使用此代码
validate :all_children_are_valid
def all_children_are_valid
  self.actions.each do |action|
    unless action.valid?
      self.errors.add(:actions, "aren't valid")
      break
    end
  end
end 

或在validates_associated课程中使用Purchase

validates_associated :actions

答案 1 :(得分:0)

如果您的商业逻辑中没有任何操作就无法保存购买,那么请在购买内的操作中添加状态验证工具

validates :actions, length: {minimum: 1}, presence: true

答案 2 :(得分:0)

事实证明,您必须显式回滚事务,子对象的错误不会传播。所以我最终得到了:

class Purchase < ActiveRecord::Base
  has_many :actions

  after_create do |p|
    a = Action.new(purchase: p)
    if !a.save
      raise ActiveRecord::Rollback
    end
  end
end

class Action < ActiveRecord::Base
  belongs_to :purchase

  before_save do |a|
    false
  end
end

请注意,我还将before_create回调更改为after_create。否则,由于belongs_to也会导致保存父级,因此您将获得SystemStackError: stack level too deep.

答案 3 :(得分:0)

我在处理竞争条件时遇到了这个问题,子对象将通过唯一性验证,但随后数据库约束失败(尝试保存父对象时),导致数据库中无子(无效)父对象

对@lunr建议的解决方案的一般性解决方案:

class Purchase < ActiveRecord::Base
  has_many :actions

  after_save do
    actions.each do |action|
      raise ActiveRecord::Rollback unless action.save
    end
  end
end

class Action < ActiveRecord::Base
  belongs_to :purchase

  before_save do |a|
    false
  end
end