In my user model i have validation of password and an instance method like this:
class User < ActiveRecord::Base
validate :email ......
validates :password, length: { minimum: 6 }
def my_method
# .....
# save!
end
end
As you can see inside this method i have a call to the save! method which save the user after altering some fields, so i want to skip the validation of password but not other validations only when i call my_method on a user instance , how i can do this please ? thank you
I find the solution if someone is interesting, i simply add attr_accessor :skip_password_validation to my model, then i add a condition to my password validation validates :password, length: { minimum: 6 }, unless: :skip_password_validation, and when i call my_method in the controller with an instance of user model, i set this attribute above with true. it's all , here what the user model will look like:
class User < ActiveRecord::Base
validate :email ......
validates :password, length: { minimum: 6 }, unless: :skip_password_validation
attr_accessor :skip_password_validation
def my_method
# .....
# save!
end
end
In the controller before i call user.my_method i just add the line : user.skip_password_validation = true.
I hope this help you :)
You can do it with 2 methods.
model.save(:validate => false)
See here and here
OR
Skipping the Callback
skip_callback :validate, :before, :check_membership, :if => lambda { self.age > 18 }
API Doc
Related
class Test < ActiveRecord::Base
def skip_validation
if self.type == 'A'
# skip all validation
else
# Do notihng.
end
end
Note : In my test model, I have added validations and callback. I need to apply these validations only if above condition matches.
Can I use object.save(validates :false)?
You can pass an :if option to do so:
validates_presence_of :password, :if => :something_is_true?
And :something_is_true is a method actually in your method where you can describe your logic.
class Test < ActiveRecord::Base # Though I would never name it 'Test'
validates_presence_of :password, :if => :should_validate_password?
def should_validate_password
# define your logic here
# at the end, it should return 'true' or 'false'
end
end
If the method through which you would like to validate the instance, belongs to the instance, then you can pass that method as a string like following:
validates_presence_of :password, if: 'admin?'
It would call admin? on the current instance, and if it returns true, it will validate the presence of password, and vice versa.
I want to validate 1 params in model method, but i can't found any fit answers , please show me the right way.
class User < ActiveRecord::Base
validate :username, presence: true, length: 4..5, unique: true
validate :email, presence: true, unique: true, format: {with: /\A[a-z0-9\.]+#([a-z]{1,10}\.){1,2}[a-z]{2,4}\z/}
def self.get_post(id)
# how to call validate id ???
validates :id, numericality: true
if id.valid?
# true code
else
# false code
end
end
def change_profile
# How to check validate user and email
username.valid?
email.valid?
# some_code....
end
end
Thanks all.
You cannot use validates there, you can do this instead
def self.get_post(id)
if id.is_a? Numeric
# true code
else
# false code
end
end
You can use active model for your customization, you can not check validation on field to filed, but you can perform with active model with number of fields as per your requirement
http://railscasts.com/episodes/219-active-model
class User
include ActiveModel::Validations
validates_with UserProfile
end
class UserProfile < ActiveModel::Validator
def validate(record)
if some_complex_logic
record.errors[:base] = "This record is invalid"
end
end
private
def some_complex_logic
# ...
end
end
I think this is a simple problem. So far I've ran
rails generate scaffold User username:string email:string password:string
to make a new scaffold for the User model. The following is my user.rb:
class User < ActiveRecord::Base
validates :username, presence: true, length: { in: 2..50 }, uniqueness: true
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, uniqueness: true
validates :password, presence: true, length: { in: 4..50}
#self.password = 'abcd' #I can't even change the parameter to something hard-coded!
end
I've written a few tests and that works great. My next step is to put the password parameter through a hashfunction (which I want to write myself for educational purposes) and save this newly modified string instead of the original string. I don't seem to understand how to do this? Do I create a method in user.rb which gets called from the users_controllers.rb under the create method?
I would like to test this by doing rails console --sandbox and writing some tests, too.
You can use the before_save callback
# user.rb model
before_save :hash_password
def hash_password
self.password = some_hash_function(self.password)
end
You have to be careful with this method not to hash the password multiple times. That is you must always hash the clear password and not hash the hashed version. That's why I would do it like this and call the field password_digest and only hash the password if the password attribute is set.
# user.rb model
attr_accessor :password
before_save :hash_password
def hash_password
self.password_digest = some_hash_function(self.password) unless self.password.blank?
end
http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
is it possible to run ActiveRecord validates on given controller and action.
For example I have user_controller and signup_controller
I need to run password required validation only on signup_controller#create action
You can run validations using an if conditional:
validates :email, presence: true, if: :validate_email?
Now you need to define this instance method (in your model):
def validate_email?
validate_email == 'true' || validate_email == true
end
This validate_email attribute could be a virtual attribute in your model:
attr_accessor :validate_email
And now, you can perform email validation depending on that virtual attribute. For example, in signup_controller#create you can do something like:
def create
...
#user.validate_email = true
#user.save
...
end
use validates :password, :if => :password_changed? in user.rb
if form in users_controller does not submit password field then you should be ok.
Just a tip for implementing #markets' answer
We can use
with_options if: :validate_email? do |z|
z.validates :email, presence: true
z.validates :name, presence: true
end
for multiple validations on our specific action.
Also, we use session to pass a variable which indicate params from this action will need some validations
Controller:
before_action :no_validate, only: [:first_action, :second_action, ..]
before_action :action_based_validation, only: [:first_action, :second_action, ..]
def first_action; end
def second_action; end
def update
..
#instance.validate = session[:validate]
..
if #instance.update(instance_params)
..
end
end
private
def no_validate
session[:validate] = nil
end
def action_based_validation
# action_name in first_action will = "first_action"
session[:validate] = action_name
end
Model
attr_accessor :validate
with_options if: "validate == 'first_action'" do |z|
z.validates :email, presence: true
..more validations..
end
with_options if: "validate == 'second_action'" do |z|
z.validates :name, presence: true
..more validations..
end
more details:
http://guides.rubyonrails.org/active_record_validations.html#conditional-validation
Okay I have quite a weird scenario that I do not know how to deal with so please bear with me as I try to explain it to you.
I have the following model.
class User < ActiveRecord::Base
Roles = { pending: 'pending_user', role2: 'role2', etc: 'etc' }
attr_accessible :role
validates :role, inclusion: {in: Roles.values}
before_create :add_pendng_role #Set user role to Roles[:pending]
end
Now the problem is when creating a record for the first time, this validation fails! For example in my controller I have the following code:
class UsersController < ActionController::Base
#user = User.new params[:user]
if #user.save # --------------- ALWAYS FAILS -------------------------------
#do something
else
#do something else
end
end
Now the reason I believe it fails is because a role is only added before_create which is called after the validations have passed. Now I know that I can't replace the before_create :add_role with before_validation :add_role because I think that it will add the role each time a validation is done. The reason I can't have that is because the user role will change in the application and I don't want to reset the role each time a validations are done on the user.
Any clues on how I could tackle this?
You could try:
before_validation :add_role, on: :create
Use *before_validation*, as explained in the rails callback guide
class User < ActiveRecord::Base
Roles = { pending: 'pending_user', role2: 'role2', etc: 'etc' }
attr_accessible :role
validates :role, inclusion: {in: Roles.values}
before_validation :add_pendng_role, on: :create #Set user role to Roles[:pending]
end
Looks like you'll be able to change before_create to before_validation if you use the :on argument:
before_validation :add_pendng_role, :on => :create