【问题标题】:How to use a parent record's value in rails validation如何在 Rails 验证中使用父记录的值
【发布时间】:2013-09-09 12:38:38
【问题描述】:

我有一个 Rails 3.2 应用程序,其中我有一个简单的父/子关系,我需要使用父级的值来验证子级的属性。模型如下所示:

class RubricItem < ActiveRecord::Base
  attr_accessible :max_score, :min_score, :name, :order
  has_many :rubric_ranges
end

class RubricRange < ActiveRecord::Base
  attr_accessible :helper, :range_max, :range_min, :rubric_item_id
  validates_presence_of :helper, :range_max, :range_min
  validates :range_max, :range_min, :numericality => {:only_integer => true}
  validates :range_max, :numericality => { :greater_than => :range_min }
  belongs_to :rubric_item
end

我希望能够验证两个不同的东西。首先,对于一个 rubric_range,我想验证它的 range_min 值对于它的父 rubic.min_score 是 >= 并且 range_max

其次,我想验证其他 rubric_range 是否具有唯一的最小/最大值。换句话说,不能为同一个值定义两个 rubric_range,因此如果一个覆盖 0-2,另一个则不能在其范围内包含 0、1 或 2。示例:第一个范围是 0-2,如果定义了 2-4 范围,我想在父级范围内引发验证错误。

感谢您的帮助。

【问题讨论】:

    标签: ruby-on-rails validation parent-child


    【解决方案1】:

    您几乎可以像使用 parent 一样使用 parent:

    class RubricRange < ActiveRecord::Base
      ...
      validate :has_proper_range
      ...
      def has_proper_range
        error.add(:range_min, ' cannot be smaller than RubricItem minimum score') if range_min < rubric_item.min_score
        error.add(:range_max, ' cannot be greater than RubricItem maximum score') if range_max > rubric_item.max_score
      end
    

    唯一的问题是,如果您想使用 nested_attributes 创建 RubricRange 项和 RubricItem,因为关联的构建方法不会为新记录设置反向关系。

    第二次验证可以通过简单地注意来完成,如果在给定范围内有任何其他范围的最小值或最大值,则它将失败。因此:

    validate :do_not_overlap_with_other_ranges
    ...
    def do_not_overlap_with_other_ranges
      overlapping_ranges = self.class.where('(range_min >= :min AND range_min <= :max) OR (range_max >= :min AND range_max <= :max)', {:min => range_min, :max => range_max})
      overlapping_ranges = overlapping_ranges.where.not(:id => id) unless new_record?
      errors.add(:base, 'Range overlapping with another range') if overlapping_ranges.exists?
    end
    

    (请随时对上面的查询发表评论,因为我认为应该有更好的方式来写这个)。

    【讨论】:

    • 这很好用,只需进行一些编辑(我已经提交了)。这是更新的完整(和工作!)查询:overlapping_ranges = self.class.where('( id = :id AND (range_min >= :min AND range_min = :min AND range_max rubric_item_id, :min => range_min, :max => range_max})
    • 实际上我必须更新查询以允许更新通过排除当前记录的最小值/最大值来通过验证:overlay_ranges = self.class.where('( id :myid AND rubric_item_id == : riid AND ( (range_min >= :min AND range_min = :min AND range_max id, :riid => rubric_item_id, :min = > range_min, :max => range_max})
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多