I have in my model
class Account < ActiveRecord::Base
validates_length_of :amount, :in 1..255, :on => update, :if => Proc.new { |a| false if a.id == nil;a.amount.blank? }
validates_length_of :name, :in 1..255, :on => update, :if => Proc.new { |a| false if a.id == nil;a.name.blank? }, :unless => user_has_amount?
end
when I comment out the if condition, it works fine but with them validation fails which is confusing. I know that the validation should only run if the proc returns true or unless returns false
in my controller I have
#account.update_attributes({:name => "king", :amount => "1223"}
the save fails and when I check errors I get
#account.errors.details
{:name =>[{:error=>:too_short, :count=>1}], :amount =>[{:error=>:too_short, :count=>1}]}
Strong Params are not an issue because I have
def self.params
params.require(:account).permit!
end
I have no idea why it fails though the value are present and correct.
Try this the following:
class Account < ActiveRecord::Base
validates :amount, length: { in: 1..255 }, on: :update
validates :name, length: { in: 1..255 }, on: :update
end
Check your strong parameters. Your error tells you that something is wrong before you get to validation: :name =>[{:error=>:too_short, :count=>1}] This is saying that the minimum string count is 1 but that your string is not even that long. Here is the docs on that.
You can try: Account.find(1).update_attributes({:name => "king", :amount => "1223"} to see if #account is not being set properly.
You can also customize the language on your errors to help further:
validates_length_of : name, within: 1..255, too_long: 'pick a shorter name', too_short: 'pick a longer name'
The issue that was happening was for one reason. The code was inheriting from a class that had:
slef.reload
in one of the function that were being called during validations.
so every time we try to update the update failed because once that validation was hit it reloaded the original values from database and ignored new values which if old values are empty is just a head scratcher.
Thanks everyone for the help
Related
I have a field called visit_time with two distinct values. They are "AM" and "PM"
I check the presence of the visit_time by the following validation syntax.
validates_presence_of :visit_time,
message: "visit time is required"
Then I need to check the inclusion validation only if the visit_time is presence, for this I am using the Proc. But it is not working.
validates :visit_time,
:inclusion => { :in => [ 'AM', 'PM'],
:message => "%{value} is not a valid time" },
:if => Proc.new { |o| o.errors.empty? }
Let me know what's wrong on it. Is Proc is not working for inclusion ??? Thanks in advance.
If you want the inclusion validation to run only if it's present, you should change the Proc to this instead:
if: Proc.new { |o| o.visit_time.present? }
I have an Invitation model that represents an invitation to join a subscription. There should only be one Invitation at any given time with a specific email / subscription_id combination unless the other records with the matching email / subscription_id also have a state of 'declined'.
I can currently validate for uniqueness given that the email and subscription_id combination is unique:
My Invitation model:
validates :email, :uniqueness => { :scope => :subscription_id }
Rspec (passes):
it { should validate_uniqueness_of(:email).scoped_to(:subscription_id) }
However, I want to skip the uniqueness check if the matching model(s) in the database have a state that is equal to 'declined'.
If the existing model's state is 'declined', the validation should pass.
The first thing that comes to mind is:
validates :email, :uniqueness => { :scope => :subscription_id },
:unless => lambda { |asset| asset.state == 'declined' }
But this is wrong because it checks if the newly created model has a state of 'declined', I want to check if the previously existing records have a state of 'declined'.
I also tried this:
validates :email, :uniqueness => { :scope => :subscription_id, :message => 'subscriptionery do' },
:if => lambda { |asset| asset.state == 'declined' }
But that fails for what I assume is the same reason.
How would I write a validation that checks an additional scope?
I feel like writing something like the following, but this is just made up syntax to help explain my idea:
it { should validate_uniqueness_of(:email).scoped_to(:subscription_id) }
unless MyModel.where(:email == new_object.email,
:subscription_id == new_object.subscription_id,
:state == 'declined')
Update:
I did this and it worked:
validates :email, uniqueness: { scope: :subscription_id, message: 'The email address %{value} is already associated with this subscription.' }, if: :state_of_others_are_not_declined?, on: :create
def state_of_others_are_not_declined?
Invitation.where(email: email).where(subscription_id: subscription_id).where.not(state: 'declined').any?
end
How does this work for you;
validate :unique_email_with_subscription_and_state
def unique_email_with_subscription_and_state
errors.add(:email,"YOUR MESSAGE") if Invitation.where(email: self.email, subscription_id: self.subscription_id).where.not(state: 'declined').any?
end
This will select all Invitiations where the the email matches, subscription_id matches and the state is not declined. If it finds any it will add an error to :email. Something like this
"SELECT invitations.* FROM invitatations WHERE email = 'me#example.com' AND subscription_id = 2 AND state <> 'declined'"
Is that the desired result?
I am getting this error when when I try to validate. I am trying to validate whether if the string is not in the DB.
this is my model
class Location < Locations::Location
validate do
#strong URL check for url_prefix
errors.add(:url_prefix, "URL already taken") if self.url_prefix.valid? && is_on_web;
end
end
Instead use,
validates :url_prefix, :uniqueness => { :message => "URL already taken and is online" }
update:
conditional validation can be added to solve your second problem like this,
validates :url_prefix, :uniqueness => { :message => "URL already taken and is online" }, :if => :is_on_web?
I'm trying to set up my model in Rails 3.2.8 such that particular values must be present, but are allowed to be the empty string. Does anyone know how to do this?
The behavior I'm looking for looks like:
#foo.value = "this is a real value"
#foo.valid? # => true
#foo.value = nil
#foo.valid? # => false
#foo.value = ""
#foo.valid? # => true
If I use
validates :foo, :presence => true
then I get what I want for 1 and 2, but not 3. And, helpfully, :allow_blank => true is ignored when validating presence.
I also tried
validates :foo, :length => { :minimum => 0 }, :allow_nil => false
Same behavior: get what I want for 1 and 2, but not 3.
I suppose I could just mark the column as NOT NULL in the database, but then I have to deal with catching the exception; I'd really rather catch this at the validation stage.
Any ideas?
I would try something like this:
validates :foo, presence: true, unless: lambda { |f| f.foo === "" }
I've got a Trip model, which among other attributes has a start_odometer and end_odometer value.
In my model, i'd like to validate that the end odometer is larger than the starting odometer.
The end odometer can also be blank because the trip may not have finished yet.
However, I can't figure out how to compare one attribute to another.
In trip.rb:
comparing against the symbol:
validates_numericality_of :end_odometer, :greater_than => :start_odometer, :allow_blank => true
gives me the error:
ArgumentError in TripsController#index
:greater_than must be a number
comparing against the variable:
validates_numericality_of :end_odometer, :greater_than => start_odometer, :allow_blank => true
NameError in TripsController#index
undefined local variable or method `start_odometer' for #
You don't necessarily need a custom validation method for this case. In fact, it's a bit overkill when you can do it with one line. jn80842's suggestion is close, but you must wrap it in a Proc or Lambda for it to work.
validates_numericality_of :end_odometer, :greater_than => Proc.new { |r| r.start_odometer }, :allow_blank => true
You'll probably need to write a custom validation method in your model for this...
validate :odometer_value_order
def odometer_value_order
if self.end_odometer && (self.start_odometer > self.end_odometer)
self.errors.add_to_base("End odometer value must be greater than start odometer value.")
end
end
You can validate against a model attribute if you use a Proc.
In rails4 you would do something like this:
class Trip < ActiveRecord::Base
validates_numericality_of :start_odometer, less_than: ->(trip) { trip.end_odometer }
validates_numericality_of :end_odometer, greater_than: ->(trip) { trip.start_odometer }
end
It's a bit kludgy, but this seems to work:
validates_numericality_of :end_odometer, :greater_than => :start_odometer.to_i, :allow_blank => true