开发者

custom error message for valid numericality of in rails

I wanted to have custom error messages for my field names. I stumbled upon another SO question

So I added something like this:

class Product < ActiveRecord::Base
  validate do |prod|
    prod.errors.add_to_base("Product price can't be blank") if prod.prod_price.blank?
  end
end

But I also want to check the numericality of prod_price. If I just add validate_numericality_of :prod_price and product price is empty then both the error messages show up (empty and is not a number).

How can I just have 'is not a number' error message show up only when product price is NOT empty?

I tried doing

class Product < ActiveRecord::Base
  validate do |prod|
    prod.errors.add_to_base("Product price can't be blank") if prod.prod_price.blank?
    if !prod.prod_price.blank?
       prod.errors.add_to_base("Product price must be a number") if prod.prod_price.<whatdo i put here>
    end
  end
end

Also, How can I have a custom message for 'is not 开发者_如何学编程a number'. I want to hide showing my column name to the user.


The currently accepted answer works, but here's a data driven way to do it using Rails' i18n:

Adding allow_blank: true to validates_numericality_of will take care of the empty problem.

Then you can use i18n to automatically translate attribute names for you (docs here). For prod_price you'd just add this to en.yml:

en:
  activerecord:
    attributes:
      product:
        prod_price: "Product price"

Now for the must be a number part, we can use i18n again. From the docs:

Active Record validation error messages can also be translated easily. Active Record gives you a couple of namespaces where you can place your message translations in order to provide different messages and translation for certain models, attributes, and/or validations.

There's a handy table of those namespaces here, where you can see that the message for a numericality validataion is not_a_number.

So now we can add that to en.yml thus:

en:
  activerecord:
    errors:
      models:
        product:
          attributes:
            prod_price:
              not_a_number: "must be a number"

Now when the validation fails it'll concatenate the two, to give you: Product price must be a number.


You can have custom messages without writing your own validate method. Just add :message:

validates_presence_of :prod_price, :message => "Product price can't be blank"

If you want to skip the numericality validation when prod_price is not present, add :allow_nil:

validates_presence_of :prod_price, :message => "Product price can't be blank" validates_numericality_of :prod_price, :allow_nil => true

Then the numericality check will not run when prod_price is missing.

EDIT:

Wait, you don't want the field name to show up in the error message, do you? I missed that. So you'll need the custom validation after all.

EDIT #2:

Ok how about this then:

protected

def validate
  if prod_price.blank?
    errors.add "Product price can't be blank"
  else
    begin
      Integer(attributes_before_type_cast["prod_price"])
    rescue ArgumentError  
      errors.add "Product price must be a number"
    end
   end
end


For a lot of reasons, unless you need to do something unusual, you should be attaching error messages to specific fields (it's easier to do unit tests, easier to modify errors later, you can display markers next to invalid fields if you want, etc). I think what you want to do can be accomplished with this:

class Product < ActiveRecord::Base
  validates_numericality_of :name, :if => lambda{ |obj| obj.prod_price? }
  validates_presence_of :name
end


I took this approach from the other SO question

class User < ActiveRecord::Base

  HUMANIZED_ATTRIBUTES = {
    :email => "E-mail address"
  }

  def self.human_attribute_name(attr)
    HUMANIZED_ATTRIBUTES[attr.to_sym] || super
  end

end

this way I dont have to write custom message for each field. I just change the fild name presented to the user


if prod.prod_price.blank?
  prod.errors.add_to_base("Product price can't be blank") 
elsif prod.prod_price.match(/[^\d]/)
  prod.errors.add_to_base("Product price must be a number")
end
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