Commit 42f23f99d6a4a701b9ba82f623e084a1e15c8768
- Diff rendering mode:
- inline
- side by side
|   | |||
| 1 | # This controller handles the login/logout function of the site. | ||
| 2 | class SessionsController < ApplicationController | ||
| 3 | # Be sure to include AuthenticationSystem in Application Controller instead | ||
| 4 | include AuthenticatedSystem | ||
| 5 | |||
| 6 | # render new.rhtml | ||
| 7 | def new | ||
| 8 | end | ||
| 9 | |||
| 10 | def create | ||
| 11 | self.current_user = User.authenticate(params[:login], params[:password]) | ||
| 12 | if logged_in? | ||
| 13 | if params[:remember_me] == "1" | ||
| 14 | self.current_user.remember_me | ||
| 15 | cookies[:auth_token] = { :value => self.current_user.remember_token , :expires => self.current_user.remember_token_expires_at } | ||
| 16 | end | ||
| 17 | redirect_back_or_default('/') | ||
| 18 | flash[:notice] = "Logged in successfully" | ||
| 19 | else | ||
| 20 | render :action => 'new' | ||
| 21 | end | ||
| 22 | end | ||
| 23 | |||
| 24 | def destroy | ||
| 25 | self.current_user.forget_me if logged_in? | ||
| 26 | cookies.delete :auth_token | ||
| 27 | reset_session | ||
| 28 | flash[:notice] = "You have been logged out." | ||
| 29 | redirect_back_or_default('/') | ||
| 30 | end | ||
| 31 | end |
|   | |||
| 1 | class UsersController < ApplicationController | ||
| 2 | # Be sure to include AuthenticationSystem in Application Controller instead | ||
| 3 | include AuthenticatedSystem | ||
| 4 | |||
| 5 | |||
| 6 | # render new.rhtml | ||
| 7 | def new | ||
| 8 | end | ||
| 9 | |||
| 10 | def create | ||
| 11 | cookies.delete :auth_token | ||
| 12 | # protects against session fixation attacks, wreaks havoc with | ||
| 13 | # request forgery protection. | ||
| 14 | # uncomment at your own risk | ||
| 15 | # reset_session | ||
| 16 | @user = User.new(params[:user]) | ||
| 17 | @user.save | ||
| 18 | if @user.errors.empty? | ||
| 19 | self.current_user = @user | ||
| 20 | redirect_back_or_default('/') | ||
| 21 | flash[:notice] = "Thanks for signing up!" | ||
| 22 | else | ||
| 23 | render :action => 'new' | ||
| 24 | end | ||
| 25 | end | ||
| 26 | |||
| 27 | end |
|   | |||
| 1 | module SessionsHelper | ||
| 2 | end |
app/helpers/users_helper.rb
(2 / 0)
|   | |||
| 1 | module UsersHelper | ||
| 2 | end |
app/models/user.rb
(78 / 0)
|   | |||
| 1 | require 'digest/sha1' | ||
| 2 | class User < ActiveRecord::Base | ||
| 3 | # Virtual attribute for the unencrypted password | ||
| 4 | attr_accessor :password | ||
| 5 | |||
| 6 | validates_presence_of :login, :email | ||
| 7 | validates_presence_of :password, :if => :password_required? | ||
| 8 | validates_presence_of :password_confirmation, :if => :password_required? | ||
| 9 | validates_length_of :password, :within => 4..40, :if => :password_required? | ||
| 10 | validates_confirmation_of :password, :if => :password_required? | ||
| 11 | validates_length_of :login, :within => 3..40 | ||
| 12 | validates_length_of :email, :within => 3..100 | ||
| 13 | validates_uniqueness_of :login, :email, :case_sensitive => false | ||
| 14 | before_save :encrypt_password | ||
| 15 | |||
| 16 | # prevents a user from submitting a crafted form that bypasses activation | ||
| 17 | # anything else you want your user to change should be added here. | ||
| 18 | attr_accessible :login, :email, :password, :password_confirmation | ||
| 19 | |||
| 20 | # Authenticates a user by their login name and unencrypted password. Returns the user or nil. | ||
| 21 | def self.authenticate(login, password) | ||
| 22 | u = find_by_login(login) # need to get the salt | ||
| 23 | u && u.authenticated?(password) ? u : nil | ||
| 24 | end | ||
| 25 | |||
| 26 | # Encrypts some data with the salt. | ||
| 27 | def self.encrypt(password, salt) | ||
| 28 | Digest::SHA1.hexdigest("--#{salt}--#{password}--") | ||
| 29 | end | ||
| 30 | |||
| 31 | # Encrypts the password with the user salt | ||
| 32 | def encrypt(password) | ||
| 33 | self.class.encrypt(password, salt) | ||
| 34 | end | ||
| 35 | |||
| 36 | def authenticated?(password) | ||
| 37 | crypted_password == encrypt(password) | ||
| 38 | end | ||
| 39 | |||
| 40 | def remember_token? | ||
| 41 | remember_token_expires_at && Time.now.utc < remember_token_expires_at | ||
| 42 | end | ||
| 43 | |||
| 44 | # These create and unset the fields required for remembering users between browser closes | ||
| 45 | def remember_me | ||
| 46 | remember_me_for 2.weeks | ||
| 47 | end | ||
| 48 | |||
| 49 | def remember_me_for(time) | ||
| 50 | remember_me_until time.from_now.utc | ||
| 51 | end | ||
| 52 | |||
| 53 | def remember_me_until(time) | ||
| 54 | self.remember_token_expires_at = time | ||
| 55 | self.remember_token = encrypt("#{email}--#{remember_token_expires_at}") | ||
| 56 | save(false) | ||
| 57 | end | ||
| 58 | |||
| 59 | def forget_me | ||
| 60 | self.remember_token_expires_at = nil | ||
| 61 | self.remember_token = nil | ||
| 62 | save(false) | ||
| 63 | end | ||
| 64 | |||
| 65 | protected | ||
| 66 | # before filter | ||
| 67 | def encrypt_password | ||
| 68 | return if password.blank? | ||
| 69 | self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record? | ||
| 70 | self.crypted_password = encrypt(password) | ||
| 71 | end | ||
| 72 | |||
| 73 | def password_required? | ||
| 74 | crypted_password.blank? || !password.blank? | ||
| 75 | end | ||
| 76 | |||
| 77 | |||
| 78 | end |
app/views/sessions/new.html.erb
(14 / 0)
|   | |||
| 1 | <% form_tag session_path do -%> | ||
| 2 | <p><label for="login">Login</label><br/> | ||
| 3 | <%= text_field_tag 'login' %></p> | ||
| 4 | |||
| 5 | <p><label for="password">Password</label><br/> | ||
| 6 | <%= password_field_tag 'password' %></p> | ||
| 7 | |||
| 8 | <!-- Uncomment this if you want this functionality | ||
| 9 | <p><label for="remember_me">Remember me:</label> | ||
| 10 | <%= check_box_tag 'remember_me' %></p> | ||
| 11 | --> | ||
| 12 | |||
| 13 | <p><%= submit_tag 'Log in' %></p> | ||
| 14 | <% end -%> |
app/views/users/new.html.erb
(16 / 0)
|   | |||
| 1 | <%= error_messages_for :user %> | ||
| 2 | <% form_for :user, :url => users_path do |f| -%> | ||
| 3 | <p><label for="login">Login</label><br/> | ||
| 4 | <%= f.text_field :login %></p> | ||
| 5 | |||
| 6 | <p><label for="email">Email</label><br/> | ||
| 7 | <%= f.text_field :email %></p> | ||
| 8 | |||
| 9 | <p><label for="password">Password</label><br/> | ||
| 10 | <%= f.password_field :password %></p> | ||
| 11 | |||
| 12 | <p><label for="password_confirmation">Confirm Password</label><br/> | ||
| 13 | <%= f.password_field :password_confirmation %></p> | ||
| 14 | |||
| 15 | <p><%= submit_tag 'Sign up' %></p> | ||
| 16 | <% end -%> |
config/routes.rb
(4 / 0)
|   | |||
| 1 | 1 | ActionController::Routing::Routes.draw do |map| | |
| 2 | map.resources :users | ||
| 3 | |||
| 4 | map.resource :session | ||
| 5 | |||
| 2 | 6 | map.resources :scheduled_debts | |
| 3 | 7 | map.resources :realizations | |
| 4 | 8 | map.resources :scheduled_profits |
db/migrate/010_create_users.rb
(20 / 0)
|   | |||
| 1 | class CreateUsers < ActiveRecord::Migration | ||
| 2 | def self.up | ||
| 3 | create_table "users", :force => true do |t| | ||
| 4 | t.column :login, :string | ||
| 5 | t.column :email, :string | ||
| 6 | t.column :crypted_password, :string, :limit => 40 | ||
| 7 | t.column :salt, :string, :limit => 40 | ||
| 8 | t.column :created_at, :datetime | ||
| 9 | t.column :updated_at, :datetime | ||
| 10 | t.column :remember_token, :string | ||
| 11 | t.column :remember_token_expires_at, :datetime | ||
| 12 | |||
| 13 | |||
| 14 | end | ||
| 15 | end | ||
| 16 | |||
| 17 | def self.down | ||
| 18 | drop_table "users" | ||
| 19 | end | ||
| 20 | end |
lib/authenticated_system.rb
(116 / 0)
|   | |||
| 1 | module AuthenticatedSystem | ||
| 2 | protected | ||
| 3 | # Returns true or false if the user is logged in. | ||
| 4 | # Preloads @current_user with the user model if they're logged in. | ||
| 5 | def logged_in? | ||
| 6 | current_user != :false | ||
| 7 | end | ||
| 8 | |||
| 9 | # Accesses the current user from the session. Set it to :false if login fails | ||
| 10 | # so that future calls do not hit the database. | ||
| 11 | def current_user | ||
| 12 | @current_user ||= (login_from_session || login_from_basic_auth || login_from_cookie || :false) | ||
| 13 | end | ||
| 14 | |||
| 15 | # Store the given user id in the session. | ||
| 16 | def current_user=(new_user) | ||
| 17 | session[:user_id] = (new_user.nil? || new_user.is_a?(Symbol)) ? nil : new_user.id | ||
| 18 | @current_user = new_user || :false | ||
| 19 | end | ||
| 20 | |||
| 21 | # Check if the user is authorized | ||
| 22 | # | ||
| 23 | # Override this method in your controllers if you want to restrict access | ||
| 24 | # to only a few actions or if you want to check if the user | ||
| 25 | # has the correct rights. | ||
| 26 | # | ||
| 27 | # Example: | ||
| 28 | # | ||
| 29 | # # only allow nonbobs | ||
| 30 | # def authorized? | ||
| 31 | # current_user.login != "bob" | ||
| 32 | # end | ||
| 33 | def authorized? | ||
| 34 | logged_in? | ||
| 35 | end | ||
| 36 | |||
| 37 | # Filter method to enforce a login requirement. | ||
| 38 | # | ||
| 39 | # To require logins for all actions, use this in your controllers: | ||
| 40 | # | ||
| 41 | # before_filter :login_required | ||
| 42 | # | ||
| 43 | # To require logins for specific actions, use this in your controllers: | ||
| 44 | # | ||
| 45 | # before_filter :login_required, :only => [ :edit, :update ] | ||
| 46 | # | ||
| 47 | # To skip this in a subclassed controller: | ||
| 48 | # | ||
| 49 | # skip_before_filter :login_required | ||
| 50 | # | ||
| 51 | def login_required | ||
| 52 | authorized? || access_denied | ||
| 53 | end | ||
| 54 | |||
| 55 | # Redirect as appropriate when an access request fails. | ||
| 56 | # | ||
| 57 | # The default action is to redirect to the login screen. | ||
| 58 | # | ||
| 59 | # Override this method in your controllers if you want to have special | ||
| 60 | # behavior in case the user is not authorized | ||
| 61 | # to access the requested action. For example, a popup window might | ||
| 62 | # simply close itself. | ||
| 63 | def access_denied | ||
| 64 | respond_to do |format| | ||
| 65 | format.html do | ||
| 66 | store_location | ||
| 67 | redirect_to new_session_path | ||
| 68 | end | ||
| 69 | format.any do | ||
| 70 | request_http_basic_authentication 'Web Password' | ||
| 71 | end | ||
| 72 | end | ||
| 73 | end | ||
| 74 | |||
| 75 | # Store the URI of the current request in the session. | ||
| 76 | # | ||
| 77 | # We can return to this location by calling #redirect_back_or_default. | ||
| 78 | def store_location | ||
| 79 | session[:return_to] = request.request_uri | ||
| 80 | end | ||
| 81 | |||
| 82 | # Redirect to the URI stored by the most recent store_location call or | ||
| 83 | # to the passed default. | ||
| 84 | def redirect_back_or_default(default) | ||
| 85 | redirect_to(session[:return_to] || default) | ||
| 86 | session[:return_to] = nil | ||
| 87 | end | ||
| 88 | |||
| 89 | # Inclusion hook to make #current_user and #logged_in? | ||
| 90 | # available as ActionView helper methods. | ||
| 91 | def self.included(base) | ||
| 92 | base.send :helper_method, :current_user, :logged_in? | ||
| 93 | end | ||
| 94 | |||
| 95 | # Called from #current_user. First attempt to login by the user id stored in the session. | ||
| 96 | def login_from_session | ||
| 97 | self.current_user = User.find(session[:user_id]) if session[:user_id] | ||
| 98 | end | ||
| 99 | |||
| 100 | # Called from #current_user. Now, attempt to login by basic authentication information. | ||
| 101 | def login_from_basic_auth | ||
| 102 | authenticate_with_http_basic do |username, password| | ||
| 103 | self.current_user = User.authenticate(username, password) | ||
| 104 | end | ||
| 105 | end | ||
| 106 | |||
| 107 | # Called from #current_user. Finaly, attempt to login by an expiring token in the cookie. | ||
| 108 | def login_from_cookie | ||
| 109 | user = cookies[:auth_token] && User.find_by_remember_token(cookies[:auth_token]) | ||
| 110 | if user && user.remember_token? | ||
| 111 | user.remember_me | ||
| 112 | cookies[:auth_token] = { :value => user.remember_token, :expires => user.remember_token_expires_at } | ||
| 113 | self.current_user = user | ||
| 114 | end | ||
| 115 | end | ||
| 116 | end |
lib/authenticated_test_helper.rb
(10 / 0)
|   | |||
| 1 | module AuthenticatedTestHelper | ||
| 2 | # Sets the current user in the session from the user fixtures. | ||
| 3 | def login_as(user) | ||
| 4 | @request.session[:user_id] = user ? users(user).id : nil | ||
| 5 | end | ||
| 6 | |||
| 7 | def authorize_as(user) | ||
| 8 | @request.env["HTTP_AUTHORIZATION"] = user ? ActionController::HttpAuthentication::Basic.encode_credentials(users(user).login, 'test') : nil | ||
| 9 | end | ||
| 10 | end |
public/stylesheets/scaffold.css
(73 / 0)
|   | |||
| 1 | body { background-color: #fff; color: #333; } | ||
| 2 | |||
| 3 | body, p, ol, ul, td { | ||
| 4 | font-family: verdana, arial, helvetica, sans-serif; | ||
| 5 | font-size: 13px; | ||
| 6 | line-height: 18px; | ||
| 7 | } | ||
| 8 | |||
| 9 | pre { | ||
| 10 | background-color: #eee; | ||
| 11 | padding: 10px; | ||
| 12 | font-size: 11px; | ||
| 13 | } | ||
| 14 | |||
| 15 | a { color: #000; } | ||
| 16 | a:visited { color: #666; } | ||
| 17 | a:hover { color: #fff; background-color:#000; } | ||
| 18 | |||
| 19 | .fieldWithErrors { | ||
| 20 | padding: 2px; | ||
| 21 | background-color: red; | ||
| 22 | display: table; | ||
| 23 | } | ||
| 24 | |||
| 25 | #errorExplanation { | ||
| 26 | width: 400px; | ||
| 27 | border: 2px solid red; | ||
| 28 | padding: 7px; | ||
| 29 | padding-bottom: 12px; | ||
| 30 | margin-bottom: 20px; | ||
| 31 | background-color: #f0f0f0; | ||
| 32 | } | ||
| 33 | |||
| 34 | #errorExplanation h2 { | ||
| 35 | text-align: left; | ||
| 36 | font-weight: bold; | ||
| 37 | padding: 5px 5px 5px 15px; | ||
| 38 | font-size: 12px; | ||
| 39 | margin: -7px; | ||
| 40 | background-color: #c00; | ||
| 41 | color: #fff; | ||
| 42 | } | ||
| 43 | |||
| 44 | #errorExplanation p { | ||
| 45 | color: #333; | ||
| 46 | margin-bottom: 0; | ||
| 47 | padding: 5px; | ||
| 48 | } | ||
| 49 | |||
| 50 | #errorExplanation ul li { | ||
| 51 | font-size: 12px; | ||
| 52 | list-style: square; | ||
| 53 | } | ||
| 54 | |||
| 55 | div.uploadStatus { | ||
| 56 | margin: 5px; | ||
| 57 | } | ||
| 58 | |||
| 59 | div.progressBar { | ||
| 60 | margin: 5px; | ||
| 61 | } | ||
| 62 | |||
| 63 | div.progressBar div.border { | ||
| 64 | background-color: #fff; | ||
| 65 | border: 1px solid gray; | ||
| 66 | width: 100%; | ||
| 67 | } | ||
| 68 | |||
| 69 | div.progressBar div.background { | ||
| 70 | background-color: #333; | ||
| 71 | height: 18px; | ||
| 72 | width: 0%; | ||
| 73 | } |
test/fixtures/users.yml
(17 / 0)
|   | |||
| 1 | quentin: | ||
| 2 | id: 1 | ||
| 3 | login: quentin | ||
| 4 | email: quentin@example.com | ||
| 5 | salt: 7e3041ebc2fc05a40c60028e2c4901a81035d3cd | ||
| 6 | crypted_password: 00742970dc9e6319f8019fd54864d3ea740f04b1 # test | ||
| 7 | created_at: <%= 5.days.ago.to_s :db %> | ||
| 8 | |||
| 9 | |||
| 10 | |||
| 11 | aaron: | ||
| 12 | id: 2 | ||
| 13 | login: aaron | ||
| 14 | email: aaron@example.com | ||
| 15 | salt: 7e3041ebc2fc05a40c60028e2c4901a81035d3cd | ||
| 16 | crypted_password: 00742970dc9e6319f8019fd54864d3ea740f04b1 # test | ||
| 17 | created_at: <%= 1.days.ago.to_s :db %> |
|   | |||
| 1 | require File.dirname(__FILE__) + '/../test_helper' | ||
| 2 | require 'sessions_controller' | ||
| 3 | |||
| 4 | # Re-raise errors caught by the controller. | ||
| 5 | class SessionsController; def rescue_action(e) raise e end; end | ||
| 6 | |||
| 7 | class SessionsControllerTest < Test::Unit::TestCase | ||
| 8 | # Be sure to include AuthenticatedTestHelper in test/test_helper.rb instead | ||
| 9 | # Then, you can remove it from this and the units test. | ||
| 10 | include AuthenticatedTestHelper | ||
| 11 | |||
| 12 | fixtures :users | ||
| 13 | |||
| 14 | def setup | ||
| 15 | @controller = SessionsController.new | ||
| 16 | @request = ActionController::TestRequest.new | ||
| 17 | @response = ActionController::TestResponse.new | ||
| 18 | end | ||
| 19 | |||
| 20 | def test_should_login_and_redirect | ||
| 21 | post :create, :login => 'quentin', :password => 'test' | ||
| 22 | assert session[:user_id] | ||
| 23 | assert_response :redirect | ||
| 24 | end | ||
| 25 | |||
| 26 | def test_should_fail_login_and_not_redirect | ||
| 27 | post :create, :login => 'quentin', :password => 'bad password' | ||
| 28 | assert_nil session[:user_id] | ||
| 29 | assert_response :success | ||
| 30 | end | ||
| 31 | |||
| 32 | def test_should_logout | ||
| 33 | login_as :quentin | ||
| 34 | get :destroy | ||
| 35 | assert_nil session[:user_id] | ||
| 36 | assert_response :redirect | ||
| 37 | end | ||
| 38 | |||
| 39 | def test_should_remember_me | ||
| 40 | post :create, :login => 'quentin', :password => 'test', :remember_me => "1" | ||
| 41 | assert_not_nil @response.cookies["auth_token"] | ||
| 42 | end | ||
| 43 | |||
| 44 | def test_should_not_remember_me | ||
| 45 | post :create, :login => 'quentin', :password => 'test', :remember_me => "0" | ||
| 46 | assert_nil @response.cookies["auth_token"] | ||
| 47 | end | ||
| 48 | |||
| 49 | def test_should_delete_token_on_logout | ||
| 50 | login_as :quentin | ||
| 51 | get :destroy | ||
| 52 | assert_equal @response.cookies["auth_token"], [] | ||
| 53 | end | ||
| 54 | |||
| 55 | def test_should_login_with_cookie | ||
| 56 | users(:quentin).remember_me | ||
| 57 | @request.cookies["auth_token"] = cookie_for(:quentin) | ||
| 58 | get :new | ||
| 59 | assert @controller.send(:logged_in?) | ||
| 60 | end | ||
| 61 | |||
| 62 | def test_should_fail_expired_cookie_login | ||
| 63 | users(:quentin).remember_me | ||
| 64 | users(:quentin).update_attribute :remember_token_expires_at, 5.minutes.ago | ||
| 65 | @request.cookies["auth_token"] = cookie_for(:quentin) | ||
| 66 | get :new | ||
| 67 | assert !@controller.send(:logged_in?) | ||
| 68 | end | ||
| 69 | |||
| 70 | def test_should_fail_cookie_login | ||
| 71 | users(:quentin).remember_me | ||
| 72 | @request.cookies["auth_token"] = auth_token('invalid_auth_token') | ||
| 73 | get :new | ||
| 74 | assert !@controller.send(:logged_in?) | ||
| 75 | end | ||
| 76 | |||
| 77 | protected | ||
| 78 | def auth_token(token) | ||
| 79 | CGI::Cookie.new('name' => 'auth_token', 'value' => token) | ||
| 80 | end | ||
| 81 | |||
| 82 | def cookie_for(user) | ||
| 83 | auth_token users(user).remember_token | ||
| 84 | end | ||
| 85 | end |
|   | |||
| 1 | require File.dirname(__FILE__) + '/../test_helper' | ||
| 2 | require 'users_controller' | ||
| 3 | |||
| 4 | # Re-raise errors caught by the controller. | ||
| 5 | class UsersController; def rescue_action(e) raise e end; end | ||
| 6 | |||
| 7 | class UsersControllerTest < Test::Unit::TestCase | ||
| 8 | # Be sure to include AuthenticatedTestHelper in test/test_helper.rb instead | ||
| 9 | # Then, you can remove it from this and the units test. | ||
| 10 | include AuthenticatedTestHelper | ||
| 11 | |||
| 12 | fixtures :users | ||
| 13 | |||
| 14 | def setup | ||
| 15 | @controller = UsersController.new | ||
| 16 | @request = ActionController::TestRequest.new | ||
| 17 | @response = ActionController::TestResponse.new | ||
| 18 | end | ||
| 19 | |||
| 20 | def test_should_allow_signup | ||
| 21 | assert_difference 'User.count' do | ||
| 22 | create_user | ||
| 23 | assert_response :redirect | ||
| 24 | end | ||
| 25 | end | ||
| 26 | |||
| 27 | def test_should_require_login_on_signup | ||
| 28 | assert_no_difference 'User.count' do | ||
| 29 | create_user(:login => nil) | ||
| 30 | assert assigns(:user).errors.on(:login) | ||
| 31 | assert_response :success | ||
| 32 | end | ||
| 33 | end | ||
| 34 | |||
| 35 | def test_should_require_password_on_signup | ||
| 36 | assert_no_difference 'User.count' do | ||
| 37 | create_user(:password => nil) | ||
| 38 | assert assigns(:user).errors.on(:password) | ||
| 39 | assert_response :success | ||
| 40 | end | ||
| 41 | end | ||
| 42 | |||
| 43 | def test_should_require_password_confirmation_on_signup | ||
| 44 | assert_no_difference 'User.count' do | ||
| 45 | create_user(:password_confirmation => nil) | ||
| 46 | assert assigns(:user).errors.on(:password_confirmation) | ||
| 47 | assert_response :success | ||
| 48 | end | ||
| 49 | end | ||
| 50 | |||
| 51 | def test_should_require_email_on_signup | ||
| 52 | assert_no_difference 'User.count' do | ||
| 53 | create_user(:email => nil) | ||
| 54 | assert assigns(:user).errors.on(:email) | ||
| 55 | assert_response :success | ||
| 56 | end | ||
| 57 | end | ||
| 58 | |||
| 59 | |||
| 60 | protected | ||
| 61 | def create_user(options = {}) | ||
| 62 | post :create, :user => { :login => 'quire', :email => 'quire@example.com', | ||
| 63 | :password => 'quire', :password_confirmation => 'quire' }.merge(options) | ||
| 64 | end | ||
| 65 | end |
test/unit/user_test.rb
(101 / 0)
|   | |||
| 1 | require File.dirname(__FILE__) + '/../test_helper' | ||
| 2 | |||
| 3 | class UserTest < Test::Unit::TestCase | ||
| 4 | # Be sure to include AuthenticatedTestHelper in test/test_helper.rb instead. | ||
| 5 | # Then, you can remove it from this and the functional test. | ||
| 6 | include AuthenticatedTestHelper | ||
| 7 | fixtures :users | ||
| 8 | |||
| 9 | def test_should_create_user | ||
| 10 | assert_difference 'User.count' do | ||
| 11 | user = create_user | ||
| 12 | assert !user.new_record?, "#{user.errors.full_messages.to_sentence}" | ||
| 13 | end | ||
| 14 | end | ||
| 15 | |||
| 16 | def test_should_require_login | ||
| 17 | assert_no_difference 'User.count' do | ||
| 18 | u = create_user(:login => nil) | ||
| 19 | assert u.errors.on(:login) | ||
| 20 | end | ||
| 21 | end | ||
| 22 | |||
| 23 | def test_should_require_password | ||
| 24 | assert_no_difference 'User.count' do | ||
| 25 | u = create_user(:password => nil) | ||
| 26 | assert u.errors.on(:password) | ||
| 27 | end | ||
| 28 | end | ||
| 29 | |||
| 30 | def test_should_require_password_confirmation | ||
| 31 | assert_no_difference 'User.count' do | ||
| 32 | u = create_user(:password_confirmation => nil) | ||
| 33 | assert u.errors.on(:password_confirmation) | ||
| 34 | end | ||
| 35 | end | ||
| 36 | |||
| 37 | def test_should_require_email | ||
| 38 | assert_no_difference 'User.count' do | ||
| 39 | u = create_user(:email => nil) | ||
| 40 | assert u.errors.on(:email) | ||
| 41 | end | ||
| 42 | end | ||
| 43 | |||
| 44 | def test_should_reset_password | ||
| 45 | users(:quentin).update_attributes(:password => 'new password', :password_confirmation => 'new password') | ||
| 46 | assert_equal users(:quentin), User.authenticate('quentin', 'new password') | ||
| 47 | end | ||
| 48 | |||
| 49 | def test_should_not_rehash_password | ||
| 50 | users(:quentin).update_attributes(:login => 'quentin2') | ||
| 51 | assert_equal users(:quentin), User.authenticate('quentin2', 'test') | ||
| 52 | end | ||
| 53 | |||
| 54 | def test_should_authenticate_user | ||
| 55 | assert_equal users(:quentin), User.authenticate('quentin', 'test') | ||
| 56 | end | ||
| 57 | |||
| 58 | def test_should_set_remember_token | ||
| 59 | users(:quentin).remember_me | ||
| 60 | assert_not_nil users(:quentin).remember_token | ||
| 61 | assert_not_nil users(:quentin).remember_token_expires_at | ||
| 62 | end | ||
| 63 | |||
| 64 | def test_should_unset_remember_token | ||
| 65 | users(:quentin).remember_me | ||
| 66 | assert_not_nil users(:quentin).remember_token | ||
| 67 | users(:quentin).forget_me | ||
| 68 | assert_nil users(:quentin).remember_token | ||
| 69 | end | ||
| 70 | |||
| 71 | def test_should_remember_me_for_one_week | ||
| 72 | before = 1.week.from_now.utc | ||
| 73 | users(:quentin).remember_me_for 1.week | ||
| 74 | after = 1.week.from_now.utc | ||
| 75 | assert_not_nil users(:quentin).remember_token | ||
| 76 | assert_not_nil users(:quentin).remember_token_expires_at | ||
| 77 | assert users(:quentin).remember_token_expires_at.between?(before, after) | ||
| 78 | end | ||
| 79 | |||
| 80 | def test_should_remember_me_until_one_week | ||
| 81 | time = 1.week.from_now.utc | ||
| 82 | users(:quentin).remember_me_until time | ||
| 83 | assert_not_nil users(:quentin).remember_token | ||
| 84 | assert_not_nil users(:quentin).remember_token_expires_at | ||
| 85 | assert_equal users(:quentin).remember_token_expires_at, time | ||
| 86 | end | ||
| 87 | |||
| 88 | def test_should_remember_me_default_two_weeks | ||
| 89 | before = 2.weeks.from_now.utc | ||
| 90 | users(:quentin).remember_me | ||
| 91 | after = 2.weeks.from_now.utc | ||
| 92 | assert_not_nil users(:quentin).remember_token | ||
| 93 | assert_not_nil users(:quentin).remember_token_expires_at | ||
| 94 | assert users(:quentin).remember_token_expires_at.between?(before, after) | ||
| 95 | end | ||
| 96 | |||
| 97 | protected | ||
| 98 | def create_user(options = {}) | ||
| 99 | User.create({ :login => 'quire', :email => 'quire@example.com', :password => 'quire', :password_confirmation => 'quire' }.merge(options)) | ||
| 100 | end | ||
| 101 | end |

