How to test a validation with conditional? - ruby-on-rails

How should I test a validation with a conditional like this:
validates :age, :numericality => true, :if => :age?
This is what I have for now:
before(:each) do
#attr = { :age => "30" }
end
it "should require a age if present" do
Model.new(#attr.merge(:age => "foo").should_not be_valid
end
And the error message is:
expected valid? to return false, got true
But doing this, the ifis not evaluated.

Have you tried :allow_nil => true instead of the :if condition?

Have you actually written a method called "age?" ?
I think what you're trying to do is actually covered by:
validates :age, :numericality => true, :allow_nil => true

Related

validates_presence_of if condition on rails 3.2 and mongoid + simple_form

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.......

Rails validation if a conditon is met

I have this validation
validates :contact_id, :presence => true, :uniqueness => {:message => 'has an account already.'}
in the application.rb model
All is good but I need to only do this validation if the state is "invalid"
For example in the applications table there is a field called state and if there is a application with a contact_id of a user and the state is "invalid" then this validation should not take effect and should let the user save the application
I believe this should do it:
validates :contact_id,
:presence => true,
:uniqueness => {:message => 'has an account already.'},
:if => :invalid?
def invalid?
state == 'invalid'
end
you could also inline that to:
validates :contact_id,
:presence => true,
:uniqueness => {:message => 'has an account already.'},
:if => lambda{ state == 'invalid' }
Hope this helps.
If you are going to do it when the state is not invalid, then you could do that two ways:
validates :contact_id,
:presence => true,
:uniqueness => {:message => 'has an account already.'},
:unless => :invalid?
Or you could change it a bit more and have a valid message, which I might prefer:
validates :contact_id,
:presence => true,
:uniqueness => {:message => 'has an account already.'},
:if => :valid?
def valid?
state != 'invalid'
end
Did you try seeing this railscasts video ? http://railscasts.com/episodes/41-conditional-validations
validates :contact_id, :if => :should_validate_contactid?
def should_validate_contactid?
Check condition
end

Rspec validation failed - attribute can't be blank but it isn't blank

I just wrote a test for testing if a new user creation also consists of an admin setting. Here is the test:
describe User do
before(:each) do
#attr = {
:name => "Example User",
:email => "user#example.com",
:admin => "f"
}
end
it "should create a new instance given valid attributes" do
User.create!(#attr)
end
it "should require a name" do
no_name_user = User.new(#attr.merge(:name => ""))
no_name_user.should_not be_valid
end
it "should require an email" do
no_email_user = User.new(#attr.merge(:email => ""))
no_email_user.should_not be_valid
end
it "should require an admin setting" do
no_admin_user = User.new(#attr.merge(:admin => ""))
no_admin_user.should_not be_valid
end
end
Then, in my User model I have:
class User < ActiveRecord::Base
attr_accessible :name, :email, :admin
has_many :ownerships
has_many :projects, :through => :ownerships
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :name, :presence => true,
:length => { :maximum => 50 }
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => { :case_sensitive => false }
validates :admin, :presence => true
end
I clearly created a new user with an admin setting, so why is it saying it's false? I created the migration for the admin setting as admin:boolean. Did I do something wrong?
Here's the error:
Failures:
1) User should create a new instance given valid attributes
Failure/Error: User.create!(#attr)
ActiveRecord::RecordInvalid:
Validation failed: Admin can't be blank
# ./spec/models/user_spec.rb:14:in `block (2 levels) in <top (required)>'
Oddly enough, when I comment out validates :admin, :presence => true, the test creates the user correctly but fails on "User should require an admin setting"
EDIT: When I change the #attr :admin value to "t" it works! Why doesn't it work when the value is false?
From the rails guides:
Since false.blank? is true, if you want to validate the presence of a
boolean field you should use validates :field_name, :inclusion => {
:in => [true, false] }.
Basically, it looks like ActiveRecord is converting your "f" to false before the validation, and then it runs false.blank? and returns true (meaning that the field is NOT present), causing the validation to fail. So, to fix it in your case, change your validation:
validates :admin, :inclusion => { :in => [true, false] }
Seems a little hacky to me... hopefully the Rails developers will reconsider this in a future release.

rails password update validation issue

I have the following validation:
validates :password, :presence => true, :confirmation => true, :length => { :within => 6..40 }, :format => { :with => pass_regex }, :unless => :nopass?
Then, when I try to update without password (nopass? is true) the following errors appear:
There were problems with the following fields:
Password is too short (minimum is 6 characters)
Password is invalid
Notice that the :unless works on :presence and :confirmation but not in :lenght or :format.
How could I fix this?
I've had some strange issues with the :confirmation flag as well, which I never figured out, but that's how I solved the problem in my Rails 3.0.x app:
attr_accessor :password_confirmation
validates :password, :presence => true, :length => {:within => PASSWORD_MIN_LENGTH..PASSWORD_MAX_LENGTH}
validate :password_is_confirmed
def password_is_confirmed
if password_changed? # don't trigger that validation every time we save/update attributes
errors.add(:password_confirmation, "can't be blank") if password_confirmation.blank?
errors.add(:password_confirmation, "doesn't match first password") if password != password_confirmation
end
end
I realise this is not an explanation why your code isn't working, but if you're looking for a quick temporary fix - I hope this will help.
You might use conditional validations
class Person < ActiveRecord::Base
validates :surname, :presence => true, :if => "name.nil?"
end

Undefined method password_changed? Error

I'm trying to set my program so that the password only is validated if it is changed (so a user can edit other information without having to put in their password).
I am currently getting an error that says
NoMethodError in UsersController#create, undefined method `password_changed?' for #<User:0x00000100d1d7a0>
when I try to log in.
Here is my validation code in user.rb:
validates :name, :presence => true,
:length => { :maximum => 50 }
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => { :case_sensitive => false }
validates :password, :presence =>true, :confirmation => true, :length => { :within => 6..40 }, :if=>:password_changed?
Here is my create method in users_controller.rb:
def create
#user = User.new(params[:user])
if #user.save
sign_in #user
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
#title = "Sign up"
render 'new'
end
end
Thank you!
Replace with:
:if => lambda {|user| user.password_changed? }
I'd do two different validations:
validates :password, :presence =>true, :confirmation => true, :length => { :within => 6..40 }, :on => :create
validates :password, :confirmation => true, :length => { :within => 6..40 }, :on => :update, :unless => lambda{ |user| user.password.blank? }
I encountered this same problem and after reading this post I implemented the code suggested by apneadiving in his answer but with a slight modification:
I used two different validations, one for create:
validates :password, :presence => true, :confirmation => true, :length => { :within => 6..128 }, :on => :create
and then I used this one for update:
validates :password, :presence => true, :confirmation => true, :length => { :within => 6..128 }, :on => :update, :unless => lambda{ |user| user.password.to_s.empty? }
Originally, I Implemented exactly what apneadiving suggested, but I realized that on updates to the user it wasn't actually validating the presence of a string. As in, it was allowing a user to set their password to " " (A string of whitespace). This is due to the fact that " ".blank? == true, and so if you have it set to validate like this:
:unless => lambda { |user| user.password.blank? }
Then it won't run the validation if a string full of whitespace is submitted by the user is submitted because it reads the string as being blank. This essentially invalidates the effect of validating for presence on the update. The reason I did password.to_s.empty? instead of simply password.empty? is to prevent errors if someone calls update_attributes on the user model and doesn't pass in anything into the password, field, then the password will be nil, and since the ruby nil class doesn't have an empty? method, it will throw an error. Calling .to_s on nil, however will convert it to an empty string, which will return true on a successive .empty? call (thus the validation won't run). So after some trials and tribulation I found that this was the best way to do it.
Ended up here googling this error message, and using
#account.encrypted_password_changed?
in my case yielded what I wanted.
The change to look for, in Rails 4 at least, is password_digest.
#account.password = "my new password"
#account.changes # => {"password_digest"=>["$2a$10$nR./uTAmcO0CmUSd5xOP2OMf8n7/vXuMD6EAgvCIsnoJDMpOzYzsa", "$2a$10$pVM18wPMzkyH5zQBvcf6ruJry22Yn8w7BrJ4U78o08eU/GMIqQUBW"]}
#account.password_digest_changed? # => true

Resources