Ruby on Rails
SaltedLoginGeneratorQuickstart

This page is intended to help you get the SaltedHashLoginGenerator up and running quickly and easily. JoeHosteny’s generator is cool, but getting it set up has caused a lot of headaches on the mailing list.

For easier installation, look at using the LoginEngine, which is a port to the Rails Engines system (an alternative to Generators that avoids copying source code into your application.)

In just a few steps, we’ll get the SaltedHashLoginGenerator up and running and get all the tests passing. I’m assuming that you have Ruby, Rails, and a database engine capable of transactions (MySQL 4.x with InnoDB, Postgres, etc)

1. Install the Gems

Install the SaltedHashLoginGenerator and LocalizationGenerator gems:


gem install salted_login_generator
gem install localization_generator

2. Create your Application

Create your application and get into its directory:


rails yourapp
cd yourapp

3. Generate the code

Bring in the generator code:

ruby script/generate salted_login User Localization

Note: you can of course choose a different name for these, but that’s outside the scope of this guide

4. Include the SHLG system into your application controller

Edit your ApplicationController (yourapp/app/controllers/application.rb) to look like this


require 'environment.rb'
require 'localization'
require 'user_system'

# The filters added to this controller will be run for all controllers in the application.
# Likewise will all the methods added be available for all controllers.
class ApplicationController < ActionController::Base
  include Localization
  include UserSystem
  require_dependency 'user'

  helper :user
  model  :user
end

If you want to protect your entire application add the following line to ApplicationController:


before_filter :login_required

5. Include the SHLG helper

Add the following line to your ApplicationHelper (yourapp/app/helpers/application_helper.rb):


include Localization

6. Require the SHLG support files in environment.rb

Add the following lines to the bottom of yourapp/config/environment.rb:


require 'environments/localization_environment'
require 'localization'
Localization::load_localized_strings
require 'environments/user_environment'

[note, “localization” and “user” above assume those are the names you used in the generate command]

[note #2, above it says to put this in environment.rb. That didn’t work for me and I received the say error that everyone else sees, which is “NoMethodError in … for CONFIG:Module”. I solved that problem by adding require ‘environment.rb’
to the top of application.rb.]

7. Salt localization settings to taste

Edit yourapp/config/environments/localization_environment.rb to taste. Refer to yourapp/README_LOCALIZATION for more details.

8. Salt user settings to taste

Edit yourapp/config/environments/user_environment.rb to taste. Specifically, make sure you set the email addresses and URL, or else your notifications won’t work/will be funky. If you leave the FROM field blank, some SMTP servers will refuse your email.

9. Configure ActionMailer

Add appropriate mail configuration to your Rails environments (yourapp/config/environments/development.rb, yourapp/config/environments/test.rb, yourapp/config/environments/production.rb)

Unix machines can often use Sendmail:

ActionMailer::Base.delivery_method=:sendmail

While other platforms may need to use SMTP:

ActionMailer::Base.smtp_settings = {
:address => “smtp.yourdomain.com”,
:port => 25
}

NOTE: ActionMailer::Base.smtp_settings used to be ActionMailer::Base.server_settings

Note: For many people, more settings will be required. In particular, you may need to set the :domain key. Refer to the ActionMailer docs for more information about the ActionMailer::Base.server_settings variable.

Thanks to DavidCorbin? for pointing this out.

10. Create the user table

Ensure that your database settings are properly configured in yourapp/config/database.yml, and import the appropriate schema in yourapp/README_USER_LOGIN. Note, however, that the schema in the README (as of 2005-06-03) is slightly different that the one offered in yourapp/db/user_model.erbsql. You\u’re only missing three fields, though — created_at, updated_at, logged_in_at which you can create by hand if you want.

If you have the db_structure gem installed, you can attempt to create the schema using it by running:

script/create_db

Note: db_structure v1.0.2 does not work with PostgreSQL. If you’re running Postgres, you’re going to have to create the database by hand.

Also note: If you run this command on an already existing application, it will destroy all tables in the databases referenced by your database.yml file.

11. Run the tests

First though, make sure your test/test_helper.rb has


self.use_instantiated_fixtures  = true

Now, run the tests and watch in amazement as they pass with flying colors:


yourbox ~/yourapp $ rake test_units
(in /home/you/yourapp)
ruby -Ilib:test "/usr/local/lib/ruby/gems/1.8/gems/rake-0.5.4/lib/rake/rake_test_loader.rb" \
"test/unit/localization_test.rb" "test/unit/user_test.rb"
Loaded suite /usr/local/lib/ruby/gems/1.8/gems/rake-0.5.4/lib/rake/rake_test_loader
Started
..............
Finished in 1.51912 seconds.

