【问题标题】:Rails validates_associated and error messagesRails validates_associated 和错误消息
【发布时间】:2016-09-09 05:30:10
【问题描述】:

我想显示来自 Child 模型的验证消息,它给了我基本的 Child is invalid 相反。我尝试了所有解决方案,但没有成功。 简而言之,以下是模型:

Class Parent
  ...
  has_many :children, dependent: :destroy, inverse_of: :parent
  accepts_nested_attributes_for :children, allow_destroy: true
end

Class Child
  belongs_to :parent
  validate :something
  def something
    check = # Here I check something
    if check < 5
      errors[:base] << "validation on children failed"
    end
  end
end

如果我将 validates_associated :children 添加到 Parent 模型,那么我实际上会收到两条 Children is invalid 消息,这有点奇怪。

无论如何,我可以将此块添加到 Parent 模型并获取我想要添加到 Parent 的任何验证消息:基本错误列表:

validate do |parent|
  parent.children.each do |child|
    check = # Here I check something
    if check < 5
      errors[:base] << "validation on children failed"
    end
  end
end

但是,我仍然会在此消息之上收到来自 Child 模型的验证错误消息,因此现在我们将收到 3 条错误消息:“Children is invalidChildren is invalidvalidation on children failed”... 丑陋。

由于我将block添加到Parent模型中,我可以从Child模型中移除validation,从Parent中移除validates_associated :children,然后保存实例不会通过validation,但是属于Child的数据模型将没有验证,并将保存/更新。

希望这一点得到清楚的解释。如果你能提供一个解决方案,那就太棒了!

更新 1:关于accepts_nested_attributes_for

这是非常糟糕的记录。正如我所解释的,我无需请求即可对我的 nsted 模型进行验证。我相信原因是accepts_nested_attributes_for 实际上是从嵌套模型运行验证。 这意味着我从嵌套模型中获得的所有验证消息,无论验证类型如何,都会给我一条消息。我可以设法以某种方式调整该消息的输出,但它仍将是一条消息,而不是特定于嵌套模型遇到的问题。

话虽如此,accepts_nested_attributes_for 确实允许 reject_if 参数。这并没有真正帮助我,因为我需要在嵌套模型上为多个条目运行唯一性验证(一个父母的许多孩子都需要有一个唯一的名字)。

总结:

我认为我需要在子模型中运行验证,但要找到一种方法通过accepts_nested_attributes_for 向父模型报告,并带有特定 消息。这本质上就是我正在寻找的东西! 我想我需要编写一个自定义验证器。有什么想法吗?

【问题讨论】:

  • 你试过这个validates_associated :children , :message=&gt; lambda{|class_obj, obj| obj[:value].errors.full_messages.join(",") }
  • 在您的子模型中...为什么要向子模型添加错误? errors.add(:children ???您肯定只是将错误添加到无效(或基础)的属性中吗?
  • @VrushaliPawar - 这不起作用,而且,如果它确实起作用,它将仅限于一条消息,而不是特定于验证失败的原因。请参阅上面关于“accepts_nested_attributes_for”的更新
  • @TarynEast - 你是对的。我更新了我的问题,尽管这并没有真正改变这个问题的任何基本内容。
  • 好吧,如果那是导致重复错误的原因:)

标签: ruby-on-rails validation


【解决方案1】:

添加我的解决方案,希望对浏览此问题的人有所帮助:

class Parent < AR
  has_many :children, inverse_of: :parent
  validates_associated :children, message: proc { |_p, meta| children_message(meta) }

  def self.children_message(meta)
    meta[:value][0].errors.full_messages[0]
  end
  private_class_method :children_message
end

class Child < AR
  belongs_to :parent, inverse_of: :children
  validates :name, presence: true
end

【讨论】:

  • 非常感谢!没想到这么复杂……
【解决方案2】:

建议的解决方案

这么简单的事情不应该这么烦人来解决。我仍然没有找到任何优雅的解决方案,但我没有更多的时间可以浪费在这上面。 为了公平起见,我将发布我的(丑陋的)解决方案。请注意,此解决方案仍需改进。

我最终创建了一个方法来从两个模型中收集错误,而不是让 Rails 来做。

def collect_errors
  errors = []
  if self.errors.any?
    parent_errors = self.errors.full_messages
    parent_errors.delete("YOURCHILDMODELNAME is invalid")
    errors << parent_errors.join(", ")
  end
  self.children.each do |child|
    if child.errors.any?
       errors << child.errors.messages.values.join(", ")
    end
  end
   return errors.join(", ")
end

然后我对每个模型进行所有验证,在视图中我只显示收集的错误而不是父模型错误:

flash[:warning] = "Failed to create Parent: #{@parent.collect_errors}"

【讨论】:

    【解决方案3】:

    还可以合并错误信息:

    @parent_model.children.each do |child_record|
      child_record.errors.messages.each do |field, messages|
        messages.each do |msg|
          @parent_model.errors.add("#{child_record.id} #{field}", msg)
        end
      end
    end
    

    【讨论】:

      【解决方案4】:

      ActiveModel 错误类现在有副本!并合并!为此目的的方法。复制替换父消息,而合并保留两者:来自父消息和子消息,使用合并或复制将删除来自父消息的消息

      您在父模型中编写如下并使用forms_errors_for:

        validate do |parent|
          errors.messages.clear 
          parent.children.each do |children|
            next if children.valid?
            
            errors.merge! children.errors
          end
        end
      

      ActiveModel 错误的定义

      
       # Merges the errors from <tt>other</tt>.
          #
          # other - The ActiveModel::Errors instance.
          #
          # Examples
          #
          #   person.errors.merge!(other)
      
          def merge!(other)
            @messages.merge!(other.messages) { |_, ary1, ary2| ary1 + ary2 }
            @details.merge!(other.details) { |_, ary1, ary2| ary1 + ary2 }
          end
      
      
      

      【讨论】:

        猜你喜欢
        • 2015-11-02
        • 1970-01-01
        • 1970-01-01
        • 2018-01-09
        • 2018-03-10
        • 2014-04-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多