0

我有两个不同的对象,它们可以属于一个父对象。这些子对象也可以彼此属于(多对多)。确保属于彼此的子对象也属于同一个父对象的最佳方法是什么。

作为我正在尝试做的一个例子,我有一个Kingdom同时具有许多PeopleLand. 该People模型将有一个自定义validate检查每个相关的Landerror.adds 是否有一个不匹配的kingdom_id. 该Land模型将具有类似的validate.

这似乎有效,但是在更新它时允许记录保存'THIS IS AN ERROR'错误people.errors,但是Land引发错误的记录已添加到People集合中。

kingdom = Kingdom.create
people  = People.create(:kingdom => kingdom)
land    = Land.create(:kingdom_id => 999)
people.lands << land
people.save
puts people.errors.inspect # @messages={:base=>["THIS IS AN ERROR"]
puts people.lands.inspect  # [#<Land id: 1...

理想情况下,我希望错误取消记录更新。我应该采取另一种方式来解决这个问题,还是我完全走错了方向?

# Models:

class Kingdom < ActiveRecord::Base
  has_many :people
  has_many :lands
end

class People < ActiveRecord::Base
  belongs_to :kingdom
  has_and_belongs_to_many :lands

  validates :kingdom_id, :presence => true
  validates :kingdom, :associated => true
  validate  :same_kingdom?

  private
    def same_kingdom?
      if self.lands.any?
        errors.add(:base, 'THIS IS AN ERROR') unless kingdom_match
      end
    end

    def kingdom_match
      self.lands.each do |l|
        if l.kingdom_id != self.kingdom_id
          return false
        end
      end
    end
end

class Land < ActiveRecord::Base
  belongs_to :kingdom
  has_and_belongs_to_many :people
end
4

1 回答 1

2

首先,验证不会阻止将记录添加到模型的未持久集合中。它将防止修改后的集合被持久化到数据库中。因此模型将处于无效状态,并带有相应错误的标记。要看到这一点,您可以简单地重新加载people对象。

您的逻辑也有错误 -kingdom_match即使没有找到无效的 Kingdom_id,该方法也永远不会返回 true。您应该添加一行来解决此问题:

def kingdom_match
  self.lands.each do |l|
    return false if l.kingdom_id != self.kingdom_id
  end
  true
end

您可以使此验证更加简洁,并kingdom_match完全跳过该方法:

def same_kingdom?
  if self.lands.any?{|l| l.kingdom_id != self.kingdom_id }
    errors.add(:base, 'THIS IS AN ERROR')
  end
end
于 2013-08-14T17:38:01.050 回答