How to skip validation of a few model fields - ruby-on-rails

I have a model User.
Here're a few validation fields:
validates :first_name, presence:{ message: "please add your First name"}
validates :last_name, presence:{ message: "please add your Last name"}
validates :username, presence:{ message: "please pick a username"},
When I try to sign up using devise, I have a message that I should provide first name and last name. But for registration I only want to use 3 fields shown: username, email, password.
How to skip validation of first and last names during registration?
Thanks.

You don't want the validations for first_name, last_name to run while creating a new user BUT you want them while updating an existing user record. All you need to do is , modify the validations such that they will only be run while updating a user record.
You can do this by using on: :update option as below:
validates :first_name, presence:{ message: "please add your First name"}, on: :update
validates :last_name, presence:{ message: "please add your Last name"}, on: :update

Related

Ruby on Rails has_secure_password validation gets errors on update

I have working on a Ruby on Rails application and have a problem. I've user model in my domain and it has a has_secure_password field like this:
class User < ApplicationRecord
validates :name, presence: true
has_secure_password
validates :password, presence: true
validates :password, length: { in: 6..20, message: 'Password shoul be minimum 6 characters'}
end
And I save the user object with this function:
def self.create_with_params(email,name,password)
user = User.new()
user.provider= :mail
user.name=name
user.email=email
user.password=password
user.activate_status=false
user.save(validate: true);
return user;
end
That's ok too.
But when I want to update a field in my user model. I get validation error for password field.
#user = User.find_by(email: params[:email]) # this record has a valid password_digest field in database.
#user.name = 'John'
#user.save
puts #user.errors.full_messages
It prints:
"Password shoul be minimum 6 characters".
Note: I have password_digest field in my users table.
I think when I query users table password_digest field couldn't be filled in to password field on model.
Any suggestions?
I think when I query Users table password_digest field couldn't be
filled in to password field on model.
Correct, the password is not stored, so when you query User you don't get the password field, yet your model asks for it every time with:
validates :password, presence: true
So, you will need to provide password before saving #user to make it work, but i guess that is not what you want, so just remove that validation from your model,
You won't need to validate password every time, just upon creating, and that validation is done with has_secure_password.
Also, for the same reason, you will need to update length validation to:
validates :password, length: { in: 6..20, message: 'Password shoul be minimum 6 characters'}, allow_nil: true

Rails validation best practice

I have this validation for my user:
validates :password,
presence: true,
confirmation: true,
length: { minimum: 6 },
:on => :create
This is obvious. When I'm creating (registering) a new user, I want to fill up their password hence that's why presence: true.
Case 1) When the user wants to update his account (lets say change his username), the form has only the email and username fields. That's ok and the validation is ok.
Case 2) He forgot his password and I send him his "forgotten password link" and he is on the page where he is creating his new password. The form has these two fields: password and password confirmation. However, he leaves both of these fields empty and submits the form. The validation passes because it's only :on => create! because of case 1)
I can not add :on => update because the case 1) wouldn't pass, because there is no password field.
What should I do in this situation? What is the best practice or what is the real word solution to this "problem"?
What I have done for this situation is instead of using on: :create, I use a virtual attribute that I set only when setting/changing the password. Something like this:
validates :password, if: :changing_password?
attr_accessor :password_scenario
def changing_password?
self.password_scenario.present?
end
Then in your controller, you would simply set password_scenario to true whenever you are requiring password to be present.

Rails Conditional Validations

