如何在Rails中处理哈希嵌套密钥验证?

时间:2017-01-29 16:34:20

标签: ruby-on-rails ruby activemodel

我目前有一个模型,其中我想使用点表示法来添加错误,以更具体地说明哈希属性中的哪个键有错误:

class MyFormObject
  include ActiveModel::Validations
  include ActiveModel::AttributeAssignment

  attr_accessor :name, :metadata

  validates :name, presence: true 
  validate address_is_present_in_metadata

  def initialize(**attributes)
    assign_attributes(attributes)
  end

  def validate_address_is_present_in_metadata
    errors.add("metadata.address", "can't be blank") if metadata[:address].blank?
  end
end

这样可行,但如果我决定使用符号而不是如下消息:

errors.add("metadata.address", :blank) if metadata[:address].blank?

然后Rails抱怨,因为metadata.address不是属性。抛出错误的ActiveModel::Errors代码检查属性是否为:base,如果属性为value = attribute != :base ? @base.send(:read_attribute_for_validation, attribute) : nil) ,则会尝试从模型中读取属性以生成错误消息...并且繁荣。

read_attribute_for_validation

作为解决方法,我决定覆盖def read_attribute_for_validation(key) key_str = key.to_s return public_send(key) unless key_str.include?(".") key_path = key_str.split(".").map(&:to_sym) public_send(key_path.first).dig(*key_path[1, key_path.size]) end

{{1}}

是否有更好/支持的方法来验证我不知道的哈希中的嵌套密钥?

1 个答案:

答案 0 :(得分:0)

来自documentation

  

默认情况下,这被认为是以。之后命名的实例   属性。如果需要,可以在子类中重写此方法   以不同方式检索给定属性的值。

所以你的策略似乎是有效的。

但有些建议:

  • 您可以使用public_send代替send
  • 嵌套有另一个meaning,您可以使用另一个变量名称
  • Array#[a,b]b开始采用a个元素,因此b不应大于Array#size。你可以使用array.drop(1)。您可能一直在寻找array[a..b],其中包含索引ab之间的元素。