14 tests, 32 assertions, 0 failures, 0 errors

yourbox ~/yourapp $ rake test_functional
(in /home/you/yourapp)
ruby -Ilib:test "/usr/local/lib/ruby/gems/1.8/gems/rake-0.5.4/lib/rake/rake_test_loader.rb" \
"test/functional/user_controller_test.rb"
Loaded suite /usr/local/lib/ruby/gems/1.8/gems/rake-0.5.4/lib/rake/rake_test_loader
Started
.........
Finished in 4.013108 seconds.

9 tests, 93 assertions, 0 failures, 0 errors

If the functional tests fail with a warning: already initialized constant DEFAULT_HEAD_OPTIONS, edit yourapp/app/helpers/user_helper.rb. At the top change

@
module UserHelper

DEFAULT_HEAD_OPTIONS = { :notice => true, :message => true, :error => false }.freeze

@

to

@
module UserHelper

  DEFAULT_HEAD_OPTIONS = {
    :notice => true,
    :message => true,
    :error => false
  }.freeze unless const_defined? "DEFAULT_HEAD_OPTIONS"
@

(there are other bug fixes on the SaltedHashLoginGenerator page, but you can get by without most of them).

If you get messages like


2) Error:
test_passwordchange(UserTest):
NoMethodError: You have a nil object when you didn’t expect it!
The error occured while evaluating nil.change_password
./test/unit/user_test.rb:17:in `test_passwordchange’

Then try editing test/test_helper.rb and set:


self.use_instantiated_fixtures = true

12. There is no step twelve!

Seriously, though, read the README so you understand how to use your new system.


Please help!!
i am using this generator and getting error in sending emails.
it says No rhtml, rxml, rjs or delegate template found for signup_en
i checked it in views/user_notify.. its present there but it is also looking for the rhtml in other plugins that i have used like fckeditor,datetime,engine etc

-Disha (disha_gupta@persistent.co.in)

hi disha,

i’ve encountered the same problem too. the culprit is localization. take away localization and it’ll work again.

-zan (liangzan at gmail.com)

How do I …

def signup
  if (User.count != 0)
    redirect_to :action => 'login'
    return
  end
  ...standard code of signup...

Please post questions or comments here

———————————


I’m on a windows platform and everything seems to be working except I don’t get any eMails. My SMTP server requires me to have a user name so i have it set up as follows

ActionMailer::Base.server_settings = { :address => "smtp.comcast.net", :port => 25, :user_name => "<a href="mailto:chillexistence@comcast.net">chillexistence@comcast.net</a>" }

and when i run the following this is my response

ruby script/console
Loading development environment.
>> UserNotify.deliver_signup(User.new, “",”")
=> #<TMail::Mail port=#<TMail::StringPort:id=0×1b876c4> bodyport=#>

when in the same area for these settings i set
config.action_mailer.raise_delivery_errors = true

and now i get

C:\rails\saltlogin>ruby script/console Loading development environment. >> UserNotify.deliver_signup(User.new, "", "") ArgumentError: both user and secret are required from c:/ruby/lib/ruby/1.8/net/smtp.rb:563:in `check_auth_args' from c:/ruby/lib/ruby/1.8/net/smtp.rb:391:in `do_start' from c:/ruby/lib/ruby/1.8/net/smtp.rb:378:in `start' from c:/ruby/lib/ruby/1.8/net/smtp.rb:316:in `start' from c:/ruby/lib/ruby/gems/1.8/gems/actionmailer-1.1.5/lib/action_mailer /base.rb:436:in `perform_delivery_smtp' from c:/ruby/lib/ruby/gems/1.8/gems/actionmailer-1.1.5/lib/action_mailer /base.rb:327:in `send' from c:/ruby/lib/ruby/gems/1.8/gems/actionmailer-1.1.5/lib/action_mailer /base.rb:327:in `deliver!' from c:/ruby/lib/ruby/gems/1.8/gems/actionmailer-1.1.5/lib/action_mailer /base.rb:223:in `method_missing' from (irb):1


Either I don’t know what I’m doing (quite possible, being a Rails and Ruby newbie), or this thing is broken. I keep getting errors like

NoMethodError in User#login 
WARNING: You have a nil object when you probably didn’t expect it! Odds are you
want an instance of Array instead.

