【问题标题】:rails has_many minimum collection size update validationrails has_many 最小集合大小更新验证
【发布时间】:2010-12-20 03:49:33
【问题描述】:

我有一个接受嵌套属性的has_many 关联。我需要在集合中至少有 1 个关联对象,所以我编写了一个自定义验证器:

class MinimumCollectionSizeValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    if value.size < options[:size]
      record.errors[attribute] << (options[:message] || "must have at least #{options[:size]} line.")
    end
  end
end

模型如下:

has_many :foos, :dependent=>:destroy
accepts_nested_attributes_for :foos
validates :foos, :minimum_collection_size=>{:size=>1}

这在创建模型时效果很好,但在更新时会失败。 @my_model.update_attributes(params[:my_model]) 会返回 true,即使所有的 foo 都被 _destroy 删除了。

如何让update_attributes 的行为与save 相同?

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3


    【解决方案1】:

    验证集合最小大小的更好方法:

    validates :my_association, :length => { :minimum => Fixnum}
    

    【讨论】:

    • 我有过使用它的经验,它确实完全满足了我的需求。因此,对于创建对象,仅验证对象是否定义了最小值。但是,如果假设最小值是 2,并且在创建后我删除了其中一个关联,它会保存并使用 1 验证对象。我不知道为什么会这样,但我希望验证不仅仅适用于创建。
    • 这个验证器也会计算标记为销毁的对象。最好使用自定义 validator 并计算未标记为销毁: answers.reject(&:marked_for_destruction?).count
    • 如果您将嵌套属性与 allow_destroy 一起使用,此验证将失败,因为它会计算标记为销毁的出现次数。
    • 这是解决方案在删除集合中的最后一条记录时出现问题。下面我写更好的解决方案。
    • @duleorlovic,@Brooks 这不再是一个案例。在 Rails 5 中引入了新的 ActiveRecordlength validator 来解决此问题。
    【解决方案2】:

    苏德苏内

    是的,validates :foos, :length =&gt; {:minimum =&gt; 1, :message=&gt;"At least one foo" } 比原来的更好,但同样的问题仍然存在。

    要修复它,我们可以使用 validate 方法:

    validate :validate_foos
    
    private
    def validate_foos
      remaining_foos = foos.reject(&:marked_for_destruction?)
      errors.add :foos, "At least one foo" if remaining_foos.empty?
    

    希望对遇到同样问题的人有所帮助。

    【讨论】:

    【解决方案3】:

    创建验证器:

    class CollectionLengthValidator < ActiveModel::Validations::LengthValidator
      def validate_each(record, attribute, value)
        value = value.respond_to?(:reject) ? value.reject(&:marked_for_destruction?) : value
        super(record, attribute, value)
      end
    end
    

    这是解决删除集合中最后一条记录的问题。

    然后在模型中用作标准长度验证器:

    validates :foos, :collection_length => {:minimum => 1}
    

    【讨论】:

    • 这其实是正确的答案。谢谢!它也适用于在改革表单中进行验证而不是依赖于accept_nested_attributes
    猜你喜欢
    • 2023-01-29
    • 2011-03-09
    • 1970-01-01
    • 1970-01-01
    • 2015-12-19
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多