验证 has_many 关系中的属性总和

Posted

技术标签:

【中文标题】验证 has_many 关系中的属性总和【英文标题】:Validation of sum of attributes from has_many relationship 【发布时间】:2014-09-16 15:43:13 【问题描述】:

使用以下 Ruby on Rails 模型“Foo”:

class Foo < ActiveRecord::Base

  has_many :bars

  accepts_nested_attributes_for :bars

  def bar_value_total
    self.bars.sum(:value) #TODO: must verify this is in range (0.0 .. 100.0)
  end

end

而 Bar 是一个具有单值属性的简单模型:

class Bar < ActiveRecord::Base

  validates :value, :inclusion =>  :in => 0.0..100.0 , :presence => true

end

如果总 Bars 中的值不在指定范围 (0.0 .. 100.0) 内,我如何添加验证以防止保存 Foo?

例如,如果 Foo 具有三个值分别为 40.0 和 50.0 的 Bars,则在添加第三个 Bar 且大于 10.0 时,保存尝试应该会失败。

如果 Foo 已经有一个值为 100.0 的 Bar,如果添加的 Bar 值超过 0.0,则 Save 尝试应该失败。


更新: 我向 Bar 模型添加了一个自定义验证(并且它有效)......但它似乎有点笨拙。还有比这更好的“Rails 方式”吗?
class Bar < ActiveRecord::Base

  validates :value, :inclusion =>  :in => 0.0..100.0 , :presence => true
  validate :bar_totals_are_within_range

private
  def bar_totals_are_within_range
    if !self.foo.bar_value_total + self.value - self.value_was).between?(0.0, 100.0)
      errors.add(:base, "Total bar value exceeded")
    end
  end

end

【问题讨论】:

做一个custom validation。 我添加了一个自定义验证,但它似乎有点脏。想知道有没有更好的方法。 (见更新) 没有内置的 Rails 方法可以做到这一点。所以,是的,它可能有点“脏”。 【参考方案1】:

我会说:

  accepts_nested_attributes_for :bars, :reject_if => :any_invalid_bar?

  def any_invalid_bar?
    bars.any? &:invalid?
  end

这种方式会在保存一个Foo 之前使用您在Bar 中编写的任何验证来验证每个Bar

【讨论】:

以上是关于验证 has_many 关系中的属性总和的主要内容,如果未能解决你的问题,请参考以下文章

ruby on rails has_many 关系表单验证孩子

有关如何使用has_many:through关系正确设置验证的指导?

使用“has_many :through”进行验证

如何处理 RoR 中的三向关联?

根据 Cypher neo4j 中的属性值总和创建新关系?

Laravel Eloquent:获取嵌套关系中的数据总和并将其添加为新属性