Table of Contents

View Screencast (Quicktime)
Right-click and choose Save As to save file to your computer


Sign Up Now!

If you aren’t already receiving our course lessons via email, sign up now to be sure you don’t miss anything.

Every few days, we’ll send you an email with a link to the next episode, plus a list of additional resources for advancing your knowledge.

There’s no cost and no obligation. And we’ll never share your email address with any third party.


We’ll send you the first lesson right away.


Want to help spread the word? We’d be grateful if you would include a link to the course in your blog, web site, or emails.

Adding User Authentication

17 comments

Goals

In this lesson, we add user authentication so only logged-in users can access the page controller and modify the contents of the site.

Setup

We begin with the code with which we ended Lesson 10. These zip files contain the beginning and ending states of the code:

Page title cleanup

First, we need to take care of a little problem we created for ourselves with the way we handled the page title metadata in the previous lesson.

We’re going to add a couple more admin controllers in this lesson, and with the approach used in the previous lesson, we’d need to specifically set the @pagetitle instance variable in each of those controllers. For now, we’re going to replace the existing setting of the title tag in the application layout with the following:

<title><%= @pagetitle || (@page && @page.title) || "Learning Rails Sample Application" %></title>

This line sets the pagetitle in one of three ways:

  1. If there is an instance variable @pagetitle, use that
  2. If not, then use @page.title, if there is a @page object
  3. If there’s neither a @pagetitle nor a @page object, use the fixed string

This is a little messy, and in a later lesson we’ll fix it in a more elegant way.

Install plugin

The plugin we’re going to use is called restful_authentication. You can find plugins by searching on Google or on various Rails plugin directory sites. One good site is AgileWebDevelopment. From this site, you can get the URL for the repository where the plugin code is located.

To install restful_authentication, enter the following line in a terminal at the root of your application:

script/plugin install http://svn.techno-weenie.net/projects/plugins/restful_authentication/

You can view the readme in vendor/plugins/restful_authentication to learn more about it.

Set up the plugin

This plugin provides a generator of its own to help us set things up, so let’s run it:

script/generate authenticated user sessions

In this command, “authenticated” is the name of the generator; “user” is the name of the model that will store user names and passwords; and “sessions” is the name of the controller that will manage user sessions.

This generator creates a migration for us, but we need to run the migration:

rake db:migrate

Finally, to make the methods provided by this plugin available in your controllers, you need to add the following line to the file controllers/application.rb:

include AuthenticatedSystem

The application controller is “mixed in” to all other controllers, so any code you put here is available to all controllers. So by putting the “include” statement for the authenticated system here, you’re effectively adding that code to every controller.

Creating a user

Before we can have log-in, we need to have users, so let’s add some user management.

The authenticated generator we ran in the previous section gave us a users controller and a view for creating users, so browse to //localhost:3000/users/new and create a login for yourself.

The generator also created a sessions controller, which is what handles the actual log in and log out operations. Logging in is creating a new session, and logging out is destroying a session. It’s convenient to have shortcuts we can use to refer to these, so let’s add some named routes. Add the following lines to the top of the config/routes.rb file:

map.logout '/logout', :controller => 'sessions', :action => 'destroy'
map.login '/login', :controller => 'sessions', :action => 'new'

This gives us two things. The text ’/logout’ and ’/login’ makes those simple URLs work. And the words after the “map.” provide shortcuts we can refer to anywhere in our code when we want to generate that URL, using either login_path, for example, to generate a relative URL, or login_url, to generate a full, absolute URL.

Let’s add a log-in button to the navigation bar. Open views/layouts/application.html.erb, and add this code to the end of the list of links that creates the nav bar:

<li>
   <% if logged_in? %>
      <%= link_to "Log Out", logout_path %>
   <% else %>
      <%= link_to "Log In", login_path %>
   <% end %>
</li>

The restful_authentication plugin provides us with a “logged_in?” method that we can use to determine if any user is logged in. If someone is logged in, then we display a log out link; if not, we display a log in link.

Using authentication to protect the admin pages

