【问题标题】:Validate children before creating parent在创建父级之前验证子级
【发布时间】:2021-05-04 19:49:49
【问题描述】:

只有当子模型符合某些验证时,我如何才能创建父模型,例如它们的属性总和等于来值等?

我有一个父模型:

class Foo < ApplicationRecord

  has_many :bars, dependent: :destroy

  accepts_nested_attributes_for :bars, allow_destroy: true

end

而子模型为:

class Bar < ApplicationRecord

  belongs_to :foo

end

有正确的方法吗?我应该在哪里验证子模型?另外我怎么能用 rspec 测试它?像这样?

before do
  @foo = create(:foo)
  @bar = create(:bar, value: 30, foo_id: @foo.id)
end

【问题讨论】:

    标签: ruby-on-rails validation model


    【解决方案1】:

    Rails 提供validates_associated,这将确保相关记录有效。如果关联记录无效,则不保存父记录。

    Foo:

    class Foo < ApplicationRecord
      has_many :bars, dependent: :destroy
      accepts_nested_attributes_for :bars, allow_destroy: true
    
      validates_associated :bars
    end
    

    Bar:

    class Bar < ApplicationRecord
      belongs_to :foo
    
      include ActiveModel::Validations
      validates_with BarValidator
    end
    

    BarValidator,即a custom validator

    class BarValidator < ActiveModel::Validator
      def validate(record)
        record.errors.add :some_error, 'Some message' unless condition_met?
      end
    end
    

    你说过:

    只有当它的子模型符合一些验证,比如它们的属性总和等于来值等等?

    这有点模棱两可。如果您确实确实需要计算子项的总和,那么您可以向父项添加一个验证器,该验证器通过子项进行映射并在未能满足条件时附加错误:

    Foo,(或者最好是验证者):

    validate :children_condition
    
    def children_condition
      errors[:base] << "Some message" if bars.map(&:attribute).sum != expected_minimum_value
    end
    

    validates_related 文档中的重要说明:

    警告:不得在关联的两端使用此验证。这样做会导致循环依赖,导致无限递归。

    注意:如果尚未分配关联,则此验证不会失败。如果要确保关联既存在又保证有效,还需要使用 validates_presence_of。

    至于:

    另外,我如何使用 rspec 对其进行测试?

    我将创建一个包含有效父、有效子 && 有效父、无效子等的测试套件,并期望 Model.count 增加了预期的数量(在后一个示例中为零)。

    【讨论】:

    • 在测试验证时,您实际上并不需要创建记录。您可以在模型上调用#valid?,然后设置期望on the errors object。您可以通过功能或请求规范间接测试实际创建记录。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-06
    • 2012-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多