Look in the callstack to see where you’re working with an object that could be nil.
Investigate your methods and make sure the object is what you expect!

/app/controllers/user_controller.rb:9:in `login’
script/server:49


In looking at the code, it seems that there are assumptions about @params‘user’ being set. When you come in fresh, this is nil, which causes this error. Why is there no exception handling in here???
So, is my application or configuration messed up, or is this generator the problem?

Possible Solution

I had some of the same problems. It turned out that the machine I was running an old version of rails. Double check yours?



Nope, it’s been rails-0.13.1 all along, but I even ran
gem install rails —remote
just to be sure. No change.

Even more puzzling, unit testing works fine:

C:>rake test_units
ruby -Ilib;test “c:/ruby/lib/ruby/gems/1.8/gems/rake-0.5.4/lib/rake/rake_test_lo
ader.rb” “test/unit/localization_test.rb” “test/unit/user_test.rb”
Loaded suite c:/ruby/lib/ruby/gems/1.8/gems/rake-0.5.4/lib/rake/rake_test_loader

Started
…………..
Finished in 1.072 seconds.

14 tests, 32 assertions, 0 failures, 0 errors

I’ve had no problems with the regular LoginGenerator, so I’m dropping back to that. sigh

same problem, but only with link_to_remote

I’m having the same problem, except strangely enough I don’t get it if I go directly to localhost:3000/user/login (or signup or anything), but I do get it when I try to use link_to_remote for the same controller and action.

Unit tests fail in PostgreSQL 8 because email is not allowed to be NULL.

Once I set the email field to be nullable the unit tests worked.

Shouldn’t :app_url be configurable per environment?

Perhaps it can but I have absolutely no idea how? :-)

Should DB column token_expiry be token_expires_at?

It was my understand that date/time columns were supposed to be named as such.

If the functional test fails, this might be why

If you changed :security_token_life_hours, the functional test might fail for your because of a hardcoded value in line 55. Be sure to modify this value to match your :security_token_life_hours setting in days.

No rhtml, rxml, or delegate template found for _form

One of the reasons that some people have more/less trouble with this generator than other people has to do with what they did before starting this quickstart. If you’ve already created most of your application, and you’re adding in this login system, you’ve got more of the ecostructure in place. If this login system is the first thing you’re creating for your app, you may find that some pieces are missing.

One item not generated in some cases is app/views/user/form.rhtml. Here’s a stub _form.rhtml that will suffice:


<%= error
messages_for ‘user’ %>




<%= text_field ‘user’, ‘login’ %>



<%= password_field ‘user’, ‘salted_password’ %>



<%= text_field ‘user’, ‘email’ %>



<%= text_field ‘user’, ‘firstname’ %>



<%= text_field ‘user’, ‘lastname’ %>



<%= text_field ‘user’, ‘salt’ %>



<%= text_field ‘user’, ‘verified’ %>



<%= text_field ‘user’, ‘role’ %>



<%= text_field ‘user’, ‘security_token’ %>



<%= datetime_select ‘user’, ‘token_expiry’ %>



<%= datetime_select ‘user’, ‘created_at’ %>



<%= datetime_select ‘user’, ‘updated_at’ %>



<%= datetime_select ‘user’, ‘logged_in_at’ %>



<%= text_field ‘user’, ‘deleted’ %>



<%= datetime_select ‘user’, ‘delete_after’ %>


users database keeps disappearing
If your user database keeps disappearing when you run your rake tests, maybe you tried to test out your changes on the test database before applying them to dev database. Make sure you apply the database changes to the dev database. The test database is re-created from the development database every time the tests are run.

*How to see what your SMTP server is reporting *
If you’ve identified that you have a problem sending your signup emails in UserNotify.deliver_signup (probably you’re seeing “Error creating account: confirmation email not sent”), one way to see what’s going on is to use the console.

ruby script/console
>>  UserNotify.deliver_signup(User.new, "", "")
Net::SMTPSyntaxError: 500 5.5.1 Command unrecognized: "AUTH CRAM-MD5"

Some unit tests failing
The unit tests are written to expect instantiated fixtures, but they are turned off in the test_helper.rb file. Turn them back on with

self.use_instantiated_fixtures  = true

and the failures may go away.

NOTE for Windows Users
You need to have iconv support.


It’s quite a long procedure.. isn’t there a faster way?

———————
Trying to rake test_units…and rake test_functional..
what does the following mean?

C:\rails\clink>rake test_units
(in C:/rails/clink)
c:/ruby/bin/ruby -Ilib;test "c:/ruby/lib/ruby/gems/1.8/gems/rake-0.6.2/lib/rake/

rake_test_loader.rb" “test/unit/localization_test.rb” “test/unit/user_test.rb”
Loaded suite c:/ruby/lib/ruby/gems/1.8/gems/rake-0.6.2/lib/rake/rake_test_loader

Started
……..F….E
Finished in 0.23 seconds.

1) Failure:

test_auth(UserTest) [./test/unit/user_test.rb:9]:
expected but was
<#<User:0×3773558
attributes= {"salt"=>"7f8b036f9b647d46d22abdbfc8113f44a88f9889", "delete_after"=>nil, "updated_at"=>nil, "security_token"=>nil, "role"=>nil, "lastname"=>nil, "firstname"=>nil, "id"=>"1000001", "deleted"=>"0", "token_expiry"=>nil, "verified"=>"1", "logged_in_at"=>nil, "salted_password"=>"ef94c16f6c124a4e84cc215c164767bfa25f6e92", "login"=>"bob", "created_at"=>nil, "email"=>"<a href="mailto:bobtest.com">bob@test.com"}>>.

2) Error:

test_passwordchange(UserTest):
NoMethodError: You have a nil object when you didn’t expect it!
The error occured while evaluating nil.change_password
./test/unit/user_test.rb:17:in `test_passwordchange’

