I am working with a form having 2 checkboxes: option_one and option_two.
I don't want to allow submission of the form if option_two is checked and option_one is not.
In other words if somebody checks option_two, they must check option_one as well.
So in my MyModel I wrote :
validates :option_one, :presence => true, :if => option_two_active?, :message => "Dummy message."
Then in the MyController, I added :
def option_two_active?
params[:option_two] == "1"
end
But it keeps giving me the following error :
NoMethodError in MyController#index
Is my approach correct ? How can I achieve this ? Thanks in advance.
You have to specify the conditional method with a symbol:
validates :option_one, :presence => true, :if => :option_two_active?, :message => "Dummy message."
Also, you since you can't use params from a model, you should assign that value to the model from the controller, either with create, update_attributes, or manually. If you want to persist the option_two field, then it should be a database column, else you can just create an attribute accessor:
attribute_accessor :option_two
The way you reference the method, it will be called directly as the class is first loaded. However, the :if parameter is expected to be used with either a proc which is then called during validation or with a symbol representing a method name. In your case, you should thus setup your validation like this:
validates :option_one, :presence => true, :if => :option_two?, :message => "Dummy message."
Notice the colon before the method name. Furthermor, the validation method needs to be defined on the model, not the controller. Fortunately, ActiveRecord already defines the proper methods for Boolean fields, as used here.
Related
I need to validate few attributes in my model only when they are present in params while updating or creating the object.
validates :attribute_a,format: {with: /some_regex/}, :if => lambda{ |object| object.attribute_a.present? }
Like attribute_a there are multiple attributes which may not be present while being created or updated.Instead of writing the validates statement for each of them,is there a way in which I can check the presence of multiple attributes and then validate every one with a common validation such as inclusion_inor format:{with:/some_regex/ }.
I wanted something like the following code which obviously is wrong.
validates :attribute_a,attribute_b,attribute_c,attribute_d,:format => {:with =>
/some_regex/}, :if => lambda{ |object| object.attribute_name.present? }
You can use validates_format_of:
validates_format_of :attr_a, :attr_b,
with: /someregexp/,
allow_blank: true
The allow blank option means that the regexp doesn't have to match if the attribute is not present.
I have this class:
class Project < ActiveRecord::Base
validates :hourly_rate, :numericality => { :greater_than_or_equal_to => 0 },
:allow_blank => true
def hourly_rate=(number)
self.hourly_rate_in_cents = number.present? ? number.to_d * 100 : nil
end
end
Essentially, any new hourly_rate that gets entered by the user will get saved to the database as an integer.
This works quite well for numbers.
But any string that is being entered, is automatically converted into 0.0 and gets saved without any validation message!
Isn't there a way to validate this using any of Rails' validation methods?
Thanks for any help.
You can create your own validate method and use that to check for the type of object.
For example (and forgive me if there's an error in this code, since it's just off the top of my head):
validate :hourly_rate_is_integer
def hourly_rate_is_integer
errors.add(:hourly_rate, "must be Integer") unless self.hourly_rate.is_a?(Integer)
end
If you have a reader method for this that converts the other way, it will work as you expect. You've only shown the assignment method here.
def hourly_rate
self.hourly_rate_in_cents and self.hourly_rate_in_cents.to_f / 100
end
All the validation routines do is call the given method and apply tests to the result.
You might want to ensure that presence is specifically tested:
validates :hourly_rate, :presence => true, ...
Having newbie trouble getting this working. I have Stores that don't have addresses (just a website) as well so the gem (Google-Maps-for-Rails) when seeding actually doesn't create them at all but only the ones with an address.
Store.rb
validates :address,
:presence => {:unless => :website,
:message => "You must enter an address, website, or both."}
acts_as_gmappable :check_process => :prevent_geocoding,
:address => "address",
:normalized_address => "address",
:msg => "Sorry, unable to find address."
# How do I correct this block?
def prevent_geocoding
unless website.present?
address.blank? || (!latitude.blank? && !longitude.blank?)
end
end
I still want to use everything here but what's the correct way to pass this block?
Thank you.
You're on the right track. You can bypass validations by passing a method into if or unless as options on the validation. In the above code, you're passing it as an option to the presence validator and not to the validation itself. Move the unless out of the hash and pass it the name of a method or a Proc — really anything that returns true or false. Here's an example:
validates :address,
:presence => { :message => "You must enter an address, website, or both." },
:unless => Proc.new { |store| store.address.nil? && store.website.present? }
That validation will run every time except in cases where the store both doesn't have an address and does have a website. If you need more complex logic, I recommend moving that out of a Proc and into a method.
I've got a User model with three fields, :email, :display_name and :handle. Handle is created behind the scenes from the :display_name.
I'm using the following validations:
validates :display_name, :presence => :true, :uniqueness => { :message => "Sorry, another user has already chosen that name."}, :on => :update
validates :email, :presence => :true, :uniqueness => { :message => "An account with that email already exists." }
I use the handle as the to_param in the model. If the user fails the validation by submitting a :display_name that already exists, then tries to change it and resubmit the form, Rails seems to use the new handle as the validation for the email -- in other words, it assumes that the email doesn't belong to the current user and validation on the email then fails. At this point, Rails assumes that the changed display name/handle is the one to use for the look up and the update action can't complete at all, because it can't find the user based on the new handle.
Here's the update method:
def update
#user = User.find_by_handle(params[:id])
#handle = params[:user][:display_name]
#user.handle = #handle.parameterize
...
end
This problem doesn't happen when the validation first fails on a duplicate email, so I'm assuming it's something about the way I've written the update method -- maybe I should try setting the handle in the model?
maybe I should try setting the handle in the model?
^ This.
The controller isn't the place to do something like this. If it's model logic that's happening behind the scenes, beyond the user's control, why put it in controller code?
Do it instead in a before_save filter, which is guaranteed to run only after the chosen display name is determined to be available and the record is deemed valid. In this way the handle won't be changed on the cached record until it is actually committed to the db, eliminating the problem of the incorrectly generated URL.
before_save :generate_handle
...
def generate_handle
self.handle = display_name.parameterize
end
I have a model with 2 validations on the 'name' attribute. It goes something like this:
validates :name, :uniqueness => true
validate do
errors.add(:name, "is dumb") if name_is_dumb?
end
I don't want the 2nd validation to run if the first validation fails (the name is not unique).
What's the best and cleanest way to do this?
According to the documentation:
Callbacks are generally run in the
order they are defined, with the
exception of callbacks defined as
methods on the model, which are called
last.
So the following snippet should work:
validates :name, :uniqueness => true
validate do
errors.add(:name, "is dumb") unless errors[:name].nil?
end