Permitted Params for Devise Reset Password - ruby-on-rails

I have a Devise auth working on my Rails 4 app, I'm facing this problem which I have my Member model with some extra fields being validated (required) only on the update method (so it doesn't messed up the sign up form) but I just noticed that the "reset password" also uses the update method, but in a different controller (DeviseController). Here's what's happening:
I try to reset a member's password
submit the form (only password and password_confirmation fields)
Got errors about the extra/required fields
Is there a way to tell Devise to only request the password and password_confirmation fields on this specific form?
Thanks!

I had the same problem, I don't know why but it was only on production.
First of all, check if this fields(extra/required fields) are not empty, before you reset password.
Also you can try smth like this in your user model
validates :first_name, :last_name, presence: true, format: { with: /\A[a-zA-Z]+\z/, message: 'only allows letters' }, unless: :password_reset
def password_reset
reset_password_token.present?
end
I tested, just check fields that must be validated before you'll reset password.

Related

Returning User name into form when registration failed

Sorry for my english, it will hard to describe problem. I have user devise model with registration params [:name, :email, :password, :confirm_password] . Problem is in name field. For example if registration was failed because of mismatched password RAILS render new reg. form but name field will be empty, but i need to set it by previous value. Email filed sets good, because it is a default param of devise gem. Can some one help?

Rails updating user settings using form_for and blank password fields

I am following Hartl's Rails Tutorial, creating the edit user page. This is how I update in the update method:
#user.update_attributes(user_params)
where user_params is a method for strong parameters
In the user model I have also included the following line:
validates :password, length: { minimum: 6 }, allow_blank: true
Now, when I edit the user's name/email and submit the form with blank password fields, the user is successfully updated (the password stays the same instead of changing to a blank one). This is what I want. But why does that work? Is it something special about the form_for method? If I use rails console and try to update a user using the update_attributes method and a blank password, the object fails to save.
It is because of the allow_blank option which Rails in this case will ignore the password if it comes blank or nil.
Another approach I like is the one from devise on which by using a method called password_required? they can handle multiple kinds of custom validations and gives you total control in case you need to overwrite, but that's just extra.

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

Updating profiles and passwords

I'm not sure on how to best tackle this issue - I need to validate a user's password when adding a new record and I also need to be able to validate when updating the passoword too. But how can I let a user update just part of their profile and perhaps leaving the password blank.
Note before you suggest allow_blank I am aware of this option but this is not suitable because when a user needs to change their password as a result of losing/forgetting it I don't want to allow user to have a blank password.
validates :password, presence: true, if: lambda { |user| user.password_changed? }
by ActiveModel::Dirty (available on all models by default)
You can pass an if statement to a validation:
`validates_presence_of :password, :if => :should_validate_password?
You should be able to pass a condition in here to catch whether the user is updating their password or not:
Model
def should_validate_password?
updating_password || new_record?
end
Controller
#user.updating_password = true
#user.save
See here for more details: http://railscasts.com/episodes/41-conditional-validations
Updated:
In your case I would create an if statement in the controller that detected whether any new password was being passed in the params. If so I would set #user.updating_password = true which would trigger the validation in the model. If not then #user.updating_password would be nil and the validation wouldn't trigger.
Fully custom way
Usually, #password= and #password_confirmation= are just virtual setters, the true attribute is #hashed_password or something. So, you could do something like this :
class User
attr_accessor :password, :password_confirmation
validate :validates_password
validates_presence_of :hashed_password
private
def validates_password
if password or password_confirmation
if password != password_confirmation
errors.add( :password, 'your message' )
end
# your others validations
self.hashed_password = hash_password
end
end
def hash_password
# your hashing code
end
end
When user is created providing password, virtual attributes password and password_confirmation are set, so if condition is true and validations are enforced.
When password is already set and user does not change it (an edit form without providing passwords), validation will not be enforced, because of if password and password_confirmation.
When password is already set and user change it, password and password_confirmation are set, so validation is triggered.
When you want to reset password, just set in your action hashed_password to nil. The model is now invalid because of validates_presence_of :hashed_password and user has to provide a new one.
Using #has_secure_password
With #has_secure_password, rails will handle most of this, especially :
it creates virtual atttributes
it will trigger validation for confirmation match only if password attributes are provided
it will hash password
So, what you need is just adding your own validations, doing it only when password or password_confirmation are present.
class User
has_secure_password
validate :validates_password
private
def validates_password
if password or password_confirmation
unless <your_test>
errors.add( :password, '<your error message>' )
end
end
end
end
As previously, this will only be triggered if password and password_confirmation are provided, which only happens if user submitted them as form data (as real attribute is password_digest).

In Rails 3, how can I skip validation of the password field when I'm not attempting to update the password?

My User model contains :name, :email, and :password fields. All 3 have validations for length. An "update account" web page allows the user to update his name and email address, but not password. When submitted, params[:user] is
{"name"=>"Joe User", "email"=>"user#example.com"}
Note there is no "password" key because the form doesn't contain such an input field.
When I call
#user.update_attributes(params[:user])
the password validation fails. However, since I'm not attempting to update the password, I don't want the password validation to run on this update. I'm confused why the password validation is running when params[:user] doesn't contain a "password" key.
Note that I want to have a separate web page elsewhere that allows the user to update his password. And for that submission, the password validation should run.
Thank you.
My application does something like this
attr_accessor :updating_password
validates_confirmation_of :password, :if => should_validate_password?
def should_validate_password?
updating_password || new_record?
end
so you have to model.updating_password = true for the verification to take place, and you don't have to do this on creation.
Which I found at a good railscast at http://railscasts.com/episodes/41-conditional-validations
In your user model, you could just ignore the password validation if it's not set.
validates_length_of :password, :minimum => N, :unless => lambda {|u| u.password.nil? }
Using update_attributes will not change the value of the password if there is no key for it in the params hash.
Validation doesn't run against the changed fields only. It validates existing values too.
Your validation must be failing because the password field contains some invalid content that's already saved in the database. I'm guessing it's probably because you're hashing it after validation and you're trying to validate the hashed string.
You can use a virtual attribute (an instance variable or method) that you validate with a custom method, and then assign the hash to the stored password field. Have a look at this technique for ideas.
An app that I am working on uses the following:
validates_confirmation_of :password,
:if => Proc.new { |account|
!account.password.blank?
|| !account.password_confirmation.blank?
|| account.new_record? }
Depending on your requirements, you might want to remove the new_record? check
When password is added then only confirmation will be called and presence will call on create action only
**validates_presence_of :password, :on =>:create**
**validates_confirmation_of :password**

Resources