Advertisement
  1. Code
  2. Ruby
  3. Ruby on Rails

Getting Started With Restful Authentication in Rails

Scroll to top
Read Time: 28 min

In this article, we will use restful_authentication to add a user system to a simple Rails application. This is great for those first starting out and need step-by-step directions for using this amazing plugin. At the end of the article, visitors will be able to create an account, reset their password, login, logout, and validate email addresses.

The Basics

This portion of the tutorial is very basic. All we will do is generate a simple application that allows users to create/read/update/destroy a record containing a movie name and rating. I recommend advanced Rails developers skip to the third section which is where the restful_authentication code begins. Note: I did all of this on in OSX on a Mac, but it is not platform specific although you might need to prepend ./ to some of the commands so that Windows knows you are looking in the current directory. If you have any troubles I can help in the comments, or on twitter (@noahhendrix)

Generate the Application

First we need to have rails generate the framework code. This is done by executing "rails MyMovies" in the terminal. "MyMovies" is what I chose to name this application and you are free to use that or anything else. This command creates a lot of files and folders most of which are of no concern to us, but are required for the application to work properly. After this executes will want to change into the newly created MyMovies directory.

1
2
rails MyMovies
3
cd MyMovies

Generate the Movie Model

Now we are going to the power of Rails generators to quickly produce the code and database for our basic application. In the terminal run the command:

1
2
script/generate scaffold Movie title:string rating:integer

Here we are telling rails that we want code generated to handle a "Movie" model, which as a string title and integer rating. Notice this will generate some more files, one of which is the database migration. This is where the magic of rails really shows itself, but first we must migrate the database.

1
2
rake db:migrate

This command will setup the database and create the table with the appropriate columns. Note: Rails is smart enough to include ID, created_at, and updated_at columns for us. It will also manage these columns so we as developers never need to write code that sets these columns. Now lets look at the fruits of our labor, thats right we have written zero lines of code, but we already have a working application. Start up the server and navigate to http://localhost:3000/movies. In your terminal type:

1
2
script/server

Enhancements

You can try to create a movie and rating and see how easily everything works. The rails team really did a great job of allowing developers to quickly push code out with little effort, however that code is only a starting point. It is up to us the developers to make it our own and add the additional features and customizations for users. A good place to start is decide if there are any restrictions we will place on our model. For this example I decided we would require that the user only be able to rate the movie between 1 and 5 stars. Though there are others like making sure they enter a movie title and that the rating is a number. This is how handled in the movie model file.

1
2
# app/models/movie.rb
3
4
validates_presence_of :title, :rating
5
validates_numericality_of :rating, :greater_than_or_equal_to => 1, :less_than_or_equal_to => 5

The syntax used in Rails is often verbose, but quite descriptive also. However a positive side effect is we never have to guess what the code we write means. We are telling rails before it saves to the database to verify that both title and rating are set, and as a further restriction rating must be a number between 1 and 5. Notice in the images below we get built in error reporting by default in rails.

User Interface Awareness

Even as developers we are not exempt from considering the interface of applications we develop. Users need to immediately understand the purpose of any information displayed to them. In our application we have them set the rating, but we never say it needs to be an integer between 1 and 5. At first a user might enter a string such as "good". We could put a label beside the text box that lists our requirements, but we can go a step further and explicitly let them choose between the options we want in a radio button format. Part of the Model View Controller (MVC) methodology of rails tells us that this is a view alteration and it is located within the views directory. First we must remove the line that creates the text box and its label, around line 11 in my code. Look for:

1
2
# app/views/movies/edit.html.erb
3
# app/views/movies/new.html.erb
4
5
<%= f.text_field :rating %>

Alright now the new code below must be added to both the new and edit files because both contain forms where the model is modified.

