Rails 3 with composed_of model and validation

匿名 (未验证) 提交于 2019-12-03 08:57:35

问题:

I have this domain model:

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 

When I try to save an invalid model:

> 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"]} 

This is ok, but I would prefer to have the error array filled with the error messages of Address, like this:

=> {: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"]} 

The question is: is there a clean Rails way to do it? Or simply I have to move the validation code from Address to Person (pretty ugly)? Any other solution?

Thank you very much.

回答1:

When you define a composed_of attribute, it becomes an object on it's own. I see two ways to answer your need.

1) add error message in your Address class

Replace your current validations with:

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

This way, you'll be able to access the error messages doing:

p = Person.new p.address.errors 

2) Customize only the address error message

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        

This would render something like:

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

Finally, you could rewrite validators in your Profile class but as you said it's really ugly.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!