views:

841

answers:

5

I'm adding a password reset feature to my Rails application that uses Authlogic. I was following the guide here: http://www.binarylogic.com/2008/11/16/tutorial-reset-passwords-with-authlogic/ and everything works as I'd like except for one thing: the password reset form accepts blank passwords and simply doesn't change them.

I've been searching around, and have learned that this is the intended default behavior because it allows you to make user edit forms that only change the user's password if they enter a new one, and ignore it otherwise. But in this case, I specifically want to enforce validation of the password like when a user initially registers. I've found two possible solutions for this problem but haven't been able to figure out how to implement either of them.

1) Someone asked this same question on Google Groups:

User model saves with blank password

Ben's response was to use @user.validate_password = true to force validation of the password. I tried this but I get an undefined method error: undefined method 'validate_password_field=' for #<User>.

2) There seems to be an Authlogic configuration option called ignore_blank_passwords. It is documented here:

Module: Authlogic::ActsAsAuthentic::Password::Config#ignore_blank_passwords

This looks like it would work, but my understanding is that this is a global configuration option that you use in your initial acts_as_authentic call in the User model, and I don't want to change it application-wide, as I do have a regular edit form for users where I want blank passwords to be ignored by default.

Anyone found a solution to this? I see validate_password= in the change log for Authlogic 1.4.1 and nothing about it having been removed since then. Am I simply using it incorrectly? Is there a way to use ignore_blank_passwords on a per-request basis?

+1  A: 

Maybe test the value of the parameter in the controller? (air code):

def update
  @user.password = params[:user][:password]
  @user.password_confirmation = params[:user][: password_confirmation]
  if @user.password.blank?
    flash[:error] = "Password cannot be blank"
    render :action => :edit
    return
  end
  if @user.save
    flash[:notice] = "Password successfully updated"
    redirect_to account_url
  else
    render :action => :edit
  end
end
zetetic
A: 

Apart from zetetic's solution you could do it this way:

def update
  @user.password = params[:user][:password]
  @user.password_confirmation = params[:user][: password_confirmation]

  if @user.changed? && @user.save
    flash[:notice] = "Password successfully updated"
    redirect_to account_url
  else
    render :action => :edit
  end
end

You're basically checking if authlogic changed the user record (which it doesn't if the password is empty). In the else block you can check if the password was blank and add an appropriate error message to the user record or display a flash message.

Colins
+4  A: 

This is kind of an old thread, but since it is unanswered I'll post this.

I've managed to do it a bit more cleanly than the other solutions, "helping" authlogic validations with my own.

I added this to user:

class User < ActiveRecord::Base

  ...

  attr_writer :password_required

  validates_presence_of :password, :if => :password_required?

  def password_required?
    @password_required
  end

  ...
end

You can reduce it to two lines by making an attr_accessor and using :if => :password_required (no interrogation), but I prefer this other syntax with the interrogation sign.

Then your controller action can be done like this:

def update
  @user.password = params[:user][:password]
  @user.password_confirmation = params[:user][: password_confirmation]
  @user.password_required = true

  if @user.save
    flash[:notice] = "Password successfully updated"
    redirect_to account_url
  else
    render :action => :edit
  end
end

This will have a local effect; the rest of the application will not be affected (unless password_required is set to true in other places, that is).

I hope it helps.

egarcia
I was able to use the `ignore_blank_paswords` attribute. Look at my answer for details.
KandadaBoggu
A: 
User.ignore_blank_passwords = false

Use model, not object for setting this property.

def update_passwords
  User.ignore_blank_passwords = false
  if @user.update_attributes(params[:user])
    ...
  end
  User.ignore_blank_passwords = true
end
Raimonds
Wouldn't that change it for the entire model? I only want to ignore blank passwords in one action.
Jimmy Cuadra
+3  A: 

This what I did.

class User < ActiveRecord::Base
  attr_accessor :ignore_blank_passwords

  # object level attribute overrides the config level
  # attribute
  def ignore_blank_passwords?
    ignore_blank_passwords.nil? ? super : (ignore_blank_passwords == true)
  end
end

Now in your controller, set the ignore_blank_passwords attribute to false.

user.ignore_blank_passwords = false

Here, you are working within the confines of AuthLogic. You don't have to change the validation logic.

KandadaBoggu