1
2
# app/views/movies/edit.html.erb
3
# app/views/movies/new.html.erb
4
5
Rating<br />
6
<%= f.radio_button  :rating, 1 %> <%= f.label :rating_1, "1" %>
7
<%= f.radio_button  :rating, 2 %> <%= f.label :rating_2, "2" %>
8
<%= f.radio_button  :rating, 3 %> <%= f.label :rating_3, "3" %>
9
<%= f.radio_button  :rating, 4 %> <%= f.label :rating_4, "4" %>
10
<%= f.radio_button  :rating, 5 %> <%= f.label :rating_5, "5" %>

Alright now lets look at this code closely. First we give the the rating label to tell the user what the radio buttons are for, then we move in the actual buttons. The first parameter for the radio_button method is the model attribute we are working with and the second is the value to send the server on submit. After each button we have a label to tell the user what rating the button corresponds to, the reason we pass in :rating_# is because when rails generates the radio button it gives it an id of attribute_value, so our labels hook into those values. Here is the what the new form looks like with the radio buttons, notice that when you edit a movie Rails automatically selects the radio button that corresponds to the previous rating from the database.

This concludes the first part. In the previous section we got our movie rating application off the ground using the power of Rails generators and some basic view code. In the next section we will make our application a little more visually appealing by adding some graphics and CSS code to spruce up the views.

Styling

Layouts

First we will look at layouts. Not getting into too much detail layouts hold the elements on a page that do not change across the application. For instance header, footer, and navigation typically (and rightfully so) stay consistent across a website. Even though our application is fairly trivial, a layout is important for consistency.

Our goal is to include a logo, background image, and centered container for content on each page. First we need to create our application wide layout page. Rails is kind enough to create a model wide layout file, but this will not apply to the user pages when we get to that part so we need to change it to a global layout. This is easily done by renaming app/views/layouts/movies.html.erb to app/views/layouts/application.html.erb. Now we need to open the file and make a few changes. First lets wrap all of our content in a div called pagewrap. This is nice, because it gives us a bit more control in CSS than we normally get with just body. This can be done by simply including the opening just below the body, and closing it right above the body closing.

1
2
# app/views/layouts/application.html.erb
3
...
4
<body>
5
6
  <div id="pagewrap">
7
8
    ...
9
10
  </div>
11
12
</body>
13
...

While we are in this file lets go ahead and include a CSS file we will create next. Find the line (9 in my file) that says stylesheet_link_tag 'scaffold' and append a comma and 'style' to it so it looks like this:

1
2
# app/views/layouts/application.html.erb
3
4
<%= stylesheet_link_tag 'scaffold', 'style' %>

This is a helper method provided by rails that creates the <link> tag for us, and links to the style.css file in our stylesheets directory. In public/stylesheets create a file called style.css. Because this is not really a CSS tutorial I will only graze over the declarations.

1
2
# public/stylesheets/style.css
3
4
html, body {
5
  background-image: url(/images/bg_body.jpg);
6
}
7
8
#pagewrap {
9
  -moz-border-radius: 10px;
10
  -webkit-border-radius: 10px;
11
12
  margin: 0 auto;
13
  padding: 10px;
14
  width: 900px;
15
16
  /* logo */
17
  background: white url(/images/logo.png) no-repeat;
18
  padding-top: 72px;
19
}

I am applying a background image to the body tag, so that is will cover the entire page. The pagewrap element we created earlier is given rounded corners (only in Safari and Firefox sorry IE), centered using margin, some padding to push content in, 900px width, and a non-repeating background image that is our logo. The content is pushed down 72px to accommodate the logo, kind of a hack but just an easy way to throw the logo on the page. Unfortunately I can't distribute the background image or logo because they were created using pieces from a template I bought on ThemeForest.net. But there doesn't that look so much better now?

Adding Stars

The index page is pretty lame as-is because it simply list the title of the movie and an integer for the rating. Let's add some CSS magic to make that a little more pretty. First lets update app/views/movies/index.html.erb, by changing the table cell that holds the rating, on line 12. We will wrap the rating in a div with a special class containing the number of stars to show. We also make use of the pluralize helper method in Rails which will output a number passed to it and append a word after the number making it plural if necessary.

