I’ve been getting emails asking me how to reset passwords with Authlogic, or how to confirm accounts. In this tutorial I’ll cover resetting passwords, since it is more complex, but after reading this tutorial there is no reason why you couldn’t set up account confirmation as well. In fact, my next tutorial will cover just that.
You are going to read a tutorial on how to reset passwords the RESTful way. I am going to pick up where I left off on the Authlogic basic setup tutorial, so if you have not read that I highly recommend doing so.
Want to see it in action before you start? Check it out for yourself:
Before we begin, let me walk you through the basic process of resetting a password as I see it:
That seems pretty simple, right? So let’s get started…
Before we start I want give you some helpful / related links:
I am going to pick up from the Authlogic basic setup tutorial, so I am assuming you are familiar with Authlogic and the basic setup.
With this tutorial I am introducing a new field in your database called perishable_token. Authlogic will take care of maintaining this for you. Here is how:
Generate your migration:
$ script/generate migration add_users_password_reset_fields
Now update the migration:
class AddUsersPasswordResetFields < ActiveRecord::Migration def self.up add_column :users, :perishable_token, :string, :default => "", :null => false add_column :users, :email, :string, :default => "", :null => false add_index :users, :perishable_token add_index :users, :email end def self.down remove_column :users, :perishable_token remove_column :users, :email end end
Migrate your database:
$ rake db:migrate
When adding the email field Authlogic will notice this and validate it for you, making sure the email is unique and a valid email address. If you wish to disable this just pass the :validate_email_field => false option to acts_as_authentic. You can also have it ignore the email field all together by passing the :email_field => nil option.
We need to know if users lost their password, why not create another resource for this?
$ script/generate controller password_resets
Let’s fill out this controller with some actions (I will explain them below):
Now update your routes:
# app/controllers/password_resets_controller.rb class PasswordResetsController < ApplicationController def new render end def create @user = User.find_by_email(params[:email]) if @user @user.deliver_password_reset_instructions! flash[:notice] = "Instructions to reset your password have been emailed to you. " + "Please check your email." redirect_to root_url else flash[:notice] = "No user was found with that email address" render :action => :new end end end
What did I just do?
The deliver_password_reset_instructions! is a method I added, you can call it whatever you want. All that it does is reset the password reset token and send an email.
Here is what I did in my own application:
# app/models/user.rb class User < ActiveRecord::Base def deliver_password_reset_instructions! reset_perishable_token! Notifier.deliver_password_reset_instructions(self) end end
The reset_perishable_token! is a handy method Authlogic gives you. It basically resets the field to a unique “friendly” token and then saves the record.
My Notifier action looks like this:
# app/models/notifier.rb class Notifier < ActionMailer::Base default_url_options[:host] = "authlogic_example.binarylogic.com" def password_reset_instructions(user) subject "Password Reset Instructions" from "Binary Logic Notifier " recipients user.email sent_on Time.now body :edit_password_reset_url => edit_password_reset_url(user.perishable_token) end end
Then the email looks like:
# app/views/notifier/password_reset_instructions.erb A request to reset your password has been made. If you did not make this request, simply ignore this email. If you did make this request just click the link below: If the above URL does not work try copying and pasting it into your browser. If you continue to have problem please feel free to contact us.
You can do the above any way you want. I actually recommend creating a text and html version of this email, but for the sake of brevity I only included the text version.
Once they get that email and click the link in it, it needs to take them somewhere. So let’s add some methods to our PasswordResetsController:
# app/controllers/password_resets_controller.rb before_filter :load_user_using_perishable_token, :only => [:edit, :update] def edit render end def update @user.password = params[:user][:password] @user.password_confirmation = params[:user][: password_confirmation] if @user.save flash[:notice] = "Password successfully updated" redirect_to account_url else render :action => :edit end end private def load_user_using_perishable_token @user = User.find_using_perishable_token(params[:id]) unless @user flash[:notice] = "We're sorry, but we could not locate your account. " + "If you are having issues try copying and pasting the URL " + "from your email into your browser or restarting the " + "reset password process." redirect_to root_url end end
What did I just do?
Now we just need to make sure the user is logged out when accessing these methods. Modify your before filters in your PasswordResetsController to look like:
Instead of cluttering up this tutorial with a bunch of basic views, I left them out. There is nothing crazy going on in the views, nor do I really need to explain anything. If you noticed in the helpful links section I have a live example of this tutorial.
If you care, here are my thoughts behind this tutorial and ultimately why I recommend resetting passwords this way…
My goal with Authlogic was to stay away from generating code and give you the proper tools so that you could easily and effectively write the code yourself. If you noticed, in this tutorial, all that we really did was add a simple PasswordResetsController. Most of this tutorial was explaining what was going on, so you could understand what you were doing. I can’t write that controller for you, because it is application specific. I want to keep the authentication logic in Authlogic and your application logic in your application. The tutorial above produces simpler and cleaner code than a generator. The most important part is that you understand what is going on and it works the way you want. I am basically laying out tools for you to use and explaining them. You get to use them how you wish. There is no “Surprise! Here are hundreds of lines of code, hope you like it”. If you want to change passwords a different way, go for it, you now know how Authlogic can assist you in your journey to resetting passwords.
Lastly, I know there are a few other common ways to reset passwords, so I will address those and why I decided against them: