I have a form with a mobile/cell number and a home phone number.
I want to have only validate presence of mobile/cell number if the phone number has been left blank or vice versa.
My current validations for these fields are as follows.
validates_presence_of :mobile_number
validates_presence_of :home_phone
validates_length_of :home_phone, :minimum => 12, :maximum => 12
validates_length_of :mobile_number, :minimum => 10, :maximum => 10, :allow_blank => true
validates_format_of :home_phone, :with => /\A[0-9]{2}\s[0-9]{4}\s[0-9]{4}/, :message => "format should be 02 9999 9999"
I thought I could have something like the following but not sure how to do this exactly.
validates_presence_of :mobile_number, :unless => :home_phone.blank?
I'm using Rails 3.
You don't need a lambda. This will do:
validates_presence_of :mobile_number, :unless => :home_phone?
Also, all of the validators take the same if/unless options, so you can make them conditional at will.
Update: Looking back at this answer a few days later, I see that I should explain why it works:
If you set a validator's :unless option to be a symbol, Rails will look for an instance method of that name, invoke that method on the instance that's being validated -- at validation time -- and only perform the validation if the method returns false.
ActiveRecord automatically creates question mark methods for each of your model's attributes, so the existence of a home_phone column in your model's table causes Rails to create a handy #home_phone? method. This method returns true if and only if home_phone is present (i.e. not blank). If the home_phone attribute is nil or an empty string or a bunch of white space, home_phone? will return false.
UPDATE: Confirmed that this old technique continues to work in Rails 5.
You must use a lambda / Proc object:
validates_presence_of :mobile_number, :unless => lambda { self.home_phone.blank? }
Starting in Rails 4, you can pass a block to presence. Concisely:
validates :mobile_number, presence: {unless: :home_phone?}
Also, :home_phone? returns false for nil or blank.
Here is another way that works in rails 4
validates_presence_of :job, if: :executed_at?
validates :code,
presence: true,
length: { minimum: 10, maximum: 50 },
uniqueness: { case_sensitive: false },
numericality: { only_integer: true }
a short solution:
validates_presence_of :mobile_number, unless: -> { home_phone.blank? }
In newer versions of Rails, instead of relying on old validates_presence_of, you should use validates and list validations for each attribute:
validates :mobile_number, presence: { if: -> { home_phone.present? } }
Tested in Rails 7, this works flawlessly:
validates :mobile_number, presence: { unless: :home_phone }
Related
I just came across a situation where the accepted solution for Validate presence of field only if another field is blank - Rails wasn't complete.
I'd like one or both of two fields to be present but in my case one of the fields points needs to be a number between 0 and 10. In cases where the points field is zero :points? is evaluating to false and a blank comment is considered invalid. I tried to make it a little more specific by specifying :points.blank?:
validates :comment, presence: { unless: :points.blank?, on: :create }
validates :points, presence: { unless: :comment?, on: :create },
numericality: { only_integer: true, allow_nil: true, less_than_or_equal_to: 10, greater_than_or_equal_to: 0 }
That seems to work (I can save the first entry with 0 points and no comment) but on subsequent saves I'm getting weird errors from the controller:
NoMethodError (undefined method 'validate' for false:FalseClass):
app/controllers/comments_controller.rb:8:in 'create'
Is there something else I need to do with the validation? Do I need to use a lambda (as suggested in some answers to the linked question)?
:points.blank? evaluates to false, which is being set as the value of the :unless key in your hash. You will need to specify a method name or Proc for the :unless option to work. You can simplify the whole setup:
validates :comment, presence: true, on: :create, if: :points?
validates :points, numericality: :only_integer, inclusion: 0..10
Not sure how you got first record working, but this is not correct syntax:
validates :comment, presence: { unless: :points.blank?, on: :create }
Instead you should be defining a method like this in your model:
def points_blank?
# your code for zero handling
#
end
and then use that method in unless like this:
validates :comment, presence: { unless: :points_blank?, on: :create }
I am using this block of code for validating email address. The format of entered email address validates well, but the problem is with the "uniqueness" part - I currently can enter more identic email addresses to the database - how is that possible?
Has something changed in Rails 4 about validations?
class BetaAccess < ActiveRecord::Base
validates_format_of :email,:with => Devise::email_regexp, uniqueness: true
end
Thank you.
Try this:
class BetaAccess < ActiveRecord::Base
validates :email,format: {with: Devise::email_regexp}, uniqueness: true
end
format and uniqueness are different validators, if you want to use in one line, you should use validates method.
validates :email, :format => { :with => Devise::email_regexp }, :uniqueness => true
validates_format_of :email,:with => Devise::email_regexp, uniqueness: true
combines uniqueness into the validation for format. Use the validates syntax
validates :email,format: {with: Devise::email_regexp},
uniqueness: true
Also, use the new ruby syntax for hashes. Kind of neat that way
I have a password field and that validates presence and length and both are working fine. But when I submit the form with blank password field, it displays error messages for both validations.
What I want is if the password is blank then length validator must not checked and display error message for only presence validator. Length validator will only be checked if password is present.
You can use Object#with_options and ActiveRecord::Base#new_record?:
class User < ActiveRecord::Base
with_options :if => :new_record? do |user|
user.validates :password, presence: true, length: { maximum: 20 }
end
end
Look rails conditional validation.
Along with other validations pass this
:allow_blank => true
For example
validates :password, :presence => true, :length => { :maximum => 20, :allow_blank => true }
I want validate presence of these 2 attributes :shipping_cost and :shipping_cost_anywhere if the attribute :shipping is equal to true. and If
I have this in my model but not working fine for me:
validates_presence_of :shipping_cost, :shipping_cost_anywhere, :allow_blank => "true" if :shipping == "true"
this is my :shipping attribute:
field :shipping, :type => Boolean, :default => "false"
How can I do it?
Thank you!
Edited.
I'm using mongoid and simple_form gems
validates_presence_of :shipping_costs_anywhere, :if => :should_be_filled_in?
def should_be_filled_in?
shipping_costs_anywhere == "value"
end
The method will return true or false when it's called in the statement.
No need to put colon in front of shipping_costs_anywhere.
The fix for me to this question is the next code:
validates :shipping_cost, :shipping_cost_anywhere, :presence => true, :if => :shipping?
Thank you to all for your help but any answer has worked for me. thanks!
Stumbled across this today and thought I'd freshen the answer. As others mentioned, you can put the logic in a function. However, you can also just throw it in a proc.
validates_presence_of :shipping_costs_anywhere, :if => Proc.new { |o|
o.shipping_costs_anywhere == "value"}
http://guides.rubyonrails.org/active_record_validations.html#using-a-symbol-with-if-and-unless
The validates is now preferred over validates_presences_of etc. As hyperjas mentioned you can do this:
validates :shipping_cost,
:shipping_cost_anywhere,
:presence => true, :if => :shipping?
However, that conditionalizes the entire validation for both :shipping_cost and :shipping_cost_anywhere. For better maintainability, I prefer a separate validate declaration for each attribute.
More importantly, you will likely run into situations where you have multiple validations with different conditions (like one for presence and another for length, format or value). You can do that like this:
validates :shipping_cost,
presence: { if: :shipping? },
numericality: { greater_than: 100, if: :heavy? }
You can also let rails evaluate a ruby string.
validates :shipping_cost,
presence: { if: "shipping?" },
numericality: { greater_than: 100, if: "shipping? and heavy?" }
And finally, optionally add separate custom messages:
validates :shipping_cost,
presence: { if: "shipping?", message: 'You forgot the shipping cost.' },
numericality: { greater_than: 100, if: "shipping? and heavy?", message: 'Shipping heavy items is $100 minimum.' }
And so on. Hope that helps.
I can't test it, but I think the syntax is more like:
validates_presence_of :shipping_cost, :shipping_cost_anywhere, :allow_blank => "true", :if => "shipping.nil?"
See:
http://guides.rubyonrails.org/active_record_validations_callbacks.html#conditional-validation
Here is my code working for me.Call method on if condition rather than comparing
validates :prefix, :allow_blank => true, :uniqueness => { :case_sensitive => true } ,:if => :trunk_group_is_originating?
def trunk_group_is_originating?
if self.direction == "originating"
true
else
false
end
end
Hope it helps you.......
I have a field that I would like to validate. I want the field to be able to be left blank, but if a user is entering data I want it to be in a certain format. Currently I am using the below validations in the model, but this doesn't allow the user to leave it blank:
validates_length_of :foo, :maximum => 5
validates_length_of :foo, :minimum => 5
How do I write this to accomplish my goal?
You can also use this format:
validates :foo, length: {minimum: 5, maximum: 5}, allow_blank: true
Or since your min and max are the same, the following will also work:
validates :foo, length: {is: 5}, allow_blank: true
I think it might need something like:
validates_length_of :foo, minimum: 5, maximum: 5, allow_blank: true
More examples: ActiveRecord::Validations::ClassMethods
Or even more concise (with the new hash syntax), from the validates documentation:
validates :foo, length: 5..5, allow_blank: true
The upper limit should probably represent somehting more meaningful like "in: 5..20", but just answering the question to the letter.
From the validates_length_of documentation:
validates_length_of :phone, :in => 7..32, :allow_blank => true
:allow_blank - Attribute may be blank; skip validation.
every validates_* accepts :if or :unless options
validates_length_of :foo, :maximum => 5, :if => :validate_foo_condition
where validate_foo_condition is method that returns true or false
you can also pass a Proc object:
validates_length_of :foo, :maximum => 5, :unless => Proc.new {|object| object.foo.blank?}
validates_length_of :reason, minimum: 3, maximum: 30
rspec for the same is
it { should validate_length_of(:reason).is_at_least(3).is_at_most(30) }
How about that:
validates_length_of :foo, is: 3, allow_blank: true
Add in your model:
validates :color, length: { is: 7 }
color is a string:
t.string :color, null: false, default: '#0093FF', limit: 7
In your model e.g.
def validate
errors.add_to_base 'error message' unless self.foo.length == 5 or self.foo.blanc?
end