rails 3 + shoulda + validations based on callbacks - ruby-on-rails-3

i am new to shoulda. many of my models have validations as below
validates :sampling_method, :presence => true, :if => :type_of_resource
validate :check_for_decimal_places, :if => :is_size_and_gdnt, :on => :update
here, type_of_resource and is_size_and_gdnt are instance methods for model
my shoulda validation for first is as
it { should validate_presence_of(:sampling_method) }
but i dont know how to add check for if
i have checked the second validation using by creating a object using factory girl, and checking its values when the object is saved but how do i test the second validation using shoulda

Related

Making select box a required field in some situations

I have a form which has a select box with categories. If a particular category is selected, another select box/dropdown is displayed to the user. I need this second dropdown to be a required field when this category is selected.
I cannot add validates :course, :presence => {:message => 'Course cannot be blank.'} to the model because this field is not always required, I need some other way to make it required only when certain category is selected in the first dropbox.
Thanks for your help
You could try using the if argument to validates, like this:
validates :course, :presence => {:message => "Course cannot be blink."}, :if => Proc.new { |u| u.first_dropdown_value == 'value_that_you_validate_courses_for' }
For more information, check out the Rails documentation on conditional validation.

Rails validators discrepancy between presence and format

I have a model that takes an email address, but I do not want to require it for instance creation. I tried the following:
validates :email, :presence => false, :format => { :with => email_regex }
But this fails my test suite, the format regex apparently makes the presence of the email attribute required.
I thought it might be possible with a before_save method: is it possible to reject saving the object in a before_save method? Is there a better, "Rails way" of doing this?
You can use :allow_blank (or :allow_nil):
validates :email, :allow_blank => true, :format => { :with => email_regex }

Why is user.save true but email shows as nil?

I'm using a nested model form for sign-up and am working through the kinks as a beginner. One issue that popped up in particular though that I don't really get is user.email is returning as nil.
Before I started playing around with the nested model form, I could create records in the console wihtout a problem. Now, however I can't create records and some of the latest records created have nil as their email. (I'm not sure if it has anything to do with the nested model at all, but that's my reference point for when it started going haywire.)
If I go into rails console to create a new User/Profile, I follow this process:
user = User.new
user.email = ""
user.password = ""
user.profile = Profile.new
user.profile.first_name = ""
...
user.profile.save
user.save
Everything goes well until user.save, which gives me the NameError: undefined local variable or method 'params' for #<User:>. In rails console it pinpoints to user.rb:25 in create_profile
So here is my User model:
class User < ActiveRecord::Base
attr_accessor :password, :email
has_one :profile, :dependent => :destroy
accepts_nested_attributes_for :profile
validates :email, :uniqueness => true,
:length => { :within => 5..50 },
:format => { :with => /^[^#][\w.-]+#[\w.-]+[.][a-z]{2,4}$/i }
validates :password, :confirmation => true,
:length => { :within 4..20 },
:presence => true,
:if => :password_required?
before_save :encrypt_new_password
after_save :create_profile
def self.authenticate(email, password)
user = find_by_email(email)
return user if user && user.authenticated?(password)
end
def authenticated?(password)
self.hashed_password == encrypt(password
end
protected
def encrypt_new_password
return if password.blank?
self.hashed_password = encrypt(password)
end
def password_required?
hashed_password.blank? || password.present?
end
def encrypt(string)
Digest::SHA1.hexdigest(string)
end
end
Can anyone help me figure out what's going on?
UPDATE: I tried changing my regex but I'm still seeing nil for email. Though a prior SO post said not to blindly copy regex without testing, so maybe I just didn't test it correctly. Good news though: I no longer get the error.
attr_accessor simply defines a "property" on the object and has no relation to the attributes of a ActiveRecord model (attributes is a Hash of the fields and values obtained from a table).
ActiveRecord does not save such "properties" as defined by the attr_accessor. (Essentially, attr_accessor defines a attr_reader and attr_writer (i.e. "getter" and "setter") at the same time)

Validation on missing attributes on update_attributes

The question is very simple, does update_attributes validates every possible validation of the model, even if I don't want to update some of the attributes?
I have a edit view, where the user might change his password, but only if he passes it, i.e., if it's blank the password would not change.
So I do the following in the controller:
def update
params[resource_name].delete(:password) if params[resource_name][:password].blank?
params[resource_name].delete(:password_confirmation) if params[resource_name][:password_confirmation].blank?
params[resource_name].delete(:current_password) if params[resource_name][:current_password].blank?
if resource.update_attributes(params[resource_name])
...
end
end
I defined the following validation on the model:
validates :password,
:length => { :within => 6..40 }
So whenever i use call the update I get an error saying that the password is too short
Ps.: I'm using Devise to deal it this.
EDIT: Do any of you know if Devise already have any validation on the password? Cause, I removed the validation and it worked in the right way, but if I put a short password it still show a validation, saying it's too short.
Yes, Devise does provide validations on password if you've passed :validatable to the devise method in your model. The default configuration for password length is 6..128. You can override this in config/initializers/devise.rb (around line 101).
You can remove :validatable from your model and write your own validations if you prefer. If you do this and don't want the validation to run if the password isn't passed to update_attributes, then do something like this:
validates :password, :presence => true, :if => lambda { new_record? || !password.nil? }

Rails 3 validates rule based on action

This seems like a simple question but I can't seem to find an answer short of writing custom validators. I have this validator
validates :password, :presence => true, :confirmation => true, :length => { :minimum => 5}
there are more rules applied such as some regex for complexity, but this gives the gist.
The issue is that I only want presence applied on create, everything else needs to be on create and update. Because the user may not be changing a password when updating their information.
I tried splitting the rules
validates :password, :presence => true, :on => :create
validates :password, # The rest of the rules
This resulted in all rules being ignored for update. Is there a simple way to apply only one rule to create and the rest to everything?
You can try keeping it in one line, but applying :on => :create to just the :presence check:
validates :password, :presence => {:on => :create}, :confirmation => true, :length => { :minimum => 5}
However, I'm not sure it makes sense to always require a minimum length, but not always require presence -- if you update an existing record with a blank password, it's going to fail validations anyway since the length is 0.
My hunch is that the problem is that the validate :password call is not additive. Can you switch the presence check to:
validates_presence_of :password, :on=>:create
And then keep your other validations using the validate. Does that work?