如何处理 Rails 中的散列嵌套键验证?
How to handle hash nested keys validation in Rails?
我目前有一个模型,我想在其中使用点符号来添加错误,以更具体地说明散列属性中的哪个键有问题:
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
,如果不是,它会尝试从模型中读取属性以生成错误消息……然后 boom.
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
是否有 better/supported 方法来验证我不知道的散列中的嵌套键?
来自documentation :
By default this is assumed to be an instance named after the
attribute. Override this method in subclasses should you need to
retrieve the value for a given attribute differently.
看来你的策略是有效的。
一些建议:
- 你可以使用
public_send
而不是 send
- 嵌套还有一个meaning,你可以使用另一个变量名
Array#[a,b]
从 a
开始采用 b
个元素,因此 b
不应大于 Array#size
。您可以只使用 array.drop(1)
。您可能一直在寻找 array[a..b]
,它采用索引 a
和 b
. 之间的元素
我目前有一个模型,我想在其中使用点符号来添加错误,以更具体地说明散列属性中的哪个键有问题:
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
,如果不是,它会尝试从模型中读取属性以生成错误消息……然后 boom.
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
是否有 better/supported 方法来验证我不知道的散列中的嵌套键?
来自documentation :
By default this is assumed to be an instance named after the attribute. Override this method in subclasses should you need to retrieve the value for a given attribute differently.
看来你的策略是有效的。
一些建议:
- 你可以使用
public_send
而不是send
- 嵌套还有一个meaning,你可以使用另一个变量名
Array#[a,b]
从a
开始采用b
个元素,因此b
不应大于Array#size
。您可以只使用array.drop(1)
。您可能一直在寻找array[a..b]
,它采用索引a
和b
. 之间的元素