1
2
# app/views/movies/index.html.erb
3
4
<td><div class="star-<%=h movie.rating %> rating"><%=pluralize movie.rating, "Star" %></div></td>

Alright now lets create the CSS code necessary. Note: I did not include the image in the HTML markup so that if a user has CSS disabled they won't see any stars just something like "3 Stars."

1
2
# public/stylesheets/style.css
3
4
.rating {
5
  background: url(/images/stars.png) no-repeat;
6
  height: 26px;
7
  overflow: hidden;
8
  text-indent: -1000px;
9
}
10
.star-5 { width: 115px; }
11
.star-4 { width: 92px; }
12
.star-3 { width: 69px; }
13
.star-2 { width: 46px; }
14
.star-1 { width: 23px; }

We apply a non-repeating background image of 5 stars to all the rating divs, and then change the width (in 20% increments) to allow hiding of stars. We also push the "# Stars" text off the page with a negative text-indent, since the stars are plain enough language to not require actual words too.

Optional: Removing The Show Page

One last thing I did was remove links to the show page. It seemed a bit redundant to include it since the index page showed all the relevant information. You can do the same by opening app/views/movies/index.html.erb and removing line 13, the link_to the show page. You also need to open app/controllers/movies_controller.rb and update lines 48 and 65 call to redirect_to, make the parameter movies_url instead.

The restful_authentication Plugin

Now that we have made it through the basics, lets add users! The purpose of the first half of this tutorial was to simulate the legacy application you have already created. So from this point on you can easily apply what we learn to any application you create. The great thing about the restful_authentication plugin is that it abstracts the authentication logic away from the other models and makes it fairly quick and painless to implement.

Install restful_authentication

First things first we need to install the restful_authentication plugin, stop the server by pressing CTRL+C, if you have it running. The GitHub page for restful_authentication has instructions on installing, but here is the reader's digest version:

1
2
script/plugin install http://github.com/technoweenie/restful-authentication.git restful_authentication

Passing in the second restful_authentication tells rails we want to rename the plugin folder to that instead of restful-authenticatoin. The reasoning is explained under the header of Installation for those who are interested. Alright now this commands basically goes out to the server and fetches all the restful_authentication files and copies them to your server. It also creates a generator script that we can run to create the necessary controllers, models, and views in our application folder.

1
2
script/generate authenticated user sessions --include-activation

Using the authenticated generator we say we want to call the model that handles user information user, and the model that handles the sessions called sessions, easy enough right? But why do we separate these? If you really think about about it registering a user and retrieving their information is similar to authenticating them, but really it is very different too. One is storing long term login information on the user and the other is more temporary and is erased once they logout. So it really makes a lot of sense to split them up in our design. We also pass in the include-activation flag so that it generates the necessary mailers for activating user accounts through email.

Alright that now we have the files in the application folder, but we are not quite done in the terminal. The generator above also created some migrations for us that creates users and sessions tables in our database, but now we need to associate users with their movie records. Let's use the migrations generator to add a user_id column to the movies table.

1
2
script/generate migration add_user_id_to_movie user_id:integer

Rails 2.0 brought some really nifty automation for the migrations generator. Because of the name schema add_user_it_to_movie rails will assume what we mean and create a schema that does just that. So all we are left to do is run

1
2
rake db:migrate

and our database is up to date. If you want to see the migrations file it created to get a feel of what we did you can check out app/db/migrate and look for the add_user_id_to_movie.rb file. Ok, we are all done in the terminal for now!

Associating Users and Movies

In order for a user to "own" a movie record we must tell rails that they do. This is down through associations declared in the models. First lets update the user model created by our generator, app/models/user.rb. I usually add the following code right above the first method declaration, activate in this case.

1
2
#app/models/user.rb
3
4
has_many  :movies

