我也有同样的问题。目前还没有好的答案。
所以我自己解决了这个问题,将关联错误消息替换为详细错误消息:
创建关注文件app/models/concerns/association_error_detail_concern.rb:
module AssociationErrorDetailConcern
extend ActiveSupport::Concern
included do
after_validation :replace_association_error_message
end
class_methods do
def association_names
@association_names ||= self.reflect_on_all_associations.map(&:name)
end
end
def replace_association_error_message
# Gets the intersection between this class's associations and the instance's associations that have validation errors
associations_with_errors = self.errors.keys & self.class.association_names
associations_with_errors.each do |association_name|
next unless self.errors[association_name]
self.errors.delete(association_name)
Array.wrap(public_send(association_name)).each do |record|
record.errors.each do |attribute, error|
self.errors.add(:"#{association_name}.#{attribute}", error)
end
end
end
end
end
然后将其包含在您的模型中:
class Shop::Product < ApplicationRecord
include AssociationErrorDetailConcern
...
end
那我们来说说这些属性的翻译。
Rails 将自动采用相关模型的翻译中定义的那些:
activerecord:
attributes:
associated_model_name:
attribute_name: 'Foo'
但是,可能需要使该属性在关联上下文中验证时具有不同的翻译。在验证用户时,您可能希望显示Poster's e-mail is required 之类的内容,而不是只显示Email is required,而在验证Post 时显示belongs_to :user。
考虑到上述问题,由于错误将被添加到键 :user.email,Rails 会找到 activerecord.attributes.user.email 的翻译,但它也会首先查找 activerecord.attributes.post/user.email,如下所示:
activerecord:
attributes:
post/user:
email: 'Foo'
这为您翻译这些属性提供了最大的灵活性,具体取决于验证它们的上下文。
如果您想了解 Rails 是如何找到这些密钥的,请查看 translation.rb#human_attribute_name,您会看到它会在 . 处拆分密钥并使用它在 .yml 文件中查找密钥.
EDITOR="sublime --wait" bundle open activemodel
最后但同样重要的是,不要忘记 Rails 只会自动验证您的关联,如果它是 has_many 或 has_and_belongs_to_many(检查每个关联类型 validate 上的 validate 选项https://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html)。
belongs_to 和has_one 有一个默认的validate: false,您可以将其更改为true 或使用validates_associated。
在上面的示例中,由于 belongs_to :user 是 Post,因此您必须添加 validates_associated :user 例如,否则用户的验证甚至不会运行。