# User Authentication

**URL:** <https://www.ruby-forum.com/t/user-authentication/54352>\
**Category:** Rails\
**Created:** [March 2, 2006, 5:37am UTC](https://www.ruby-forum.com/t/user-authentication/54352 "2006-03-02T05:37:12Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Greg\_MacGregor](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/b77776/32.png) [@Greg\_MacGregor](https://www.ruby-forum.com/u/Greg_MacGregor)\
**Post date:** [March 2, 2006, 5:37am UTC](https://www.ruby-forum.com/t/user-authentication/54352/1 "2006-03-02T05:37:12Z")

</div>

I’m trying to create a simple authentication system but am failing  
miserably. I’m (sort of) following the “Logging In” chapter of the Agile  
book. Ideally, any access to [http://example.com/publish](http://example.com/publish) (and any of its  
subdirectories) should redirect to http:/example.com/publish/login when  
there is no valid session user\_id.

Code so far:

* * *

# controller

class PublishController \< ApplicationController

before\_filter :authenticate, :except =\> [:login, :login\_user]

def login  
if request.post?  
logged\_in\_user = @user.attempt\_login  
if logged\_in\_user  
session[:user\_id] = logged\_in\_user.id  
redirect\_to(:action =\> ‘index’)  
else  
flash[:notice] = ‘Invalid username or password. Please try  
again’

```
    end
end

```

end

def self.authenticate  
unless session[:user\_id]  
redirect\_to :action =\> ‘login’  
end  
end

end

#model  
class User \< ActiveRecord::Base

require “digest/sha1”

attr\_accessor :password  
attr\_accessible :username, :password, :first\_name, :last\_name, :email

validates\_uniqueness\_of :username  
validates\_presence\_of :username, :first\_name, :last\_name, :email  
validates\_length\_of :password, :within =\> 5…40, :on =\> :create

def before\_create  
self.sha\_password = User.encrypt(self.password)  
end

def after\_create  
@password = nil  
end

private  
def self.encrypt(password)  
Digest::SHA1.hexdigest(password)  
end

def self.login\_user(username, password)  
encrypted\_password = encrypt(password || “”)  
find(:first, :conditions =\> [“username = ? and sha\_password = ?”,  
username, encrypted\_password])  
end

def attempt\_login  
User.login\_user(self.username, self.password)  
end

end

* * *

If I browse to, say, [http://example.com/publish/user/list](http://example.com/publish/user/list) I get a  
NoMethodError in Publish#user:

undefined method `authenticate’ for #PublishController:0x387ab58W

When I browse to [http://example.com/publish/login/](http://example.com/publish/login/) I see the login form  
but  
upon submit I get another NoMethodError in Publish#login:

You have a nil object when you didn’t expect it!  
The error occured while evaluating nil.attempt\_login

I’m totally stumped and appreciate any help.

Greg

---

<div class="post-metadata">

**Author:** ![Greg\_MacGregor](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/b77776/32.png) [@Greg\_MacGregor](https://www.ruby-forum.com/u/Greg_MacGregor)\
**Post date:** [March 2, 2006, 6:08am UTC](https://www.ruby-forum.com/t/user-authentication/54352/2 "2006-03-02T06:08:22Z")

</div>

Greg MacGregor wrote:

> I’m trying to create a simple authentication system but am failing  
> miserably. I’m (sort of) following the “Logging In” chapter of the Agile  
> book. Ideally, any access to [http://example.com/publish](http://example.com/publish) (and any of its  
> subdirectories) should redirect to http:/example.com/publish/login when  
> there is no valid session user\_id.

Greg MacGregor wrote:

> I’m trying to create a simple authentication system but am failing  
> miserably. I’m (sort of) following the “Logging In” chapter of the Agile  
> book. Ideally, any access to [http://example.com/publish](http://example.com/publish) (and any of its  
> subdirectories) should redirect to http:/example.com/publish/login when  
> there is no valid session user\_id.

Are you sure you don’t want to save a lot of time and use one of the  
pre-written packages that are available? Salted, for example:

[http://wiki.rubyonrails.com/rails/pages/SaltedHashLoginGenerator](http://wiki.rubyonrails.com/rails/pages/SaltedHashLoginGenerator)

I am a fellow Rails newbie, and I had no problem getting Salted up and  
running. And it’s really easy to modify. You might also want to look  
here, for user _authorization_:

[http://d-haven.org/modules/news/article.php?storyid=28](http://d-haven.org/modules/news/article.php?storyid=28)

I haven’t tried that yet, but I’m going to set it up tomorrow, and I’m  
thinking it will be up and running in 1-2 hours.

One of the reasons Rails is so awesome is that there is SO much existing  
code out there to use. And it’s so easy to modify to do exactly what you  
want to do.

BUT… if you do want to write your own User system, I’m sure there’s a  
lot of folks here who can help you. You wouldn’t want to be taking  
Rails or Ruby coding advice from me just yet…

Micah

---

<div class="post-metadata">

**Author:** ![Greg\_MacGregor](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/b77776/32.png) [@Greg\_MacGregor](https://www.ruby-forum.com/u/Greg_MacGregor)\
**Post date:** [March 2, 2006, 6:12am UTC](https://www.ruby-forum.com/t/user-authentication/54352/3 "2006-03-02T06:12:48Z")

</div>

Micah B. wrote:

> Are you sure you don’t want to save a lot of time and use one of the  
> pre-written packages that are available?

… building it myself (and running into errors such as this) will help  
me to better understand how the controller and model interact with one  
another. I appreciate the links, Micah!

Greg

---

<div class="post-metadata">

**Author:** ![Greg\_MacGregor](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/b77776/32.png) [@Greg\_MacGregor](https://www.ruby-forum.com/u/Greg_MacGregor)\
**Post date:** [March 2, 2006, 6:21am UTC](https://www.ruby-forum.com/t/user-authentication/54352/4 "2006-03-02T06:21:41Z")

</div>

On 3/1/06, Greg MacGregor [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> ```
> redirect_to(:action => 'index')
> else
> flash[:notice] = 'Invalid username or password. Please try again'
> end
> end
> 
> ```
> 
> end
> 
> def self.authenticate

This needs to be a regular method (what’s the correct terminology  
here?), not a class method.  
You want:

```
  def authenticate

```

And I’d put the authenticate method in the Application controller,  
that way other controllers can access it (note: if you do that, you’ll  
need to change the below redirect to also include the controller.

Joe

---

<div class="post-metadata">

**Author:** ![Greg\_MacGregor](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/b77776/32.png) [@Greg\_MacGregor](https://www.ruby-forum.com/u/Greg_MacGregor)\
**Post date:** [March 2, 2006, 6:39am UTC](https://www.ruby-forum.com/t/user-authentication/54352/5 "2006-03-02T06:39:34Z")

</div>

Hi Greg,

comments inline:

On 1-Mar-06, at 8:37 PM, Greg MacGregor wrote:

> I’m trying to create a simple authentication system but am failing  
> miserably. I’m (sort of) following the “Logging In” chapter of the  
> Agile book. Ideally, any access to [http://example.com/publish](http://example.com/publish) (and  
> any of its subdirectories) should redirect to http:/example.com/  
> publish/login when there is no valid session user\_id.

Okay, it’s the “sort of” that’s biting you in the rear right now.  
I’ll point out why you’re getting the errors but I advise you to go  
back and work through the Logging In chapter again, step by step.

more below:

> ```
> if request.post?
> 
> ```

One of your errors is that you’re trying to call (effectively)  
“nil.attempt\_login”. The offending line is above, where you call  
@user.attempt\_login. The problem is, you’re not assigning a value to  
@user so it’s ‘nil’.

If I look at your User model below, I’d guess you really want to say:

logged\_in\_user = User.login\_user(params[:username], params[:password])

of course, this assumes you’re actually passing username and password  
as POST params.

> def self.authenticate  
> unless session[:user\_id]  
> redirect\_to :action =\> ‘login’  
> end  
> end

The authenticate method above has “self.” in front of it which makes  
it a _class_ method. i.e. you can only call it as  
PublishController.authenticate

However, your filters are expected to be _instance_ methods of the  
controller so ditch the ‘self.’ and that will eliminate your  
“undefined method `authenticate`” error.

## HTH, Trevor

Trevor S.  
[http://somethinglearned.com](http://somethinglearned.com)

---

<div class="post-metadata">

**Author:** ![Greg\_MacGregor](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/b77776/32.png) [@Greg\_MacGregor](https://www.ruby-forum.com/u/Greg_MacGregor)\
**Post date:** [March 2, 2006, 6:58am UTC](https://www.ruby-forum.com/t/user-authentication/54352/6 "2006-03-02T06:58:46Z")

</div>

On 3/1/06, Greg [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> ```
> if logged_in_user
> unless session[:user_id]
> 
> ```
> 
> There is indeed a list action in the user controller, so how come the  
> redirect doesn’t work?
> 
> Thanks again for the help.
> 
> Greg

Is the User controller defined like:  
class Publish::AdminController \< ApplicationController  
?

What exactly doesn’t work with the redirection?

---

<div class="post-metadata">

**Author:** ![Greg\_MacGregor](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/b77776/32.png) [@Greg\_MacGregor](https://www.ruby-forum.com/u/Greg_MacGregor)\
**Post date:** [March 2, 2006, 6:53am UTC](https://www.ruby-forum.com/t/user-authentication/54352/7 "2006-03-02T06:53:35Z")

</div>

Thanks Trevor. Before you posted I made these changes:

class PublishController \< ApplicationController

before\_filter :authenticate

def login  
if request.post?  
@user = User.new(params[:user])  
logged\_in\_user = @user.attempt\_login  
if logged\_in\_user  
session[:user\_id] = logged\_in\_user.id  
redirect\_to(:controller =\> ‘/publish/user’, :action =\> ‘list’)  
else  
flash[:notice] = ‘Invalid username or password. Please try  
again’  
end  
end  
end

def authenticate  
unless session[:user\_id]  
redirect\_to :action =\> ‘login’  
end  
end

end

* * *

and i added this to my model:

public  
def attempt\_login  
User.login\_user(self.username, self.password)  
end

(note public)

everything seems to work now but I have another problem. After  
successful login I want to point the user to  
[example.com/publish/user/list](http://example.com/publish/user/list). I’ve referred to this as

redirect\_to(:controller =\> ‘/publish/user’, :action =\> ‘list’)

above. My app looks like

app  
+controllers  
-application\_controller.rb  
-publish\_controller.rb  
+publish  
-user\_controller.rb

There is indeed a list action in the user controller, so how come the  
redirect doesn’t work?

Thanks again for the help.

Greg

---

<div class="post-metadata">

**Author:** ![Greg\_MacGregor](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/b77776/32.png) [@Greg\_MacGregor](https://www.ruby-forum.com/u/Greg_MacGregor)\
**Post date:** [March 2, 2006, 3:16pm UTC](https://www.ruby-forum.com/t/user-authentication/54352/8 "2006-03-02T15:16:40Z")

</div>

Greg,  
Like you, when I first started with Rails I used the authentication  
sample from the Agile book. But I quickly dicovered that it was too  
limited, even for the hobby site I was building.

I recommend looking at the acts\_as\_authenticated plugin. It’s easy to  
set up, and has convenience methods for handy things like displaying the  
name of the user logged on (e.g. current\_user.login). Or, “logged\_in?”,  
a simple test to determine if someone is logged in. This is handy if you  
want to display special menus to users who are logged in vs. the general  
public. Of course, that just scratches the surface. It also integrates  
ActionMailer for emailing, etc.

Of course, you’re free to code this stuff yourself, but I decided that  
using an available plugin for the drudgery of authentication left me  
with more time for writing my “actual” application.

FYI, There’s even a separate, new ACL system written to complement the  
acts\_as\_authenticated plugin (I haven’t tried it yet). So you can assign  
roles/permissions to certain users.

Good luck!  
-Chris

---

<div class="post-metadata">

**Author:** ![Greg\_MacGregor](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/b77776/32.png) [@Greg\_MacGregor](https://www.ruby-forum.com/u/Greg_MacGregor)\
**Post date:** [March 2, 2006, 4:09pm UTC](https://www.ruby-forum.com/t/user-authentication/54352/9 "2006-03-02T16:09:21Z")

</div>

Joe Van D. wrote:

> Is the User controller defined like:  
> class Publish::AdminController \< ApplicationController  
> ?
> 
> What exactly doesn’t work with the redirection?

Given my structure above, the User controller is defined like this:  
class Publish::UserController \< ActionController … or

-app  
+controllers  
-publish\_controller.rb  
+publish  
-user\_controller.rb

Like I said, there is a list action in the user\_controller that I know  
works. After login I am redirected to:  
[http://example.com/publish/user/list](http://example.com/publish/user/list) and get the error: “no action for  
user#list” or something to that effect. I don’t understand why that is  
happening if the action is indeed there?!

I think that I may use a pre-fab authentication controller after all.  
This is giving me a headache. Thanks again to all of you for the help.

Greg