This is pretty straight-forward, we are telling rails that user has many movie records associated with their account. Now lets inform the movie model of the associate in app/models/movie.rb. Add this code right below our validation methods from earlier.

1
2
#app/models/movie.rb
3
4
belongs_to  :user

Similar to above we just are saying that each individual movie record belongs to a user. Now the beauty of these associations is Rails now assumes our database has a user_id column in the movies table, which we of course already do. That is all the work we have to do no foreign keys, no custom code it is just given to us out of the box more or less.

Routes

This is more of a user experience modification, but something all applications should include. Currently if a user wanted to sign up the url is example.com/users/new or if they wanted to login it is example.com/sessions/new, a bit verbose in my opinion. So we will add some custom routes in config/routes.rb, mine went in around line 8.

1
2
# config/routes.rb
3
4
map.activate '/activate/:activation_code', :controller => 'users', :action => 'activate'
5
map.signup '/signup', :controller => 'users', :action => 'new'
6
map.login '/login', :controller => 'sessions', :action => 'new'
7
map.logout '/logout', :controller => 'sessions', :action => 'destroy'

As you can see here we are declaring active, signup, login, and logout for their obvious counterparts. This will make our URLs more sensible and easy to remember. Notice that activate requires a string passed in which will be the activation code we send out in emails to users to validate email addresses.

Validating Email Addresses

It is common practice with many websites to require users to validate email addresses by clicking a link in an email sent to the address they provide. In other languages and frameworks this is somewhat difficult, but the restful_authentication plugin and rails mailers makes this advanced functionality very easy. However before we can send out emails we need to tell rails how to authenticate with our SMTP server. Now this varies from host to host, and you will need to contact your host to determine how to fill in these settings. Note: You will need to create the file config/initializers/mail.rb first.

1
2
# config/initializers/mail.rb
3
4
ActionMailer::Base.delivery_method = :smtp
5
ActionMailer::Base.smtp_settings = {
6
	:address => "mail.example-domain.com",
7
	:port => 25,
8
	:domain => "www.example-domain.com",
9
	:authentication => :login,
10
	:user_name => "user@example-domain.com",
11
	:password => "secret"
12
}

While we are setting up defaults we should define the URL of our website we will use in all our emails. You might wonder why we would do this, and reason is to future-proof our application. For instance, while we are developing locally the domain is localhost:3000/, and presumably our production domain is different. If at some point in the future the production URL changes we can update it in one place and not worry about other missing other changes. But where do we site these defaults? Rails created some configuration files that are loaded depending on the environment we are in: development, testing, or production. Starting with development we must modify config/environments/development.rb, at line 19.

1
2
# config/environments/development.rb
3
4
SITE_URL  = "localhost:3000"

And likewise in config/environments/production.rb at line 30.

1
2
# config/environments/production.rb
3
4
SITE_URL  = "noahhendrix.com"

Now we need to update the user_mailer model file, app/models/user_mailer.rb, to use our newly create SITE_URL variable. These changes need to be made on lines 6, 13, and 20 remove YOURSITE and replace it with #{SITE_URL}. On line 19 you need to update the email address to your own.

Here is what the email asking them to activate their account looks like.

They also receive an email once the account is activated

Updating our Controllers

The movies controller that rails created for us was helpful before we added a user system, but now we want to only allow users to cretate, read, update, and destroy their own movies and prevent them from seeing other users' movies. This is done by modifying the movies controller and having it add a user_id column restriction on all queries to the movies table.

We are going to update a bunch of lines and because they are so pretty much the same we won't go over them individually. Essentially we are telling the controller to restrict all finds to the current_user variable (i.e. add "WHERE user_id = ##" to the database queries). The current_user variable is something restful_authentication gives us to use in our controller for this specific reason. I've included the approximate line numbers, but if they are different for you then know that we are only modifying the methods: index, show, edit, create, update, and destroy. Note: the variable Movie is changed to movies because we are accessing it through the user which comes from when we said a user has many movies.

