Rails multiple conditional validation - ruby-on-rails

I have the following model
class User < ActiveRecord::Base
VALID_EMAIL_REGEX = /^.+#.+\..+$/i
attr_accessible :active_list_id, :password, :password_confirmation, :email, :temp
has_secure_password
before_create { generate_token(:auth_token) }
if :temp.nil?
before_validation :downcase_email
validates_presence_of :email, :password, :password_confirmation, :on => :create
validates_confirmation_of :password
#something#something.something
validates :email, :uniqueness => true,
:format => {:with => VALID_EMAIL_REGEX }
end
after_create { make_list([email,"'s shopping list"].join('')) }
has_many :shopping_lists
has_many :transactions, :class_name => 'Order'
HUMANIZED_ATTRIBUTES = {
:password_digest => "Password"
}
...
end
I try to create a model in my rails console by calling User.create(:temp => true) (which is a boolean and is defined in my migrations/schema). But it always rollsback the transaction. What am I doing wrong?
I also tried doing :if => temp.nil? and if => "temp.nil?" and :if => lambda { |user| user.temp.nil? } for all 3 of my validations.

create a method called temp_is_nil? and use that on the if condition
def temp_is_nil?
temp.nil?
end
make sure that temp is an attribute of user.
before_validation :downcase_email, if: temp_is_nil?
validates_presence_of :email, :password, :password_confirmation, :on => :create, if: temp_is_nil?
validates_confirmation_of :password, if: temp_is_nil?
validates :email, :uniqueness => true,
:format => {:with => VALID_EMAIL_REGEX }, if: temp_is_nil?

Related

Validation Rails

Hi this is my User model
class User < ActiveRecord::Base
has_many :events
validates :cellphone, numericality:{ only_integer: true, message:"no es un numero"}, format: { with: /\d{11}/, message: "mal formato, deben ser 11 digitos, incluyendo codigo de area" }, :allow_blank => true
validates :phone, numericality:{ only_integer: true, message:"no es un numero"}, format: { with: /\d{11}/, message: "mal formato, deben ser 11 digitos, incluyendo codigo de area" }, :allow_blank => true
validates_numericality_of :cellphone, :on => :create, :message => "no es un numero", :allow_blank => true
validates_numericality_of :document, :on => :create, :message => "no es un numero", :allow_blank => true
validates :name, :presence => true
validates :lastname, :presence => true
validates :document, :presence => true, :uniqueness => true
validates :cellphone, :presence => true, :uniqueness => true
validates :phone, :presence => true, :uniqueness => true
validates_format_of :email,:with => Devise::email_regexp, :allow_blank => true
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
I want to valida, example :cellphone, numericality only if it pass :cellphone, :presence => true validation.
I already read all the post here in StackOverflow but i cant seem to understand what they are doing.
If some1 could help me with this step by step.
Thanks
:allow_blank => true
:presence => true
As #apneadiving mentioned in the comment, these two are 180 degree apart from each other. If one is true, the other one should be false. You can't have both at the same time.
What you are asking is that you want to check for the numericality if and only if the record is presence. For that, you can do the following:
validates :cellphone, numericality:{ ... }, format: { ... }, :allow_blank => true
In this way, since cellphone field can be blank, numericality will only be checked for it if it exists.
The other option is: You can pass a block to check if the field exists, and it does, check for numericality.
Here's how:
validate :cellphone, numbericality: { ... }, :if => lambda{ |object| object.cellphone.present? }

Rails, validations within a with_options block don't work

