I'm a newbie in rails and I'm stuck with this problem: I have a model named User
class User < ActiveRecord::Base
attr_accessor :password
EMAIL_REGEX = /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i
validates :first_name, :presence => true,:format => /\A[a-zA-Z]+\z/
validates :last_name, :presence => true,:format => /\A[a-zA-Z]+\z/
validates :email, :presence => true, :uniqueness => true, :format => EMAIL_REGEX
validates :password, :presence => true
validates_length_of :password, :in => 6..20, :on => :create
end
with database attributes first_name, last_name, email, hashed_password and encrypted_password.
When I create new Object of User and saves it in the database there is no problem. NOW, here's the problem I want to edit attributes of my User Object EXCEPT email and password.
Once I try to edit the record through edit of rails resource it flags an error that password should not be empty. I am planning to have an exemption of validation if the user wants to edit his/her information but I know that it is not a good practice.
Hoping to find the best answer.
For starters check out http://guides.rubyonrails.org/active_record_validations.html#conditional-validation - once this approach becomes unDRY (repeated more then 2-3 times) see http://apidock.com/rails/Object/with_options
Once you get more advanced you will want to try something in the lines of a form/service class and extract form/action-specific validations there - http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/
...and welcome to rails :)
Try using
validates :password, :presence => true, on: :create
And in the user edit form add every field except email and password.
But thing is that while you are going to change the password, there is no validation on password. So when you are implementing the change_password section, you need handle it and nee to add the errors manually for the password.
Problem Solved! Im not sure if this is the best solution. Once I instantiate a User object I use the after_initialize then set updatePassword to true as a default value then in the edit action of User Object I set updatePassword to false so that it will be exempted in the validation. I also use the conditional validation for the updatePassword. :D Thanks for all the ideas!
Related
I am using devise for user registrations, meaning, that by default new user is registered through registrations_controller. So by clicking button "Register" user is redirected to a new_user_registration path.
My registration form however has two steps. In first step (new_user_registration) I am asking for a name and password. In the second step (users_controller), when user is saved, I am asking for address. This I am doing with wizard gem:
def create
#user = User.new(params[:user])
if #user.save
session[:user_id] = #user.id
redirect_to user_steps_path
else
render :new
end
end
So, those a kind of partioal validations, but I cannnot validate depending in the step, as the first part of my form is handeled through registrations controller. The second part is however in the users_controller. It's getting complicated here and I would like to know, if I can validatede depending on the controller. Like:
validates :first_name, presence: true, if: -> { new_user_registration_path }
validates :last_name, presence: true, if: -> { new_user_registration_path }
validates :street, presence: true, if: -> { new_user_path }
I know, like this, it makes no sence, but maybe it helps to understand my thinking behind. Also, maybe I can work with smth. like:
validates :first_name, presence: true, if: -> { #user.save }
validates :last_name, presence: true, if: -> { #user.save }
validates :street, presence: true, if: -> { #user.update}
So basically, when creating a new user, I would validate if name and password is present. And when then adding address (it's an update action for user), I will check if address is present. Does anyone has experince with forms like this?
Another thought, maybe, I can skip registrations controller, redirecting directly to the user and creating two steps for partial validations? But as I am working with devise, I don't know, if I can just go throught users controller, skipping new_user_registration path. I did it, how it was advised on the wicked tutorial, but still ended up in the registrations controller:
def create
super
end
def update
super
end
Thanks!
The best solution to this type of problem is to use form objects. See this example and the gem Reform.
With form objects, each HTML form is processed via a form object. In your example you could have a "User Registration" form, and a "User update" form. The key point is that the validation is done by the form and not the model. That way the validation is relevant to the current form input, and you avoid the issues of classing validation rules.
It's as easy as that:
validates :first_name, presence: true, :on => :create
validates :last_name, presence: true, :on => :create
validates :street, presence: true, :on => :update
validates :house_number, presence: true, :on => :update
validates :city, presence: true, :on => :update
validates :zip_code, presence: true, :on => :update
Clearly "Sign-Up" creates a User. And the wizard_steps just update the user. So for this simple example this works perfectly and raises validation errors according to the controller action.
I am trying to validate fields in a form where I want two different messages for two different problems with the input.
I have the following code:
validates_format_of :email,
:with => /^([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})$/i,
:allow_blank => false
If the email field is left blank then the error message "Email is invalid" is shown in the website.
How can I get the validation to return a message saying the field cannot be blank if it is left out by the user, instead of just saying it is too short?
I like to handle this with 2 different validations (and make sure they don't both fire at the same time). So something like this:
validates_format_of :email,
:with => /^([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})$/i,
:allow_blank => true
validates_presence_of :email
The validates_presence_of handles making sure the email is not blank. And changing validates_format_of to use :allow_blank => true will make sure the formatting validation won't run if the email is blank.
In Rails 3.0+ you can also combine the two validations into a single one using validates:
validates :email,
presence: true,
format: { with: /^([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})$/i,
allow_blank: true }
You create a separate validation for the blank case:
validates_presence_of :email
validates_format_of :email,
:with => /^([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})$/i,
:allow_blank => true
You need to add another validation checking for presence separately, like:
validates :email, presence: true, format: { with: YOUR_REGEX }
I have a users sign up form, but when the users sign back in they are required to type their email address with the same cases as they signed up with. I have measures to prevent this, but for some strange reason they are not working.
In the users model:
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => { :case_sensitive => false }
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
This was not working... im not sure why. but then I added another method to see what it did:
before_save :downcase_fields
def downcase_fields
self.email.downcase
end
and down cased the fields when users type them in with this in my sessions controller:
def create
user = User.authenticate(params[:session][:email].downcase,
params[:session][:password])
#...
end
All of this still yields a case sensitive email field when the users sign back in... help?
Try this:
self.email.downcase!
In my user model, I have
validates :email, :presence=>true,
:format => { :with => email_regex },
:uniqueness => true
In my controller, I update the email if a user chooses to change it like this:
#user.update_attribute("email","#{#new_email}")
However, it doesn't throw an error if the format is not honored.
update_attribute does no validations. use
#user.update_attributes({ :email => #new_email })
instead.
I found out that update_attribute skips checking for validation but update_attributes doesn't! Interesting.
http://apidock.com/rails/ActiveRecord/Base/update_attributes
I have a User model with the usual attributes such as email and hashed_password etc. I want to write a validation that checks for the presence of an email address but only when
1) there isn't one stored in the database for this object (i.e. this is a new user signing up)
2) the user is trying to update their email address.
My current validations
validates_presence_of :email
validates_presence_of :email_confirmation
validates_confirmation_of :email
are obviously preventing me from updating any attributes. I thought of using
validates_presence_of :email , :if :email_validation_required?
def email_validation_required?
self.email.blank?
end
But that wont help with scenario 2 as it will return true because the user does have an password email address in the db.
I cant work out how i can limit it to just those 2 scenarios above.
Can anyone help?
I think EmFi is on to something. But I don't think the validates_presence_of :email should be holding you up. The email should always be present - if it is left blank in the form the parameter will not mess with your save of the user. If it is entered in the form, even for update, it should have an email_confirmation along for the ride.
Give this a try:
validates_presence_of :email
validates_presence_of :email_confirmation, :if => :email_changed?
validates_confirmation_of :email
you have two options. one is to use :on. by default, they are set to :on => :save, but you can do something like this this
validates_presence_of :email, :on => :create
or
validates_presence_of :email, :on => :update
the other options is to use :if, and then pass in a method name or a proc. so something like
validates_presence_of :email, :if => :should_validate
or
validates_presence_of :email, :if => Proc.new { |user| user.signup_stage > 2 }
Hope that helps :)
You want to use an :if clause on the validation that uses the ActiveRecord::Dirty methods:
validates_presence_of :email, :if => Proc.new { |user| user.email_changed?}
N.B. Only works in Rails 2.1 or later.