Now we have our entire authentication system in place, but we haven’t actually used it to require login for any pages. We need to invoke the authentication feature for the pages for which we want to require log-in.

Open the file controllers/pages_controller.rb, and add the following line:

before_filter :login_required

“login_required” is another method provided for us by the restful_authentication plugin. The before_filter causes this method to be executed before any action in the controller.

Now do the same for users_controller.

Take care of page titles

Just as in the previous lesson, we need to set the @pagetitle instance variable in the user and session controllers, since these pages aren’t generated from page objects.

Wrapping up

Try accessing localhost:3000/pages, and you should be presented with a login screen. Log in with the credentials created in the previous step, and you should see the Log In button in the nav bar change to Log Out.

Try creating a new user by accessing localhost:3000/users/new. You shouldn’t be able to create a new user without being logged in. (If you didn’t create a user before adding the login requirement to the users controller, you can comment that line out temporarily.)

Coming up

In our next lesson, we’ll make a variety of small enhancements to add some polish and additional capabilities to our content management system.


Add a Comment

Have a comment or question about this lesson? Add it here.






Comments on This Lesson

From: Henry       Date: 07/01/08 09:09 AM

Subject: Login oddity

After completing the code about and attempting to access “pages”, I now get an IE “web login” dialog, which is not unexpected (??). However, the oddity is that if you cancel the login dialog, I now get prompted to open/save/cancel a Shockwave file named “new.” If I try to either open or save, I get an error. Is this expected behaviour at this point in the tutorials?

From: Christopher Haupt       Date: 06/03/08 09:09 AM

Subject: RE: getting the plugin

Now that Rails 2.1 is out, it includes a fixed up version of script/plugin that can install from either Subversion or git. If you are able, update your Rails gem to 2.1 (Mac: sudo gem update rails, Win: gem update rails) and you can start using script/plugin install again.

Of course, you’ll need to have git installed too. On Mac, if you don’t have it already, you can use the MacPorts version. (My articles on installing Rails on Mac details MacPorts setup itself.) On Windows get the full msysgit package from the download area.

The other ideas here work (e.g. clone the plugin repository, download a tar, etc), but what you have to be careful of is that many plugins require that you run their “install” script to properly get set up. This process can vary depending on the plugin.

From: phil       Date: 06/02/08 10:10 AM

Subject: Route Login/Logout Location

Ah ha! After some time debugging – I figured out that the location of map.login/map.logout matters in routes.rb These must be above map.view_page

thanks from a noob

From: Josh Harris       Date: 05/29/08 08:08 AM

Subject: Re: Plugin not found

Answering my own post.

Instead of using the git-based link provided at agilwebdevelopment.com… stick with the link provided in the screencast:

http://svn.techno-weenie.net/projects/plugins/restful_authentication/

and be sure to use an underscore between “restful_authentication” at the end of the URL.

From: Josh Harris       Date: 05/29/08 08:08 AM

Subject: Plugin not found

I am getting a ‘plugin not found’ with

git://github.com/technoweenie/restful-authentication.git

which is what is listed as the Repository at agilewebdevelopment.com. Any help with getting this plugin to work or a work around.

From: Michael Slater       Date: 05/20/08 09:09 AM

Subject: :login_required

Tim, thanks for pointing that out. I’ve corrected the text. In “before_filter :login_required”, the colon is required because we’re providing the name of the method, not invoking the method.

From: Nitilaksha.M       Date: 05/18/08 09:21 PM

Subject: Thanks

Excellent-very clear and concise tutorial.Thanks a lot for Your Team

From: Scott       Date: 05/17/08 06:06 AM

Subject: Re: Plugin is now git-based and...

Responding to my own post to provide the correct command:

git clone git://github.com/technoweenie/restful-authentication.git

From: Tim Morgan       Date: 05/15/08 03:15 PM

Subject: small typo

login_required should be a symbol in the before_filter declaration above.

-great lessons!

From: Scott       Date: 05/13/08 09:21 PM

Subject: Plugin is now git-based and running script/plugin install produces infinite loop

This course is fantastic. Many thanks! I’ll be sure to digg it, 5-star it on iTunes, etc. as soon as I finish it.