14 tests, 27 assertions, 1 failures, 1 errors
rake aborted!
Command failed with status (1): [c:/ruby/bin/ruby -Ilib;test "c:/ruby/lib/r…]

C:\rails\clink>rake test_functional
(in C:/rails/clink)
c:/ruby/bin/ruby -Ilib;test “c:/ruby/lib/ruby/gems/1.8/gems/rake-0.6.2/lib/rake/
rake_test_loader.rb” “test/functional/user_controller_test.rb”
Loaded suite c:/ruby/lib/ruby/gems/1.8/gems/rake-0.6.2/lib/rake/rake_test_loader

Started
F.FEF…F
Finished in 0.741 seconds.

1) Failure:

test_auth_bob(UserControllerTest) [./test/functional/user_controller_test.rb:23]
:
expected but was
<#<User:0×375da60
attributes= {"salt"=>"7f8b036f9b647d46d22abdbfc8113f44a88f9889", "delete_after"=>nil, "updated_at"=>nil, "security_token"=>nil, "role"=>nil, "lastname"=>nil, "firstname"=>nil, "id"=>"1000001", "deleted"=>"0", "token_expiry"=>nil, "verified"=>"1", "logged_in_at"=>nil, "salted_password"=>"ef94c16f6c124a4e84cc215c164767bfa25f6e92", "login"=>"bob", "created_at"=>nil, "email"=>"<a href="mailto:bobtest.com">bob@test.com"}>>.

2) Failure:

test_change_password(UserControllerTest)
[c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.0/lib/action_controller/depr
ecated_assertions.rb:23:in `assert_session_has’
./test/functional/user_controller_test.rb:186:in `do_change_password’
./test/functional/user_controller_test.rb:194:in `test_change_password’]:
<"user"> is not in the session <#<ActionController::TestSession:0×36caee0
@attributes={"user"=>nil, “flash”=>{}}>>

3) Error:

test_delete(UserControllerTest):
NoMethodError: undefined method `advance_by_days=’ for Time:Class
./test/functional/user_controller_test.rb:132:in `test_delete’

4) Failure:

test_edit(UserControllerTest)
[c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.0/lib/action_controller/depr
ecated_assertions.rb:23:in `assert_session_has’
./test/functional/user_controller_test.rb:89:in `test_edit’]:
<"user"> is not in the session <#<ActionController::TestSession:0×395f8a0
@attributes={"user"=>nil, “flash”=>{}}>>

5) Failure:

test_signup(UserControllerTest)
[c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.0/lib/action_controller/depr
ecated_assertions.rb:13:in `assert_redirect’
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.11.0/lib/action_controller/depr
ecated_assertions.rb:98:in `assert_redirect_url’
./test/functional/user_controller_test.rb:37:in `do_test_signup’
./test/functional/user_controller_test.rb:145:in `test_signup’]:
Expected response to be a <:redirect>, but was <200>

9 tests, 76 assertions, 4 failures, 1 errors
rake aborted!
Command failed with status (1): [c:/ruby/bin/ruby -Ilib;test "c:/ruby/lib/r…]

———————

It looks like you aren’t using instantiated fixtures. Make sure the following is in test/test_helper.rb:

self.use_instantiated_fixtures = true

— ericdfoley at google’s mail service

Right. See Mike Clark’s explanation.

———————

My rake tests are failing because of loads of inconsistencies in the spelling of localization/localisation

———————
I am trying to use the ‘scripte\generate salted_login User Localization’ command with a rails project that was created before the salted_login or localization_generator gems were installed and I am getting this error message “No such file or directory – ./script/../config/../lib/localization.rb”. If I run the same command in a new rails project, all is well. Is there a way I can hack my old project to work with the generator?

———————
It appears that MySQL versions before 4.1 don’t support “charset” on table creation … so find your db_structure.rb file installed by gem, and edit the @options for mysql to remove “DEFAULT CHARSET=utf8”

———————
Please note that I tried to install the salted_login_generator on Windows XP using Ruby 1.8.2. The installation would give me the RDoc errors mentioned above, but would not finish.
It took my CPU to 99% and used 600 MB of memory.

I upgraded to Ruby 1.8.4 using the one-click ruby installer at rubyforge
This resolved my installation problem.
—Nate

———————
There seems to be a large number of settings I’m not seeing a way of editing. Such as the “changeable” helper method – I’d like to make the email changeable for example.

Many thanks for your help.

———————
Turning Login Generator into a User Manager
How much would it take and what changes would you suggest in moulding the existing login generated code to turn it into a full User manager as well? Offering the ability to edit/delete specific users rather than just the currently logged in user?

———————————

Having a nightmare setting this up. It really needs way more documentation and guidance.

———————————
I second that motion. I’ve got later than 4.1 mysql and getting file not found errors when installing w/ gem. And it didn’t even lay down the db_structure.rb file.
———————————

How do we setup ActionMailer to use a specific smtp server (with username and password)?
———————————
You can give ActionMailer all of these params:

ActionMailer::Base.server_settings = {

:address => “smtp.mac.com”, :port => 25, :domain => “smtp.mac.com”, :user_name => “”, :password => “”, :authentication => :login

}

Also, for my question, I finished setting it up, but when I tried to start the server it said, “=> Booting WEBrick…” then canceled and went back to the command prompt. What is wrong?

—> You need to install inconv support as or upgrade to ruby 1.8.4. Links for both of these have been mentioned earlier.

———————————-

I’ve spent hours trying to ge this working. I’m still getting the following exception ‘undefined method `[]’ for CONFIG:Module’
I’m ready to leave ror and go back to what works. seriously.

———————————-

Everything seems to be running smoothly up until the point I need to generate the login emails. While no errors are generated, I’m not sending out any emails.

I’m running off a development environment on my local machine (localhost), but my smtp server is from a hosted account elsewhere. Here’s how I’ve got it set up right now:

ActionMailer::Base.server_settings = {
:address => “mail.example.com”,
:port => 25,
:domain => “localhost”,
:user_name => “myusername”,
:password => “mypassword”
:authentication => :login
}

Does anyone have any ideas where I’m going wrong.
———————————-
Are you seeing an error on the front-end screen, like:

‘Error creating account: confirmation email not sent’

For me it was failing because I had mistyped my ActionMailer settings. I changed the rescue block in def signup to this:


rescue Exception => exc
flash.now‘message’ = l(:user_confirmation_email_error)
logger.warn("User failed confirmation: " + exc.message)
end

I found that this generator generally has good error handling except in the logs.

Taking a quick look at your Actionmailer settings it looks like you are not init. it correctly. There is a correct example above in the wiki.
- Adam G.

———————————————-
Hi, i have a problem when lokk at my app on url app/user/login or other signup … :

undefined method `[]’ for CONFIG:Module

localization.rb:8:in `l’
#{RAILS_ROOT}/app/helpers/user_helper.rb:67:in `head_helper’
#{RAILS_ROOT}/app/views/user/login.rhtml:2:in `_run_rhtml_user_login’
#{RAILS_ROOT}/app/controllers/user_controller.rb:172:in `generate_blank’
#{RAILS_ROOT}/app/controllers/user_controller.rb:6:in `login’

help me what is the problem ?
-krull

———————————————-

You need to add this to the bottom of your config/environment.rb file:

require ‘environments/localization_environment’
require ‘localization’
Localization::load_loca