I validate Realty objects depending on their active_state, so if it's pending, multiple fields are allowed to be blank.
with_options :if => Proc.new { |a| a.active_state == 'pending'} do |realty|
realty.validates :street, :length => {:in => 1..100}, :allow_blank => true
realty.validates :postalcode, :numericality => {:only_integer => true}, :length => {:in => 4..5}, :allow_blank => true
realty.validates :city, :length => {:in => 1..50}, :allow_blank => true
realty.validates :description, :length => {:maximum => 8000}, :allow_blank => true
realty.validates :leasing_costs, :numericality => {:only_integer => true}, :length => {:in => 1..9}, :allow_blank => true
end
with_options :if => Proc.new { |a| a.active_state != 'pending'} do |realty|
realty.validates :street, :length => {:in => 1..100}
realty.validates :postalcode, :numericality => {:only_integer => true}, :length => {:in => 4..5}
realty.validates :city, :length => {:in => 1..50}
realty.validates :description, :length => {:maximum => 8000}
realty.validates :leasing_costs, :numericality => {:only_integer => true}, :length => {:in => 1..9}
end
The only difference are those :allow_blank => true options.
I want to make this code more dry, so my attempt would be to use the normal validations block once:
validates :street, :length => {:in => 1..100}
validates :postalcode, :numericality => {:only_integer => true}, :length => {:in => 4..5}
validates :city, :length => {:in => 1..50}
validates :description, :length => {:maximum => 8000}
validates :leasing_costs, :numericality => {:only_integer => true}, :length => {:in => 1..9}
and then simply call some function on all of those fields in case the state is pending:
with_options :if => Proc.new { |a| a.active_state == 'pending'} do |realty|
realty.allow_blank_of :street, :postalcode, :city, :description, :leasing_costs
end
Similar to all those validates_uniqueness_of :x, :y, :z methods.
I couldn't find a function to fit my need. How can I approach this?
It would be nice if the :allow_blank option took a proc, but I don't think it does. However, you can achieve the same result using the :if option since :allow_blank is essentially a way of saying "if the attribute is blank then don't run this validation requirement". So try this:
with_options :if => Proc.new { |a| a.active_state == 'pending' ? a.present? : true } do |realty|
realty.validates :street, :length => {:in => 1..100}
realty.validates :postalcode, :numericality => {:only_integer => true}, :length => {:in => 4..5}
realty.validates :city, :length => {:in => 1..50}
realty.validates :description, :length => {:maximum => 8000}
realty.validates :leasing_costs, :numericality => {:only_integer => true}, :length => {:in => 1..9}
end
The proc in this case is saying... if the active_state is 'pending' and the attribute is present then execute this validation. But if the active_state is not 'pending' then the attribute isn't allowed to be blank so always run the validation. I hope I got that logic right based on your needs.
From pdobb's answer
However, you can achieve the same result using the :if
option since :allow_blank is essentially a way of saying "if the
attribute is blank then don't run this validation requirement".
Based on pdobbs explanation what allow_blank => true actually does, I could narrow the validations down to:
validates :street, :length => {:in => 1..100}, :unless => :pending?
validates :postalcode, :numericality => {:only_integer => true}, :length => {:in => 4..5}, :unless => :pending?
validates :city, :length => {:in => 1..50}, :unless => :pending?
validates :description, :length => {:maximum => 8000}, :unless => :pending?
validates :leasing_costs, :numericality => {:only_integer => true}, :length => {:in => 1..9}, :unless => :pending?
def pending?
active_state == "pending"
end
So I simply skip all of those validations if the active_state is "pending".
Allot more DRY :)
I haven't ran this, but I think this may work
before_commit :build_callback_validator, :on => :create
def build_callback_validator
validates :street, :length => {:in => 1..100}
validates :postalcode, :numericality => {:only_integer => true}, :length => {:in => 4..5}
validates :city, :length => {:in => 1..50}
validates :description, :length => {:maximum => 8000}
validates :leasing_costs, :numericality => {:only_integer => true}, :length => {:in => 1..9}
if self.active_state != 'pending'
self.allow_blank_of :street, :postalcode, :city, :description, :leasing_costs
end
end
Right now, I have a User model with a username field that's being validated by:
validates :username,
:presence => true,
:length => { :in => 3..60 },
:format => { :with => /^[a-zA-Z0-9\-_ ]+$/ }
How can I hide the :length and :format validation errors if :presence is not met?
Try :allow_blank => true in 2nd and 3rd validations.
I think you can do like this:
validates :username,
:presence => true,
:length => { :in => 3..60, :allow_nil => true },
:format => { :with => /^[a-zA-Z0-9\-_ ]+$/, :allow_nil => true }
It will not care about length and format validations when username is not set, but it will work fine with at least one character typed.
I have the following in my user.rb:
validates :fname, :length => { :minimum => 1, :maximum => 100 }
validates :lname, :length => { :minimum => 1, :maximum => 100 }
How can I update this validations to only apply to existing users? I ask as I want to allow a user to signup without having to enter a fname or lname.
Ideas?
validates :fname, :length => { :minimum => 1, :maximum => 100 }, :unless => :new_record?
validates :fname, :length => { :minimum => 1, :maximum => 100 }, :unless => :new_record?
You can also use :on => :update, to make the validation only apply when a record is updated (as opposed to :on => :create)
I have an object that contains a number range and a description [min_val, max_val, name].
I need to validate that min_val < max_val. However, if one of them is blank I get a nil comparison error, instead, I'd like to tell the user that a number is required.
Also, how can I change the error message for numericality?
validates :min_val, :presence => true, :numericality => {:greater_than => 0, :less_than => :max_val}
validates :max_val, :presence => true, :numericality => {:greater_than => 0, :greater_than => :min_val}
validates :name, :presence => true, :if => Proc.new { |r| !r.min_val.nil? || !r.max_val.nil? }
You can use :message to specify a custom error message.
validates :max_val, :presence => true, :numericality => {:greater_than => 0, :message => " is an invalid number."}
validates :min_val, :presence => true, :numericality => {:greater_than => 0, :message => " is an invalid number."}
validate do |record|
record.errors.add_to_base("The min_val should be less than max_val") if min_val.to_i >= max_val.to_i
end
validates :name, :presence => true, :if => Proc.new { |r| !r.min_val.nil? || !r.max_val.nil? }
I'm a newbie in rails. how put a validated on password field. specified only on create and used an allow_blank method. but everytime i update it still creates a nil in the password field. any help?
validates :password, :presence => { :on => :create },
:confirmation => true,
:length => { :within => 8..40},
:allow_blank => true,
Try this:
validates :password, :presence => { :if => :new_record? },
:confirmation => true,
:length => { :within => 8..40 }