ruby-on-railsrubyvalidationruby-on-rails-4grails-validation

Require current password to set a new password


I want users to input their current password when editing their profile.

This is how my user model looks like:

attr_accessor :current_password

def current_password
  errors[:current_password] << 'Incorrect password' unless self.current_password == self.password
end

validate :current_password, on: :update

And my controller params:

def user_params
  params.require(:user).permit(:email, :name, :current_password, :password, :password_confirmation, :phone)
end

And the user form partial:

<div class="form-group">
  <%= f.label :password, "Current password" %>
  <%= f.password_field :current_password, class: "form-control", placeholder: "Current password" %>
</div>

But I get stack level too deep, it enters a validation loop.

What am I doing wrong?


Solution

  • This method

    def current_password
      errors[:current_password] << 'Incorrect password' unless self.current_password == self.password
    end
    

    calls itself: that's why you're getting the stack too deep error - it's stuck in a loop calling itself endlessly.

    What you're attempting to do is confusing because the current_password method is overwriting the one created by attr_accessor :current_password, and actually doing some validation rather than just returning the value. I would do this, instead:

    attr_accessor :current_password
    
    validate :current_password_same_as_password, on: :update
    
    def current_password_same_as_password
      errors[:current_password] << 'Incorrect password' unless self.current_password == self.password
    end
    

    So, here, i'm leaving the attr_accessor methods alone: they are simple read-and-write into an instance variable methods. The validation has a different method name so it's not fighting with the accessor method name.