I am using this block of code for validating email address. The format of entered email address validates well, but the problem is with the "uniqueness" part - I currently can enter more identic email addresses to the database - how is that possible?
Has something changed in Rails 4 about validations?
class BetaAccess < ActiveRecord::Base
validates_format_of :email,:with => Devise::email_regexp, uniqueness: true
end
Thank you.
Try this:
class BetaAccess < ActiveRecord::Base
validates :email,format: {with: Devise::email_regexp}, uniqueness: true
end
format and uniqueness are different validators, if you want to use in one line, you should use validates method.
validates :email, :format => { :with => Devise::email_regexp }, :uniqueness => true
validates_format_of :email,:with => Devise::email_regexp, uniqueness: true
combines uniqueness into the validation for format. Use the validates syntax
validates :email,format: {with: Devise::email_regexp},
uniqueness: true
Also, use the new ruby syntax for hashes. Kind of neat that way
Related
We can validate email by doing:
validates :email, format: { with: VALID_EMAIL_REGEX }
or
validates_format_of :email, :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
What is the difference between the 2 approaches. Is one approach better than the other?
There is no difference between those two forms. The first is just a convenient shortcut for being able to specify multiple validations on a single attribute. For example, let's say you wanted to ensure that an email is valid but also unique. Using the second form in your example, this would be written
validates_uniqueness_of :email
validates_format_of :email, with: VALID_EMAIL_REGEX
Or, it could be written more succinctly using validates
validates :email, uniqueness: true, format: { with: VALID_EMAIL_REGEX }
What's also nice about using validates is that you can mix default validations with your own custom validations with a single call to validates. More information here.
There is an AcviteRecord Model named User like this:
class User < ActiveRecord::Base
validates :name, :presence => true
validates :email, :presence => true, :uniqueness => true
validates :plain_password, :presence => true, :confirmation => true
validates :plain_password_confirmation, :presence => true
#...other codes
end
It requires that the update of name and email and the update of password are separated.
When only update name and password, using update or update_attributes will cause password validation which is not needed. But using update_attribute will save name and email without validation.
Are there any ways to update particular fields of model with validation without causing the other fields' validation?
Give it a try, might help
class User < ActiveRecord::Base
validates :name, presence: true
validates :email, presence: true, :uniqueness => true
validates :plain_password, length: { in: 4..255, allow_nil: true }, confirmation: true
validates :plain_password_confirmation, presence: true, if: -> (user){ user.plain_password.present? }
# ......
# ......
end
Apart from this you should reconsider about saving plain_password ;)
You can adjust your validations to only run on create. Requiring confirmation ensures changes on edit are applied.
validates :plain_password,
confirmation: true,
presence: {
on: :create },
length: {
minimum: 8,
allow_blank: true }
validates :plain_password_confirmation,
presence: {
on: :create }
I am assuming you are hashing your passwords, so this would accompany code similar to:
attr_accessor :plain_password
before_save :prepare_password
def encrypted_password( bcrypt_computational_cost = Rails.env.test? ? 1 : 10)
BCrypt::Password.create plain_password, cost: bcrypt_computational_cost
end
private #===========================================================================================================
# Sets this users password hash to the encrypted password, if the password is not blank.
def prepare_password
self.password_hash = encrypted_password if plain_password.present?
end
A better way to handle this is to not include the fields in the rest of the edit form, but rather provide a link to "Change my password". This link would direct to a new form (perhaps in a modal window) which will require the new password, confirmation of the new password, and the old password, to prevent account hijacking.
In your case you can use has_secure_password The password presence is only validated on creation.
I have now this validate for my User model:
validates :email,
presence: true,
uniqueness: { :case_sensitive => false }
I'd like to add :on create for the uniqueness as users are definitely allowed to update their email by putting the same email!
Should I write it this way? I'm afraid the on:create also applies to the presence:true but it should only apply to the uniqueness validation:
validates :email,
presence: true,
uniqueness: { :case_sensitive => false }, on: :create
I would like to say some logic. Email should be unique and user will be identified by his email. So while update, there is no need to put email field where user can edit the email value. You can make the email field as readonly, so that user can not change it while updating the profile.
And yes, the syntax on: :create is the nice solution for it.
yes it will applied on both you can use separate validation for that
validates :email, presence: true
validates :email, uniqueness: { :case_sensitive => false }, on: :create
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.......
I have a form with a mobile/cell number and a home phone number.
I want to have only validate presence of mobile/cell number if the phone number has been left blank or vice versa.
My current validations for these fields are as follows.
validates_presence_of :mobile_number
validates_presence_of :home_phone
validates_length_of :home_phone, :minimum => 12, :maximum => 12
validates_length_of :mobile_number, :minimum => 10, :maximum => 10, :allow_blank => true
validates_format_of :home_phone, :with => /\A[0-9]{2}\s[0-9]{4}\s[0-9]{4}/, :message => "format should be 02 9999 9999"
I thought I could have something like the following but not sure how to do this exactly.
validates_presence_of :mobile_number, :unless => :home_phone.blank?
I'm using Rails 3.
You don't need a lambda. This will do:
validates_presence_of :mobile_number, :unless => :home_phone?
Also, all of the validators take the same if/unless options, so you can make them conditional at will.
Update: Looking back at this answer a few days later, I see that I should explain why it works:
If you set a validator's :unless option to be a symbol, Rails will look for an instance method of that name, invoke that method on the instance that's being validated -- at validation time -- and only perform the validation if the method returns false.
ActiveRecord automatically creates question mark methods for each of your model's attributes, so the existence of a home_phone column in your model's table causes Rails to create a handy #home_phone? method. This method returns true if and only if home_phone is present (i.e. not blank). If the home_phone attribute is nil or an empty string or a bunch of white space, home_phone? will return false.
UPDATE: Confirmed that this old technique continues to work in Rails 5.
You must use a lambda / Proc object:
validates_presence_of :mobile_number, :unless => lambda { self.home_phone.blank? }
Starting in Rails 4, you can pass a block to presence. Concisely:
validates :mobile_number, presence: {unless: :home_phone?}
Also, :home_phone? returns false for nil or blank.
Here is another way that works in rails 4
validates_presence_of :job, if: :executed_at?
validates :code,
presence: true,
length: { minimum: 10, maximum: 50 },
uniqueness: { case_sensitive: false },
numericality: { only_integer: true }
a short solution:
validates_presence_of :mobile_number, unless: -> { home_phone.blank? }
In newer versions of Rails, instead of relying on old validates_presence_of, you should use validates and list validations for each attribute:
validates :mobile_number, presence: { if: -> { home_phone.present? } }
Tested in Rails 7, this works flawlessly:
validates :mobile_number, presence: { unless: :home_phone }