1
2
# app/controllers/movies_controller.rb
3
4
Line 8: @movies = current_user.movies
5
Line 20: @movie  = current_user.movies.find(params[:id])
6
Line 42: @movie  = current_user.movies.find(params[:id])
7
Line 49: @movie  = current_user.movies.create(params[:movie])
8
Line 67: @movie  = current_user.movies.find(params[:id])
9
Line 85: @movie  = current_user.movies.find(params[:id])

While we have this file open at the top (line 2) we need to add a before filter. This tells rails that before it runs any of the methods below it needs to first run a method we provide.

1
2
# app/controllers/movies_controller.rb
3
4
before_filter :login_required

The method :login_required is provided by the plugin and basically will check if the user is logged in, and if not will redirect them to the login page.

Alright not too bad, right? We have a few last things to clean up before the plugin is fully functioning. In app/controllers/sessions_controller.rb and app/controllers/users_controller.rb there is an include statement that need to be removed, and added to app/controllers/application_controller.rb. This line includes the necessary back end files that the plugin uses to manage the users and sessions. I put mine at line 5.

1
2
# app/controllers/application_controller.rb
3
4
include AuthenticatedSystem

If you curious where it is pulling this file from, you can find it in lib/authenticated_system.rb.

Adding Password Reset

Updating The Users Controller

We need to add two methods to the users controller, app/controllers/users_controllers.rb, that will take care of the form for users to reset their password. However, before we dive into code lets take a second to discuss our plan. We want to allow a user to click a link that says they forgot their password. They will then be taken to a page asking what email address they used when creating their account, once they submit that we will fire off an email with a link containing a special hash that will they can click. Once they open the link in their email they will have a form to choose a password, and confirm it.

Alright lets look at each function individually starting with forgot.

1
2
# app/controllers/users_controller.rb
3
4
def forgot
5
  if request.post?
6
    user = User.find_by_email(params[:user][:email])
7
8
    respond_to do |format|
9
      if user
10
        user.create_reset_code
11
        flash[:notice] = "Reset code sent to #{user.email}"
12
13
        format.html { redirect_to login_path }
14
        format.xml { render :xml => user.email, :status => :created }
15
      else
16
        flash[:error] = "#{params[:user][:email]} does not exist in system"
17
18
        format.html { redirect_to login_path }
19
        format.xml { render :xml => user.email, :status => :unprocessable_entity }
20
      end
21
    end
22
23
  end
24
end

Here is the action referring to the form where they enter their email address. First we check to see if they have submitted the form via a post request, if not we do nothing because we are waiting for the form to be submitted. Once we have post data we find the users information using the provided email address to make sure they exist. We are using a respond_to format block so that we can respond to both xml and html requests. In this tutorial we won't use the XML format, but it is good to provide it for web services. Now you will see we have a simple if statement saying if user is not nil (implied) we want to run the method create_reset_code and notify the user via a flash method that they need to check their email for a reset link. If the user doesn't exist we let them know that as well.

Alright now lets look at the reset action, the one they see after they click the link in their email.

1
2
# app/controllers/users_controller.rb
3
4
def reset
5
  @user = User.find_by_reset_code(params[:reset_code]) unless params[:reset_code].nil?
6
  if request.post?
7
    if @user.update_attributes(:password => params[:user][:password], :password_confirmation => params[:user][:password_confirmation])
8
      self.current_user = @user
9
      @user.delete_reset_code
10
      flash[:notice] = "Password reset successfully for #{@user.email}"
11
      redirect_to root_url
12
    else
13
      render :action => :reset
14
    end
15
  end
16
end

First we find the users information through the reset code, to make sure that they exist in the database. If there is user data found we log them, and present the form to reset their password. Next we check to see if they are just loading the form or if they have already submitted it. If there is post data we update the password to the one they supplied. We set the current_user to that user, and remove the reset code so no one else can use the link to change their password. We give them a flash notice that confirms the reset. If we can't update the password we send them back to the password page with errors.

