【问题标题】:Rails 3 with composed_of model and validation带有composed_of模型和验证的Rails 3
【发布时间】:2011-07-15 13:22:37
【问题描述】:

我有这个域模型:

class Person < ActiveRecord::Base
  composed_of :address,
              mapping: [%w(address_street street), %w(address_city city), %w(address_zip_code zip_code), %w(address_country country)]

  validates :name, presence: true, length: { maximum: 50 }
  validates :surname, presence: true, length: { maximum: 50 }

  validates_associated  :address
end

class Address
  include ActiveModel::Validations
  include ActiveModel::Conversion
  extend ActiveModel::Naming

  attr_reader :street, :city, :zip_code, :country

  validates :street, presence: true
  validates :city, presence: true
  validates :zip_code, presence: true
  validates :country, presence: true

  def initialize(street, city, zip_code, country)
    @street, @city, @zip_code, @country = street, city, zip_code, country
  end

  def ==(other_address)
    street == other_address.street && city == other_address.city && zip_code == other_address.zip_code && country == other_address.country
  end

  def persisted?
    false
  end
end

当我尝试保存无效模型时:

> p = Person.new
=> #<Person id: nil, name: nil, surname: nil, address_street: nil, address_city: nil, address_zip_code: nil, address_country: nil
> p.valid?
=> false
> p.errors
=> {:name=>["can't be blank"], :surname=>["can't be blank"], :address=>["is invalid"]}

这没关系,但我更希望错误数组填充地址的错误消息,如下所示:

=> {:name=>["can't be blank"], :surname=>["can't be blank"], :address_street=>["can't be blank"], :address_city=>["can't be blank"], :address_zip_code=>["can't be blank"], :address_country=>["can't be blank"]}

问题是:有没有一种干净的 Rails 方法可以做到这一点?或者只是我必须将验证代码从地址移动到个人(非常丑陋)?还有其他解决方案吗?

非常感谢。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 validation activerecord composition


    【解决方案1】:

    当您定义一个composed_of 属性时,它会成为一个自己的对象。我看到有两种方法可以满足您的需求。

    1) 在您的 Address 类中添加错误消息

    将您当前的验证替换为:

    validates_each :street, :city, :zip_code, :country do |record, attr, value|  
      record.errors.add attr, 'should not be blank' if value.blank?
    end
    

    这样,您将能够访问错误消息:

    p = Person.new
    p.address.errors
    

    2) 仅自定义 address 错误消息

    validates_associated  :address, 
                          :message => lambda { |i18n_key, object| self.set_address_error_msg(object[:value]) }
    
    def self.set_address_error_msg address
      errors_array = Array.new
      address.instance_variables.each do |var|
        errors_array << "#{var[1..-1]} should not be blank" if address.send(var[1..-1]).blank?
      end
      errors_array.join(", ")
    end       
    

    这将呈现如下内容:

    => #<OrderedHash {:address=>["country should not be blank, zip_code should not be blank, validation_context should not be blank, city should not be blank"]}> 
    

    最后,您可以在 Profile 类中重写验证器,但正如您所说,它真的很难看。

    【讨论】:

    • 我已经结束了使用validates_each 并使用&lt;ul&gt; &lt;% (@person.errors.full_messages + @person.address.errors.full_messages).each do |msg| %&gt; &lt;li&gt;&lt;%= msg %&gt;&lt;/li&gt; &lt;% end %&gt; &lt;/ul&gt; 在表单中显示错误
    • 有没有更好的方法来获取模型的所有错误及其所有组成的对象?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多