Model password validation

Hi,
I’m doing something that seems so simple, but I can’t figure it out.
I’m writing a change password function for the “my account” section of
a site. I want the user to enter their old password and their new
password (and a confirmation), and then check that the old password
matches before updating the record.

However, I don’t know how to keep the old password around in order to
do the validation. Because the validations happen in the model, the
attributes are wiped out when assigning the new password value to the
object.

I have to admit that I’m having trouble with validations generally.
Database stuff is fine and relatively easy, but anything not backed by
the database and I’m at a loss.

Does this make sense? How do you handle this?

Cheers,
Jord

Jordan E. wrote:

Hi,
I’m doing something that seems so simple, but I can’t figure it out.
I’m writing a change password function for the “my account” section of
a site. I want the user to enter their old password and their new
password (and a confirmation), and then check that the old password
matches before updating the record.

However, I don’t know how to keep the old password around in order to
do the validation. Because the validations happen in the model, the
attributes are wiped out when assigning the new password value to the
object.

I have to admit that I’m having trouble with validations generally.
Database stuff is fine and relatively easy, but anything not backed by
the database and I’m at a loss.

Does this make sense? How do you handle this?

Validation is done in model, it provides means to check data
consistency.

Verifying if user is allowed to do something with model is a controller
responsibility and should happen prior to updating model. This includes
checking of old password to verify user.

In my view I have:

Old password: <% password_field_tag %>
New password: <% password_field(:user, :password) %>
New password (confirm): <% password_field(:user, :password_confirmation)
%>

and in my controller:

if User.authenticate(current_user, params[:password]) == current_user
current_user.update_attributes(params[:user])
else
flash[:error] = ‘Please provide valid current password’
redirect_to :action => ‘change_password’
end

Controller first checks if user is allowed to change password in if
clause. Then model takes care of checking if password is confirmed -
validations kick in during update_attributes.

As you can see those are two distinct steps performed by two different
entities.

Model is good for checking data MODEL integrity. Controller is good for
flow CONTROL and security :slight_smile:

Cheers,
Bragi

Sorry… gmail’s being a pest. I tried to post an example but it got
cut
off. The solution provided by Lucasz is a great one. However, I still
like
to have that sort of stuff in the model instead of the controller
because I
may have various ways for a password to be changed.

No no no.

I have to disagree. This ‘change password’ should be called in the
model.

However, I’d refactor it a bit.

view:

Old password: <% password_field_tag %>
New password: <% password_field(:user, :password) %>
New password (confirm): <% password_field(:user, :password_confirmation)
%>

controller

def change_password

end

Very nice.

Thanks both for your suggestions. I’ve managed to come up with
something that works now.

I’ve added a virtual attribute to take the current password from the
user and this is only validated when a password is changed. So, now I
have something like this:

Model:

class Customer < ActiveRecord::Base
attr_accessor :current_password
validates_presence_of :current_password, :on => :update, :if =>
:password_change?

def change_password(attributes)
  @password_change = true
  self.attributes = attributes
  save
end

private

    def validate_on_update
        if password_change?
            errors.add(:current_password, "is incorrect") unless

encrypt(current_password) == crypted_password
end
end

    def password_change?
        @password_change
    end

end

Controller:

class AccountController < ApplicationController
def change_password
@customer = @current_customer
if request.post?
if @customer.change_password(params[:customer])
flash[:notice] = “Your password has been changed”
end
end
end
end

Thanks for your advice.

Cheers,
Jord