I have an old Rails 2 app where I have a User model that handles profiles of users coming from web and mobile applications. I would like to have 2 separate groups of validations for web and mobile users. I use DEVISE for authentication.
In order to recognize if a user relates to web or mobile, I use an attr_accessor called validation_for_mobile that I set on the controller side, before saving/updating the record.
It appears that some validations, especially the "validates_length_of :password", get executed even if they are inside a block with_options that should not be evaluated.
Inside the User model I have this code:
# WEB VALIDATIONS
with_options :if => "self.validation_for_mobile == false && !self.remote_sync" do |vm1|
vm1.validates_date :birthday, :allow_blank => true
vm1.validates_presence_of :company, :name, :surname, :address, :city, :province, :postal_code, :position, :company_type, :phone, :unless => :is_imported
vm1.validates_format_of :phone, :with => /\A([0-9]+)\Z/i, :message => 'deve contenere solo numeri', :unless => :is_imported
vm1.validates_presence_of :vat, :if => "!imported && !self.script_imported && company_type != 'individuale' && !company_type.blank?"
vm1.validates_presence_of :social_number, :if => "!imported && !self.script_imported && company_type == 'individuale' && !company_type.blank? "
vm1.validates_presence_of :remote_id, :if => "!came_from_user && !imported && !script_imported"
vm1.validates_acceptance_of :privacy_accepted, :privacy_third_part, :accept => true, :allow_nil => false, :unless => :is_imported
vm1.validates_presence_of :login, :email
vm1.validates_email_format_of :email, :message => "email non valida"
vm1.validates_presence_of :remote_sap_code, :remote_as_code, :if => "!came_from_user"
vm1.validates_uniqueness_of :login, :scope => :branch_id, :case_sensitive => false
vm1.with_options :if => :password_required? do |v|
v.validates_presence_of :password
v.validates_confirmation_of :password
v.validates_format_of :password, :with => /^(?=(.*\d){1})(?=.*[a-zA-Z])[0-9a-zA-Z]+$/i, :message => 'solo lettere e almeno 1 numero!'
v.validates_length_of :password, :within => 6..10, :allow_blank => true
end
end
# MOBILE VALIDATIONS
with_options :if => "self.validation_for_mobile == true && !self.remote_sync" do |vm2|
with_options :if => :mobile_validations do |vm2|
vm2.validates_presence_of :company, :vat, :name, :surname, :phone
vm2.validates_format_of :phone, :with => /\A([0-9]+)\Z/i, :message => 'deve contenere solo numeri'
vm2.validates_length_of :vat, :within => 11..15
vm2.validates_presence_of :login, :email, :branch_id
vm2.validates_email_format_of :email, :message => "email non valida"
vm2.validates_uniqueness_of :login, :scope => :branch_id, :case_sensitive => false
vm2.with_options :if => :password_required? do |v|
v.validates_presence_of :password
v.validates_confirmation_of :password
v.validates_format_of :password, :with => /^(?=(.*\d){1})(?=.*[a-zA-Z])[0-9a-zA-Z]+$/i, :message => 'solo lettere e almeno 1 numero!'
v.validates_length_of :password, :within => 1..10, :allow_blank => true
end
end
Every time I try to create a new user from mobile, I expect only the second block of validations to be evaluated, where "validates_length_of :password" is "within => 1..10"
But I receive the error that password is too short (at least 6 chars). And that's the first block!!!
Can you help me?
I also tried to move the conditions of with_options inside a method, like this:
with_options :if => :web_validations
with_options :if => :mobile_validations
but nothing changed.
This is the code I use to test it:
#user = User.new
#user.company = "Testuser"
#user.vat = "123456789012"
#user.name = "Fafag"
#user.surname = "Fafag"
#user.phone = "9182624"
#user.email = "utentest9876#test.it"
#user.login = "Utentest63"
#user.branch_id = 2
#user.password = "TEST1"
#user.password_confirmation = "TEST1"
#user.plain_password = "TEST1"
#user.mobile_signup = true
#user.mobile = true
#user.validation_for_mobile = true # model custom validation
#user.renew_mobile_token!
#user.came_from_user = true
#user.remote_id = 0
#user.confirmed = nil
#user.active = false
if #user.save
return true
else
puts #user.errors.full_messages.inspect
end
Ok, I solved this puzzle!
It seems nested with_options blocks don't inherit the outer condition. So I had to specify the first condition inside the nested with_option block, like this:
with_options :if => :mobile_validations do |vm2|
vm2.validates_presence_of :company, :vat, :name, :surname, :phone
vm2.validates_format_of :phone, :with => /\A([0-9]+)\Z/i, :message => 'deve contenere solo numeri'
vm2.validates_length_of :vat, :within => 11..15
vm2.validates_presence_of :login, :email, :branch_id
vm2.validates_email_format_of :email, :message => "email non valida"
vm2.validates_uniqueness_of :login, :scope => :branch_id, :case_sensitive => false
vm2.with_options :if => [:password_required?, :mobile_validations] do |v2|
v2.validates_presence_of :password
v2.validates_confirmation_of :password
v2.validates_format_of :password, :with => /^(?=(.*\d){1})(?=.*[a-zA-Z])[0-9a-zA-Z]+$/i, :message => 'solo lettere e almeno 1 numero!'
v2.validates_length_of :password, :within => 1..10, :allow_blank => true
end
end

If else in validates in rails

In model I want something like below
validates :category, :presence => true if self.post = "this_is_post"
Is it possible or I have to use a hook method before save for this checking?
This should work:
validates :category, :presence => true, :if => ->(a){ a.post == 'this_is_post' }
Here, more than one code snippest for validate condition in rails:
class Person < ActiveRecord::Base
validates :surname, presence: true, if: "name.nil?"
end
========================
validates :category,
:presence => true,
:if => :valid?
def valid?
self.post == "this_is_post"
end
================
class Person < ActiveRecord::Base
validates :category, presence: true, if: "self.post.eql?('this_is_post')"
end

how to skip model validation for particular function in rails?

I want to skip some model validation for controller functions. I am doing like this
Model :
attr_accessible :skip_method_2
validates :name, presence: true, length: { maximum: 50 }, :unless => :skip_method_2
VALID_PHONE_REGEX = /\(?([0-9]{3})\)?([ .-]?)([0-9]{3})\2([0-9]{4})/
validates :phoneno, presence: true,uniqueness: { case_sensitive: false, :scope => :user_id}, format: { with: VALID_PHONE_REGEX }, :unless => :skip_method_2
Controller :
def contacts_callback
#contacts = request.env['omnicontacts.contacts']
#contacts.each do |contact|
next if current_user.contacts.exists?(:email => "#{contact[:email]}")
contact1 = current_user.contacts.new(:skip_method_2 => true)
contact1.name = contact[:name]
contact1.email = contact[:email]
contact1.group = "Others"
contact1.save
end
redirect_to "/contact"
end
I dont want to save it by :validation => false. I want to skip name and phoneno validation for contacts_callback function. But it is not working.
It gives error in controller -
undefined local variable or method `skip_method_2' for contacts_callback. I already mentioned attr_accessible in my model
Change validates :name, presence: true, length: { maximum: 50 }, :unless => :skip_method_2
to
validates :name, presence: true, length: { maximum: 50 }, :unless => lambda {|x| x.skip_method_2}
Also checkout this answer

how to NOT update a field Ruby on Rails

I'm a newbie in rails. how put a validated on password field. specified only on create and used an allow_blank method. but everytime i update it still creates a nil in the password field. any help?
validates :password, :presence => { :on => :create },
:confirmation => true,
:length => { :within => 8..40},
:allow_blank => true,
Try this:
validates :password, :presence => { :if => :new_record? },
:confirmation => true,
:length => { :within => 8..40 }

Resources