Updating the User Model

Some of this is pretty confusing because we haven't fully implemented some methods we used such as: create_reset_code, recently_reset?, and delete_reset_code. We will put these in the user model, app/models/user.rb, right above the word protected towards the bottom.

1
2
#app/models/user.rb
3
4
#reset methods
5
def create_reset_code
6
  @reset = true
7
  self.attributes = {:reset_code => Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )}
8
  save(false)
9
end
10
11
def recently_reset?
12
  @reset
13
end
14
15
def delete_reset_code
16
  self.attributes = {:reset_code => nil}
17
  save(false)
18
end

In the create_reset_code function we are setting an instance variable @reset to true so that our application can keep remember that they are have recently reset their password. Then we are setting a reset_code in the database (which we have yet added a column for) to a hash of the current time to make it unique. Then we save that reset_code to the database, the false parameter tells rails to ignore validations which we can do because we set the code ourselves not users.

The recently_reset? method is just so we can check if the @reset variable is true or false. And finally the delete_reset_code does exactly what it's name infers, remove the reset code from the database.

Creating the Forgot and Reset Views

We've talked about the forms the user needs to fill out in order to reset their password, lets go a head and create those. First in the directory app/views/users/ called forgot.html.erb.

1
2
# app/views/users/forgot.html.erb
3
4
<%= error_messages_for :user %>
5
6
<% form_for :user do |f| -%>
7
  <p>
8
    Reset Password Request
9
  </p>
10
11
12
  <p>
13
    <label for="email">Email</label><br />
14
    <%= f.text_field :email %>
15
  </p>
16
17
18
  <p>
19
    <%= link_to "Cancel", login_path %>
20
    <%= submit_tag 'Submit' %>
21
  </p>
22
<% end -%>

This is a pretty generic form, where we ask the user for their email. Now we need to create the form to reset the password in the same directory as above create a file called reset.html.erb.

1
2
# app/views/users/reset.html.erb
3
4
<%= error_messages_for :user %>
5
6
<% form_for :user do |f| -%>
7
  <p>
8
    Pick a new password for <span><%= @user.email %></span>
9
  </p>
10
11
  <p>
12
    <label for="password">Password</label><br />
13
    <%= f.password_field :password %>
14
  </p>
15
16
  <p>
17
    <label for="password">Confirm Password</label><br />
18
    <%= f.password_field :password_confirmation %>
19
  </p>
20
21
22
  <p>
23
    <%= submit_tag 'Reset' %>
24
  </p>
25
<% end -%>

Emailing the User A Reset Link

Alright now that we have the forms setup lets modify the user mailer class to send the reset links out. Since we are working with views lets start there. If a traditional view translates roughly to a webpage then a mailer view would translate to an email. Basically this is the basic layout of the email we want to send the user, leaving spots for variables our controller will provide. The file we are going to create is app/views/user_mailer/reset_notification.html.erb, and the insert this code:

1
2
# app/views/user_mailer/reset_notification.html.erb
3
4
Request to reset password received for <%= @user.login %>
5
6
Visit this url to choose a new password:
7
8
<%= @url %>
9
(Your password will remain the same if no action is taken)

This is all pretty generic mark up, notice that we have a space for the url and the users login name. We also tell them that if they do nothing the password will not be changed. Now lets go into app/models/user_mail.rb and create the reset_notification method, this is where our view gets the user login and reset url variables. Insert this code somewhere after the activation method, but above protected.

1
2
# app/models/user_mailer.rb
3
4
...
5
def reset_notification(user)
6
  setup_email(user)
7
  @subject    += 'Link to reset your password'
8
  @body[:url]  = "#{SITE_URL}/reset/#{user.reset_code}"
9
end
10
...

