Undefined method password_changed? Error
Asked Answered
A

4

8

I'm trying to set my program so that the password only is validated if it is changed (so a user can edit other information without having to put in their password).

I am currently getting an error that says

NoMethodError in UsersController#create, undefined method `password_changed?' for #<User:0x00000100d1d7a0>

when I try to log in.

Here is my validation code in user.rb:

    validates :name,  :presence => true,
 :length   => { :maximum => 50 }
validates :email, :presence   => true,
:format     => { :with => email_regex },
:uniqueness => { :case_sensitive => false }
validates :password, :presence =>true, :confirmation => true, :length => { :within => 6..40 }, :if=>:password_changed?  

Here is my create method in users_controller.rb:

def create
    @user = User.new(params[:user])
    if @user.save
        sign_in @user
        flash[:success] = "Welcome to the Sample App!"
        redirect_to @user
    else
        @title = "Sign up"
        render 'new'
    end
end

Thank you!

Alfeus answered 16/8, 2011 at 15:37 Comment(0)
M
5

Replace with:

:if => lambda {|user| user.password_changed? }

I'd do two different validations:

validates :password, :presence =>true, :confirmation => true, :length => { :within => 6..40 }, :on => :create
validates :password, :confirmation => true, :length => { :within => 6..40 }, :on => :update, :unless => lambda{ |user| user.password.blank? }  
Manzoni answered 16/8, 2011 at 15:40 Comment(3)
is password a column of your model?Manzoni
in the database? No, just encrypted_password. Should I add it?Alfeus
Sorry I'm new to this - how do I do that?Alfeus
S
3

I encountered this same problem and after reading this post I implemented the code suggested by apneadiving in his answer but with a slight modification:

I used two different validations, one for create:

validates :password, :presence => true, :confirmation => true, :length => { :within => 6..128 }, :on => :create

and then I used this one for update:

validates :password, :presence => true, :confirmation => true, :length => { :within => 6..128 }, :on => :update, :unless => lambda{ |user| user.password.to_s.empty? }

Originally, I Implemented exactly what apneadiving suggested, but I realized that on updates to the user it wasn't actually validating the presence of a string. As in, it was allowing a user to set their password to " " (A string of whitespace). This is due to the fact that " ".blank? == true, and so if you have it set to validate like this:

:unless => lambda { |user| user.password.blank? }

Then it won't run the validation if a string full of whitespace is submitted by the user is submitted because it reads the string as being blank. This essentially invalidates the effect of validating for presence on the update. The reason I did password.to_s.empty? instead of simply password.empty? is to prevent errors if someone calls update_attributes on the user model and doesn't pass in anything into the password, field, then the password will be nil, and since the ruby nil class doesn't have an empty? method, it will throw an error. Calling .to_s on nil, however will convert it to an empty string, which will return true on a successive .empty? call (thus the validation won't run). So after some trials and tribulation I found that this was the best way to do it.

Sullage answered 14/10, 2011 at 18:19 Comment(0)
C
2

Ended up here googling this error message, and using

@account.encrypted_password_changed?

in my case yielded what I wanted.

Castroprauxel answered 4/11, 2015 at 4:24 Comment(0)
A
1

The change to look for, in Rails 4 at least, is password_digest.

@account.password = "my new password"
@account.changes # => {"password_digest"=>["$2a$10$nR./uTAmcO0CmUSd5xOP2OMf8n7/vXuMD6EAgvCIsnoJDMpOzYzsa", "$2a$10$pVM18wPMzkyH5zQBvcf6ruJry22Yn8w7BrJ4U78o08eU/GMIqQUBW"]}
@account.password_digest_changed? # => true
Avirulent answered 17/7, 2015 at 23:48 Comment(1)
Likewise, none of the above worked for me. I ended up with this instead, just in case: validates_presence_of :password_confirmation, if: lambda { |staff| staff.password.present? } So now it requires password_confirmation on both create and update, and only if there is a password attribute sent as well. I'm surprised this isn't default behavior.Whiteley

© 2022 - 2024 — McMap. All rights reserved.