Every repository with this icon (
Every repository with this icon (
Change Password
Here’s a version that might be a little more “ruby” (or at least more relevant to the contemporary Rails universe of resources, etc.) than what’s below.
In account_controller.rb:
def change_password if current_user.authenticated?(params[:old_password]) current_user.password = params[:password] current_user.password_confirmation = params[:password_confirmation] begin current_user.save! flash[:notice] = ‘Successfully changed your password.’ rescue ActiveRecord::RecordInvalid => e flash[:error] = “Couldn’t change your password: #{e}” end else flash[:error] = “Couldn’t change your password: is that really your current password?” end respond_to do |format| format.html { redirect_to :action => “edit” } end endin the view:
<% form_for( :user, :url => user_change_password_path( @user.id ), :html => { :method => :put }) do |f| %>
<%= password_field_tag “old_password” >
<= password_field_tag “password” >
<= password_field_tag “password_confirmation” >
<= submit_tag “Change Password”%>
<% end %>
And the relevant routing:
map.user_change_password ‘users/:id/change_password’, :controller => ‘users’, :action => ‘change_password’—Greg
Please correct if this is “not enough ruby”… :)
Controller (account_controller.rb):
def change_password return unless request.post? if User.authenticate(current_user.login, params[:old_password]) if (params[:password] == params[:password_confirmation]) current_user.password_confirmation = params[:password_confirmation] current_user.password = params[:password] flash[:notice] = current_user.save ? “Password changed” : “Password not changed” else flash[:notice] = “Password mismatch” @old_password = params[:old_password] end else flash[:notice] = “Wrong password” end endView (change_password.rhtml):
<%= start_form_tag >
<
<%= password_field_tag ‘password’ %>
<%= password_field_tag ‘password_confirmation’ %>
<%= submit_tag ‘Change password’ %>
<%= end_form_tag %>
__
added by Railsroad
I’ve created some tests:
def test_should_allow_password_change post :change_password, { :old_password => ‘test’, :password => ‘newpassword’, :password_confirmation => ‘newpassword’ }, { :user =>1 } assert_equal ‘newpassword’, assigns(:current_user).password assert_equal “Password changed”, flash[:notice] post :logout assert_nil session[:user] post :login, :login => ‘bryan’, :password => ‘newpassword’ assert session[:user] assert_response :redirect assert_redirected_to :controller => ‘contract’, :action => ‘index’ end def test_non_matching_passwords_should_not_change post :login, :login => ‘bryan’, :password => ‘test’ assert session[:user] post :change_password, { :old_password => ‘test’, :password => ‘newpassword’, :password_confirmation => ‘test’ } assert_not_equal ‘newpassword’, assigns(:current_user).password assert_equal “Password mismatch”, flash[:notice] end def test_incorrect_old_password_does_not_change post :login, :login => ‘bryan’, :password => ‘test’ assert session[:user] post :change_password, { :old_password => ‘wrongpassword’, :password => ‘newpassword’, :password_confirmation => ‘newpassword’ } assert_not_equal ‘newpassword’, assigns(:current_user).password assert_equal “Wrong password”, flash[:notice] endSuggestion by Barry Hess.
I’m pretty sure there is a bug in the account_controller class in the following update_password action code:
flash[:notice] = current_user.save ? “Password changed” : “Password not changed”On the update password screen, if one enters the correct old password without entering anything for a new and confirmed password, the system does not generate an error. I think this is because of the password_required? stipulation that is checked upon every password validation in the model:
def password_required?
crypted_password.blank? || !password.blank?
end
As you can see, this works fine upon sign-up as the password will be required due to the user’s crypted_password being blank. But when updating one’s password, the crypted_password is not blank and the second part of the or clause resolves to false as well because the password attribute is now blank as well.
I’m not 100% confident where the tweaking should take place, but I did something on the order of:
flash[:notice] = !params[:password].blank? && current_user.save ? “Password changed” : “Password not changed”The !params[:password].blank? still does not give us an error if both password fields are blank
corrected by replacing line 3 with
if ((params[:password] == params[:password_confirmation]) && params[:password_confirmation] != nil && params[:password_confirmation] != ’’)I busted this out in user.rb:
def self.update_attributes( params )
- handle password changes here
passed_password = params[ :password ]
passed_password_confirmation = params[ :password_confirmation ]
- something was passed
if ( passed_password ‘’ && passed_password_confirmation != ’’ || passed_password != ’’ && passed_password_confirmation ’’ || passed_password != passed_password_confirmation ) - one or the other was entered, but not confirmed, or the passwords didn’t match
self.errors.add_to_base ‘Password and Password Confirmation must match.’
return false
else - are we good here? I guess so.
self.password = passed_password
super.update_attributes( params )
end
else - no password funny business, just update attributes
super.update_attributes( params )
end
end
Seems to do the trick for me. Thoughts? Critiques?
I would suggest using this instead of the != nil and != ’’
if ((params[:password] == params[:password_confirmation]) && !params[:password_confirmation].blank?)
Suggestions by brad.j.miller on May 18th, 2007
This is my modified code, which bases the form on the user model and lets the model validate the input.
Controller (account_controller.rb):
def change_password
return unless request.post?
@user = self.current_user
@user.update_attributes(params[:user])
@user.reset_password
@user.save!
flash[:notice] = “Password has been successfully changed.”
redirect_to(:action => ‘index’)
end
View (change_password.rhtml):
<%= error_messages_for :user %>
<% form_for :user do |f| -%>
<%= f.password_field :password %>
<%= f.password_field :password_confirmation %>
<%= submit_tag ‘Submit’ %>
<% end -%>
Good idea, however i get an error ‘undefined method `reset_password’ for #User blah blah’ i’m new to rails, so any help would be appreciated!!!
Suggestion by Scott on October 9, 2007
I came across the same bug as Barry, but it seemed to me that the real problem had to do with password_required?.
I implemented the change_password method in the controller like Brad did above, then I also modified password_required from this:
def password_required? crypted_password.blank? || !password.blank? endto this:
def password_required? crypted_password.blank? || !password.nil? end