Here we are doing a few things. First we call the setup_email method that is declared under protected (protected means only this class can call that method), which is some generic email setup things. We append a string to the subject to help the user identify the purpose of the email from the subject. Next we set that URL we talked about earlier notice we are using the #{SITE_URL} variable we set earlier. The reset_code variable comes from the user model that we set earlier using the create_reset_code method, remember that?

One more model that we need to update, app/models/user_observer.rb. Basically this is where we say to send that email if the @reset variable is true. These methods are executed whenever the user is interacted with, in this case after we save it to the database we want to check if they need to get a reset email. After the line that sends the activation email add this code.

1
2
# app/models/user_observer.rb
3
4
...
5
UserMailer.deliver_reset_notification(user) if user.recently_reset?
6
...

Alright lets update one more file before we move into the terminal to add the reset_code column. Remember that URL the user is emailed? Well we need to set that up in the routes file, config/routes.rb. On the line below where we setup the logout route add these two lines:

1
2
# config/routes.rb
3
4
map.forgot    '/forgot', :controller => 'users', :action => 'forgot'
5
map.reset     'reset/:reset_code', :controller => 'users', :action => 'reset'

This is just like the above routes, we are mapping friendly URLs to the proper controllers and actions. Alright, lets move into the terminal. So now we are going to use the same migration generator we used for adding user_id to the movies table. So this code will look really familiar.

1
2
script/generate migration add_reset_code_to_user reset_code:string

Don't forget to run

1
2
rake db:migrate

to update the database.

Cleaning Up Loose Ends

Setting the Default Root Page

First we need to delete the file public/index.html. This is the page and will override the default controller we will set. Next open config/routes.rb, and uncomment line 46 (the one starting map.root). Change welcome to movie, this tells rails to render the movie controller as our default if someone navigates to localhost:3000/ or the root of our production domain.

Adding Sign Up, Reset, and Logout links

Alright now we get to move to the views. in app/views/sessions/new.html.erb we should remove lines 8 and 11 to allow our users to remember their session so they do not have to re-login each time they visit. On line 11 there is a paragraph tag we need to add sign up and forget passwords links within that element.

1
2
# app/views/sessions/new.html/erb
3
4
<%= link_to 'Sign Up', :signup %>
5
<%= link_to 'Forgot Password?', :forgot %>

Users are now able to easily sign up, login, or reset their password but we need to include a logout link once they are logged in so they can end their session. We will do this in the application layout file, app/views/layouts/application.html.erb, so that it appears on all pages. I added mine right above the flash messages, but below the pagewrap div.

1
2
# app/views/layouts/application.html.erb
3
<div class="user">
4
  <%= link_to "Logout", :logout unless !logged_in? %>
5
</div>

Notice that we say to include the link unless logged_in? is false, logged_in? is a helper the plugin provides that returns true if the user is logged in and false if they are not, and of course we only want to the link if they are actually logged in.

While we are here lets add another flash message type, alert. This is to display errors to the user passed in from the controllers. Below the existing one add this line.

1
2
# app/views/layouts/application.html.erb
3
4
<p style="color: red"><%= flash[:alert] %></p>

Preventing Auto-Login on Sign Up

You might have noticed that when you sign up the application logs you in without first requiring the email verfication, although it prevents any subsequent logins. This is something included in the default user controller where if the user passes validation they are logged in by setting current_user to the user model just created. In our application this is a bug because we want the user to first authenticate their email address. We can fix this behavior in app/controllers/users_controller.rb around line 16 we need to remove, or comment out, where it sets current_user = @user.

Also as a helpful hint to users we should modify line 17 where it tells the user they successfully signed up to something that instructs them to check their email.

1
2
# app/controllers/users_controller.rb
3
4
flash[:notice] = "Thanks for signing up! Please check your email to activate your account."

Alright that is all we need to do for our basic user authentication. I hope this has helped as a step-by-step walkthrough of how to install and use restful_authentication in your rails application. I know that this is very simplistic so post any desired customizations in the comments, or contact me on twitter (@noahhendrix) and I will try to address them. Thanks for reading!


Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.