I ran in to one slight problem outside of your purview: the restful authentication plugin repository is now at http://github.com/technoweenie/restful-authentication/tree/master

Running script/plugin install produces this recursion: ./opensearch.xml ./bundle.css?[alnum string] ./master/opensearch.xml ./master/bundle.css?[alnum string] ./master/master/opensearch.xml ./master/master/bundle.css?[alnum string]
  1. etc.

While I can of course just download the tar, can you advise the correct way to handle this?

From: Michael Slater       Date: 05/08/08 10:22 PM

Subject: Finding methods in restful_authentication

Shilpa, unfortunately, for the most part you just need to read the code, in particular the file authenticated_system.rb in your lib directory. There’s also examples scattered around the web in various tutorials and blog posts, and in a couple books. This is one of the hazards of open-source software.

From: Shilpa       Date: 05/08/08 03:15 PM

Subject: Restful_authentication

Hi Guys, This is an awesome screencast. I did learn how to use plugin.Also the restful_authentication is the most required i feel. Thanks a lot. One quaetion i have in this regard ..How do we know what methods are available and the usage of the methods in the plugins ,as i didn’t find any explanation in ReadMe also. For example login_required?Logout,Login when i installed plugin i got a message like don’t forget to use Signup it’s syntax,similalrly Login Logout what you have explained in the screencast.

Or am i missing to notice something???

From: John       Date: 05/05/08 05:17 PM

Subject: RE: Plugins and Subversion

Chris, Thank you for your response. I did install Subversion on the machine (Fedora 8 distro) and still had problems installing the plugins, but once I put it under version control, the problem went away. The error btw was “Plugin Not Found” even though typing “script/plugin list—source=X” (where X is repository URL) actually did report several available plugins, including of course Restful Authentication. Anyhow, not sure exactly what happened, but putting the project under SVN control did the trick. It was the first time I used Subversion after installing it, so perhaps something somewhere got initialized in setting up just ANY project under version control. Cheers…and thank you for the new screencast. -John

From: Christopher Haupt       Date: 05/04/08 03:15 PM

Subject: RE: Plugins and Subversion

John: What kind of problems did you run in to? On what platform? Rails plugins are independent of source-code control, so using plugins shouldn’t be a problem regardless if your own project is under Subversion, git, or nothing at all. What may be a problem, though, is if you try to install a plugin and you don’t have the Subversion client program on your machine. Some plugins are stored in source code repositories and the script/plugin install script will utilitize Subversion to pull down the code if required (it will try http when possible). Best thing to do is to install a Subversion client on your machine (see our Installation Articles), but if you don’t want to, you can usually download the plugin code manually, unpack it, and place it in your vendor/plugins area of your project (no source code control required).

From: John       Date: 05/02/08 04:16 PM

Subject: Plugins and Subversion

First off I want to thank you guys for really awesome work! I am brand new to Rails and Ruby, having used PHP with some frameworks that were, well let’s say, lacking :-) I love how easy it has been to get into Rails following your screencasts.

As a newbie, I ran into quite a bit of difficulty installing the plugin, and it took me a good hour of googling around to realize that Rails plugins work only on code that is under Subversion control. If you didn’t mention it in the screencast, it might be worth putting a comment on your site somewhere.

Thanks again. I look forward to Cinqo de Mayo now for more reasons than one.

John

From: Michael Slater       Date: 04/27/08 09:21 PM

Subject: @pagetitle vs. @page.title

Nate, you raise an excellent point. We were trying to keep things simple, but it ended up making it more complex. To be honest, it was a decision that we regret, and we’ll be changing it (more than once, as the design evolves) in future lessons.

From: nate       Date: 04/27/08 12:12 PM

Subject: @pagetitle vs. @page.title

I’m curious about the choice of accessing @page.title directly in the application template, rather than assigning it to @pagetitle in the pages controller “show” action, thereby eliminating the need for the || comparison in the view.

Thanks for the tip on the restful_authentication plug-in. I’m eager to dive into the code it provides to see how it compares with the RailsSpace book’s implementation of user authentication.

Nate