ActiveRecord validation for nil - ruby-on-rails

I am trying to write an active record validation that allows any string but does not allow nil.
The problem with validates_presences_of is that it returns false for "" or " " which I want to consider valid.
I have also tried to do validates_length_of :foo, :minimum => 0 which did not work
I have also tried t o do validates_length_of :foo, :minimum => 0, :unless => :nil? which also did not work. Both of these allowed for nil values to be set and the validation still returns true.
Am i missing something here? I feel like it shouldnt be this hard to simply validate that the element is not nil.

validate :blank_but_not_nil
def blank_but_not_nil
if self.foo.nil?
errors.add :foo, 'cannot be nil'
end
end

Can you try:
validates_length_of :foo, :minimum => 0, :allow_nil => false
For example:
User < ActiveRecord::Base
validates_length_of :name, :minimum => 0, :allow_nil => false
end
> u=User.new
> u.valid? #=> false #u.name is nil
> u.name=""
> u.valid? #=> true

Related

Validation not working on Ranges?

Can someone explain to me why my validation won't get triggered when I submit a string such as "foo" to number?
class Course < ActiveRecord::Base
validates :number, :inclusion => 0..100
end
Only when I change my code to this...
class Course < ActiveRecord::Base
validates :number, :inclusion => 0..100, :numericality => true
end
... the validation gets triggered.
Is this a Rails bug or am I missing something really fundamental here?
I am using Rails 4.2.0 by the way.
It's because rails is converting the string to a number (assuming you've got it persisted as an integer) before doing the validation. If you call to_i on a string you get 0 which is valid for your range.
For example:
> c = Course.new
> c.number = 'hi'
> c.number
=> 0
> c.valid?
=> true
The reason the numericality validators is triggering when you add it is, I think, because it checks the value before any type casting happens:
> c.number = 'hi'
> c.number_before_type_cast
=> 'hi'
Please try this:
validates_numericality_of :number, :only_integer => true,
:greater_than_or_equal_to => 1,
:less_than_or_equal_to => 99,
:message => "can only be number between 1 and 100."
ref: http://apidock.com/rails/ActiveModel/Validations/ClassMethods/validates_numericality_of
This turned out to work best for me:
class Course < ActiveRecord::Base
validates :number, :numericality => { :greater_than_or_equal_to => 0, :less_than_or_equal_to => 100 }
end

How to validate numericality and inclusion while still allowing attribute to be nil in some cases?

In a Rails app I have several integer attributes on a model.
A user should be able to create a record and leave these attributes blank.
Or, if the user enters values for these attributes, they should be validated for numericality and within a certain range.
In the model I have something like this
validates_presence_of :name
validates_numericality_of :a, :only_integer => true, :message => "can only be whole number."
validates_inclusion_of :a, :in => 1..999, :message => "can only be between 1 and 999."
If I now test with the minimum required attributes to save:
factory :model do
sequence(:name) { |n| "model#{n}" }
end
it "should save with minium attributes" do
#model = FactoryGirl.build(:model)
#model.save.should == false
end
I get
Validation failed: a can only be whole number., a can only be between 1 and 999.
How can I validate numericality and inclusion only if a value is given for :a, while still allowing :a to be nil in some cases?
Thanks
You can add an :allow_nil => true to your validates_numericality_of.
validates_numericality_of :a, :only_integer => true, :allow_nil => true,
:message => "can only be whole number."
You can also use greater_than_or_equal_to and less_than_or_equal_to options if you just want to use one validation:
validates_numericality_of :a, :only_integer => true, :allow_nil => true,
:greater_than_or_equal_to => 1,
:less_than_or_equal_to => 999,
:message => "can only be whole number between 1 and 999."
should be simply:
validates_numericality_of :a, :only_integer => true, :message => "can only be whole number.", :allow_nil => true
same for the second validation

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

How to test a validation with conditional?

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

How to update attributes without validation

I've got a model with its validations, and I found out that I can't update an attribute without validating the object before.
I already tried to add on => :create syntax at the end of each validation line, but I got the same results.
My announcement model have the following validations:
validates_presence_of :title
validates_presence_of :description
validates_presence_of :announcement_type_id
validate :validates_publication_date
validate :validates_start_date
validate :validates_start_end_dates
validate :validates_category
validate :validates_province
validates_length_of :title, :in => 6..255, :on => :save
validates_length_of :subtitle, :in => 0..255, :on => :save
validates_length_of :subtitle, :in => 0..255, :on => :save
validates_length_of :place, :in => 0..50, :on => :save
validates_numericality_of :vacants, :greater_than_or_equal_to => 0, :only_integer => true
validates_numericality_of :price, :greater_than_or_equal_to => 0, :only_integer => true
My rake task does the following:
task :announcements_expiration => :environment do
announcements = Announcement.expired
announcements.each do |a|
#Gets the user that owns the announcement
user = User.find(a.user_id)
puts a.title + '...'
a.state = 'deactivated'
if a.update_attributes(:state => a.state)
puts 'state changed to deactivated'
else
a.errors.each do |e|
puts e
end
end
end
This throws all the validation exceptions for that model, in the output.
Does anybody how to update an attribute without validating the model?
You can do something like:
object.attribute = value
object.save(:validate => false)
USE update_attribute instead of update_attributes
Updates a single attribute and saves the record without going through the normal validation procedure.
if a.update_attribute('state', a.state)
Note:- 'update_attribute' update only one attribute at a time from the code given in question i think it will work for you.
try using
#record.assign_attributes({ ... })
#record.save(validate: false)
works for me
Yo can use:
a.update_column :state, a.state
Check: http://apidock.com/rails/ActiveRecord/Persistence/update_column
Updates a single attribute of an object, without calling save.
All the validation from model are skipped when we use validate: false
user = User.new(....)
user.save(validate: false)
Shouldn't that be
validates_length_of :title, :in => 6..255, :on => :create
so it only works during create?

Resources