Is there a way to get around this? Basically in my user model i have a password validation to check and make sure the user has a minimum password length
validates :password, length: {minimum: 6 }
However, when I get the user to update additional info through a form helper, it refuses to update if I dont comment/delete the line above.
The following is some of my code in my user controller to update some user attributes in a db table
def additional_info
#user = User.find params[:id]
end
def update
#user = User.find(params[:id])
if #user.update(user_addinfo)
redirect_to #user
else
render action: 'additional_info'
end
end
def user_addinfo
params.permit(:years_business, :years_relationships, :years_careers, :years_lifeoutlook)
end
end
Help is greatly appreciated. My website is structured around Michael Hartl's tutorial but i made some personal modifications.But for the most part, its exactly the same.
Ah, I think I understand.
You can look at the has_secure_password source to see what validations, attributes, and other stuff it adds to your model.
As you probably know, has_secure_password adds an attr_reader :password along with a #password= setter that calculates the password_digest whenever you assign something to the password attribute. This prevents the password attribute from being persisted to the database. (Good!)
But that means that when you call #user.update, it will be on a #user which will have a nil password.
The trick is that you only want to validate the length of the password when the password is initially set. You should be able to fix this problem by changing your validation line to read:
validates :password, length: {minimum: 6 }, on: :create
If you want to allow users to change their passwords, you will have to do something else, like
validates :password, length: { minimum: 6 }, if: Proc.new { |u| u.password.present? }
Let me know if that works. I'm not 100% sure I understand your problem so let me know if this isn't the fix you were looking for.
Related
I have a User model which uses Devise for authentication. My User model has additional attributes like city etc.
On my registration page i only require email and password on user creation. Then i redirect the user to the User edit page to fill up the additional fields.
Validation looks like this:
validates :email, :password, presence: true
validates :city, presence: true, on: :update
So far so good - everything works fine with Rails 5.0.2 - now i upgraded to 5.1.5 and it redirects me straight back to registration page with the message 'city required'.. in the console i can see that the User is created. The thing is - it updates the user on login with last signed in stuff.
It's weird cause it shouldn't work with either of those rails versions.
Is there any better solution to force the user to update some additional fields after registration?
My registrations controller:
class RegistrationsController < Devise::RegistrationsController
private
def after_sign_up_path_for(resource)
edit_user_path
end
end
Your on: update must be within the options for the presence-validation. eg:
validates :city, presence: { on: :update }
However - you could also consider looking into using a form-pattern for each step of your process... which is how a lot of people do multi-stage form validation. Each form represents a stage in the process and has its own set of validations.
Figured out some kind of 'hack' to easily get it working:
validates :city, presence: true, unless: lambda { |u| u.last_sign_in_at_was.nil? }
The _was part is crucial.
In my User model I set validations for the password and its confirmation:
validates_presence_of :password, :password_confirmation
I use this for the forms. These attributes are not stored in the database, I am using the authlogic gem.
Now I am trying to make a system to restore forgotten passwords via email. The user inputs his email and the object is retrieved like this:
#user = User.find_by_email(params[:email])
Then, at a certain point in the process the value of a User attribute is set to true meaning that the user forgot his password, so I need to do a #user.save.
And there's the problem. Since password and password_confirmation were never stored, their values are nil. However, the validations come in play and prevent the user from being updated.
Is there any way to skip those particular validations so I can make this work? Or should I do something else? Any help?
You can skip all validations with save(validate: false). You can skip individual validations with the :if or :unless option, for example.
validates_presence_of :password, :password_confirmation, unless: :forgot_password?
def forgot_password?
# return true if the user is in the forgot password process
end
change
validates_presence_of :password, :password_confirmation
to
Assuming your field that is set to true is forgot_password
validates_presence_of :password, :password_confirmation, :unless => Proc.new { |a| a.forgot_password? }
Conditional Validations documentation
I have a user object, he can update his profile which includes name, user_name, password (blank), password_confirmation (blank), email, email_confirmation (blank), bio and picture url.
My model states that all of the (blank) MUST be filled in. but if your admin and your just going to the users page to update the user's role - You as the admin should not have to fill in user data you obviously don't know.
So how does one get around this? should I instead create a list of users with a drop down beside them? is this not, essentially , a giant form? If so - how would this get created?
essentially: What's the best way to deal with this situation?
This is currently how users get updated
def update
#user = User.friendly.find(params[:id])
#user.update_attributes(user_update_params)
if #user.save
render :show
else
render :edit
end
end
private
def user_update_params
params.require(:user).permit(:name, :user_name, :email, :email_confirmation, :password,
:password_confirmation, :bio, :picture_url, :role)
end
The real problem seems to be that you have a logical error in your User model validations.
You seem to have a validation of the form,
validates :password, presence: true, confirmation: true
which is enforced EVERY TIME, i.e. a new password has to be selected every single time a user object is saved. But this is likely not what you want. You likely want this validation to only be enforced when the user is created for the first time, i.e. when it is a new record.
You can do this with,
validates :password, presence: true, confirmation: true, if: :new_record?
update_attribute
Updates the attribute without doing validations, you need this one.
check out this api doc
EDIT:
Speaking about reading documentation
Here is an abstract from the method documentation
update_attribute(name, value) public
Updates a single attribute and saves the record. This is especially
useful for boolean flags on existing records. Also note that
Validation is skipped.
Callbacks are invoked.
updated_at/updated_on column is updated if that column is available.
Updates all the attributes that are dirty in this object.
EDIT:
If you still need to validate with this method, note that it says that callbacks are invoked, so what you can do is write your own code to validate input and use callbacks as described here.
I'm using authlogic with rails 3. I have this in my user model:
validates :last_name, :presence => true
acts_as_authentic do |c|
c.validates_length_of_password_field_options = {:minimum => 7}
end
And then I have a controller action that updates the user's name:
def update_name
if #current_user.update_attributes(params[:user])
flash[:success_name] = true
redirect_to edit_user_via_account_settings_path
else
render 'edit_user_via_account_settings'
end
end
If the user enters a blank last name and attempts to update their name with this controller action, the #current_user model correctly has errors on last name, but it also has errors on password (password must be a minimum of 7 chars). How can I only validate the password if the password is being updated?
You need to use the merge_validates_* config methods instead of the validates_* methods. The former keeps the conditionals (like ignore blank password) and the latter overwrites them. That should clear everything up. And don't use the assignment on the merge_* methods.
a.merge_validates_length_of_password_field_options :minimum => 7
I think the config you are looking for is found here
http://rdoc.info/github/binarylogic/authlogic/master/Authlogic/ActsAsAuthentic/Password/Config#ignore_blank_passwords-instance_method
Unless its a new user, if no password is supplied it does not validate the password.
I have a simple User class with the following validation of name uniqueness:
class User < ActiveRecord::Base
validates :name, :uniqueness => true,
It works great when a new user is created. However, when I check the login form, the user enters his name, and the system says it's already taken which doesn't make any sense.
So I implemented a separate valid_login? method, however I can't turn that unqueness check there:
def valid_login?
validates :name, :uniqueness => false # doesn't work
end
This is my controller's code:
def login
return unless request.post?
#user = User.new(params[:user])
if #user.valid_login?
# Redirect to user's page
end
end
I'm using my own authentication system which is quite simple: I store user's ID + password's hash in the cookies.
How can I turn of certain validation when I don't need it?
I solved this problem with the :if/:unless parameters.