Validates Uniqueness getting called when field hasn't changed? - ruby-on-rails

Does validates :uniqueness get called every time an object is saved even if a field has not changed? Isn't this a performance issue?
validates :name, :schedule_id, :uniqueness => true
It seems to be the case that it does. So isn't it almost always necessary to make sure a change has taken place before running the validation? As every field being checked for uniqueness requires a database hit.
This would be better:
validates :name, :schedule_id, :uniqueness => true, :if => "name_changed? || schedule_id_changed?"
And this much better, if a bit more verbose:
validates :name, :uniqueness => true, :if => :name_changed?
validates :schedule_id, :uniqueness => true, :if => schedule_id_changed?
Gist here: https://gist.github.com/4017019

try this
validates :name, :uniqueness => true, :if => lambda {self.name_changed? }

Related

Ruby on rails Update

I have User model, it has some validations and they work on create. But when i call any user from database as #user=User.find(1) #user.valid? it returns false. Could you help me?
class User < ActiveRecord::Base
validates :name, :surname, :username, :phone, :role, :gender, :presence => true
validates :password_confirmation, :email_confirmation, :presence => true
validates :username, :email, :uniqueness => true
validates :verified, :bulletin, :inclusion => { :in => [true, false] }
validates :password,:email, :confirmation => true
....
end
I guess you need to add on: :create param for each validations that only need to be run on create.
For example when you're doing #user.valid? I gess you don't want to check if password_confirmation is present.
So in this case it should be:
validates :password_confirmation, :email_confirmation, :presence => true, :on => :create
Hope it helps :)
There is a special validation for this use case, that the user should provide a confirmation, but the confirmation is not stored in the database
validates :email, confirmation: true, :uniqueness => true
validates :password, confirmation: true, ....
This substitutes the validation for :password_confirmation and :email_confirmation, so you need also to remove them.
See the fine rails guides http://guides.rubyonrails.org/active_record_validations.html#confirmation

Rails 3 validate presence of many columns with custom messages

Is there a way to specify many validations like this more concisely?
validates :col_a, :presence => {:message => 'col_a cannot be blank'}
validates :col_b, :presence => {:message => 'col_b cannot be blank'}
validates :col_c, :presence => {:message => 'col_c cannot be blank'}
I'd settle for a generic message if I had to.
You can give multiple field names to a validator
validates :col_a, :col_b, :col_c, :presence => true
You can specify multiple validators in the same line.
validates :col_a, :col_b, :col_c, :presence => true, :numericality => true
The full error message will contain the field name. You don't need to add the field name prefix. If you want to use a custom message then:
validates :col_a, :col_b, :col_c, :presence => {:message => "empty value found"}
You can use
validates :col_a, presence: true
validates :col_b, presence: true
validates :col_c, presence: true
Use the validates_presence_of helper.
validates_presence_of :col_a
EDIT
You could clean it up a bit with validates_each. There is an example on the api page. http://api.rubyonrails.org/classes/ActiveModel/Validations.html
Hope that helps

Rails 3 Validation :presence => false

Here's what I expected to be a perfectly straightforward question, but I can't find a definitive answer in the Guides or elsewhere.
I have two attributes on an ActiveRecord. I want exactly one to be present and the other to be nil or a blank string.
How do I do the equivalent of :presence => false? I want to make sure the value is nil.
validates :first_attribute, :presence => true, :if => "second_attribute.blank?"
validates :second_attribute, :presence => true, :if => "first_attribute.blank?"
# The two lines below fail because 'false' is an invalid option
validates :first_attribute, :presence => false, :if => "!second_attribute.blank?"
validates :second_attribute, :presence => false, :if => "!first_attribute.blank?"
Or perhaps there's a more elegant way to do this...
I'm running Rails 3.0.9
For allowing an object to be valid if and only if a specific attribute is nil, you can use "inclusion" rather than creating your own method.
validates :name, inclusion: { in: [nil] }
This is for Rails 3. The Rails 4 solution is much more elegant:
validates :name, absence: true
class NoPresenceValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
record.errors[attribute] << (options[:message] || 'must be blank') unless record.send(attribute).blank?
end
end
validates :first_attribute, :presence => true, :if => "second_attribute.blank?"
validates :second_attribute, :presence => true, :if => "first_attribute.blank?"
validates :first_attribute, :no_presence => true, :if => "!second_attribute.blank?"
validates :second_attribute, :no_presence => true, :if => "!first_attribute.blank?"
use custom validation.
validate :validate_method
# validate if which one required other should be blank
def validate_method
errors.add(:field, :blank) if condition
end
It looks like :length => { :is => 0 } works for what I need.
validates :first_attribute, :length => {:is => 0 }, :unless => "second_attribute.blank?"
Try:
validates :first_attribute, :presence => {:if => second_attribute.blank?}
validates :second_attribute, :presence => {:if => (first_attribute.blank? && second_attribute.blank? )}
Hope that help .

Certain validations only in Rails.env.production?

I would like to only allow certain validations within production vs other environments for an app.
For example, I have tried to add:
if Rails.env.production?
validates :email, :uniqueness => true
validates :phone, :uniqueness => true
end
However this will not work. How can one add validations only to specific environment modes?
Try this -
validates :email, :uniqueness => true, :if => lambda{ Rails.env.production?}
validates :phone, :uniqueness => true, :if => lambda{ Rails.env.production?}
Totally agree with the comments, but if you really want to do this, try the :if option
validates_uniqueness_of :email, :if => Rails.env.production?

Are these model validations overkill if schema is already restrictive?

I have a restrictive schema (i.e. the schema already has null restrictions and maximum length etc). Would putting all of them in the model also overkill and counterproductive?...
validates :CouponID, :presence => true,
:numericality => true
validates :MerchantName, :presence => true,
:length => { :maximum => 100 }
validates :MerchantID, :presence => true,
:numericality => true
validates :Network, :length => { :maximum => 20 }
validates :Label, :presence => true
validates :CouponCode, :length => { :maximum => 100 }
validates :EndDate, :presence => true
validates :Link, :presence => true
validates :Status, :presence => true,
:length => { :maximum => 45 }
validates :Country, :length => { :maximum => 100 }
No it's not an overkill. Putting these into validators your model would allow Rails to catch them before inserting them into the database. It's also good design and practice.
If you omitted these, you would get MySQL errors thrown instead.
For example. Let's say I have a Comment model which contains an attribute string called body which can not be nil in my table.
class Comment < ActiveRecord::Base
end
If I tried:
comment = Comment.create(body: nil)
I would get the following exception.
ActiveRecord::StatementInvalid: Mysql2::Error: Column 'body' cannot be null:
This is bad. The natural flow of your application would break.
But, if I put the validators in my model like so
class Comment < ActiveRecord::Base
validates :body, presence: true
end
and tried the following:
comment = Comment.create(body: nil)
I would not get an exception thrown but the errors array for my variable to tell me what went wrong.
comment.errors.full_messages
=> ["Body can't be blank"]
It's good practice to put validators in your models and allows for good design.

Resources