I am working on a project and need some help on where to begin. I have three pages
Update User
Create User
Admin User Password Change (like a Hard Reset Password for but only the admin can reset the user's password)
Change Password
On Create User first name, last name, username, password, and password confirmation are mandatory.
On Update User just first name, last name and username are mandatory.
On Admin User Password Change and Change Password, just password and password confirmation are mandatory.
How would you go about doing this? I don't think this is possible through models using validates_presence_of with an if because there are too many scenarios. Any help or guidance would be appreciated. Also, I am pretty new to Rails if you can't already tell.
You can pass conditionals to your validations:
validates :password, :confirmation => true, :presence => true
validates :first_name, :last_name, :username, :presence => true
validate :admin_user_password_change?
Of course you'd have to define what the admin_user_password_change? method would be to determine if it is an admin user changing a password.
UPDATE
The admin_user_password_change? method might be something like:
def admin_user_password_change?
unless self.admin? && self.password.present? && self.password_confirmation.present?
self.errors.add(:admin_password_change, "password and password_confirmation are required.")
end
end
As for How would it communicate with the controller?, it wouldn't directly. But if any of the conditions in the method are false (e.g. self.admin? && self.password.present? && self.password_confirmation.present?), an error will be added to the instance of User and the instance won't save in the controller.
Setting some fields to new values doesn't unset other fields; just because you're only updating some fields in one action doesn't mean the other fields will be unset, so long as they start in a consistent state.
Just add your validations. It will work fine.
You can tell to your validation work only on certain cenarios only using:
The create:
validates :first_name, :last_name, :username, presence: true, on: :create
The update:
validates :password, presence: true, on: :update
Take a look at on.
For validation based on context take a look at Context Validations

Validation of fields from some box on the view - Rails

I have an User model. It has next fields:
attr_accessible :user_name, :first_name, :last_name, :email ....
There is a profile view for the User with 6 blocks. Each of them associated with the various fields. Box 1 - first_name and last_name, Box 2 - user_name and email, etc.
I need to validate all the fields (presence, format, etc). But validators must trigger only for those fields, that has came from a particular block (Box 1 or Box 2, for example).
If I write something like next:
validates :user_name, :presence => true
and I will not edit the block with the *user_name*, I will see the error "user Name can't be blank". I can't use *:allow_blank => true* or nil because it can't(!) be blank!
In two words: I must validate only those fields, that was past from the resquest.
What I can do to solve my problem? Thx
You can add if or unless option to skip of particular condition.
validates :user_name, :presence => true, :if => "first_name.blank? and last_name.blank?"
You can pull the specific fields out of your model and create a model for each block, then you add one_to_one relationships to your User model.

Devise custom messages when validation fails

I'm using devise as authentication engine in my app.
Is there any way to use custom messages when devise validation fails.
Devise provides me with the following message when the password is blank: Password can't be blank, but i need another message. How can i do it?
ActiveRecord en.yml is the answer I would suggest if you want to change the Validation Message for Devise
Here is how the en.yml should look like
en:
activerecord:
errors:
models:
user:
attributes:
email:
blank: "Please Specify an Email id"
taken: "Please use a different Email id"
invalid: "Please Specify a valid Email id"
password:
blank: "Please Specify a Password"
confirmation: "Password does not match"
password_confirmation:
blank: "Please Specify a Password Confirmation"
first_name:
blank: "Please Specify First Name"
last_name:
blank: "Please Specify Last Name"
pdf:
attributes:
name:
blank: "Please Specify name to PDF"
taken: "Please use different name for PDF"
attachment:
blank: "Please Upload a PDF Attachment"
data_element:
attributes:
name:
blank: "Please give Element a desired name"
taken: "Already Created Element with given name"
color:
blank: "Please assign a color to Element"
template:
attributes:
name:
blank: "Please Specify a Name"
taken: "Please use a different name"
I advice you to define this way instead of customizing devise validation module
Because if you follow the above approach, it would be possible that you would skip a validation a place or two
for Example I the remove the above devise validation module and then substitue your own in
User Model
then all the validation would work for but you would miss the validation in Change Password
There by resulting your to login even though the password was never supplied and never given
Keep a loop of that too
Cheer
Regards
Please refer to the URL below.
http://railscasts.com/episodes/210-customizing-devise?view=asciicast
If the user is signing in, you can edit all the error messages in devise.en.yml under config/locales.
If you're signing up, Devise provides its own validations out of the box without any customizing. If you want to customize it, you can edit the User model.
Find devise :validatable and remove the :validatable option. After which, you should be able to use the usual rails validations. Note that this will cause you to have to do all the validations yourself.
validates_presence_of :password, :message=>"Your custom error message!"
Some usual validations:
validates_confirmation_of :password
validates_presence_of :password, :on => :create
validates_presence_of :email
validates_uniqueness_of :email
Not a complete answer, but this sounds like it should be solvable with I18n, either with the devise-internal keys, or by overriding active record's validation error messages for your user model.
Here's a similar question: Devise attributes for i18n?
You can customize your devise messages from config/locales/devise.en.yml but if you want to change to validation message then delete :validatable from Model. Then you can change a validation message like before.
For example:
validates_uniqueness_of :email, :case_sensitive => false, :allow_blank => true, :if => :email_changed?
validates_format_of :email, :with => Devise.email_regexp, :allow_blank => true, :if => :email_changed?
validates_presence_of :password, :on=>:create
validates_confirmation_of :password, :on=>:create
validates_length_of :password, :within => Devise.password_length, :allow_blank => true

Resources