vita-clearance 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/CHANGELOG.textile +123 -0
  2. data/LICENSE +21 -0
  3. data/README.textile +109 -0
  4. data/Rakefile +73 -0
  5. data/TODO.textile +6 -0
  6. data/app/controllers/clearance/confirmations_controller.rb +47 -0
  7. data/app/controllers/clearance/passwords_controller.rb +65 -0
  8. data/app/controllers/clearance/sessions_controller.rb +62 -0
  9. data/app/controllers/clearance/users_controller.rb +30 -0
  10. data/app/models/clearance_mailer.rb +19 -0
  11. data/app/views/clearance_mailer/change_password.html.erb +7 -0
  12. data/app/views/clearance_mailer/confirmation.html.erb +2 -0
  13. data/app/views/passwords/edit.html.erb +23 -0
  14. data/app/views/passwords/new.html.erb +15 -0
  15. data/app/views/sessions/new.html.erb +28 -0
  16. data/app/views/users/_form.html.erb +13 -0
  17. data/app/views/users/new.html.erb +6 -0
  18. data/config/clearance_routes.rb +19 -0
  19. data/generators/clearance/USAGE +1 -0
  20. data/generators/clearance/clearance_generator.rb +41 -0
  21. data/generators/clearance/lib/insert_commands.rb +103 -0
  22. data/generators/clearance/lib/rake_commands.rb +22 -0
  23. data/generators/clearance/templates/README +22 -0
  24. data/generators/clearance/templates/factories.rb +13 -0
  25. data/generators/clearance/templates/migrations/create_users.rb +20 -0
  26. data/generators/clearance/templates/migrations/update_users.rb +41 -0
  27. data/generators/clearance/templates/user.rb +3 -0
  28. data/generators/clearance_features/USAGE +1 -0
  29. data/generators/clearance_features/clearance_features_generator.rb +20 -0
  30. data/generators/clearance_features/templates/features/password_reset.feature +31 -0
  31. data/generators/clearance_features/templates/features/sign_in.feature +41 -0
  32. data/generators/clearance_features/templates/features/sign_out.feature +22 -0
  33. data/generators/clearance_features/templates/features/sign_up.feature +30 -0
  34. data/generators/clearance_features/templates/features/step_definitions/clearance_steps.rb +110 -0
  35. data/generators/clearance_features/templates/features/step_definitions/factory_girl_steps.rb +5 -0
  36. data/generators/clearance_features/templates/features/support/paths.rb +22 -0
  37. data/lib/clearance/authentication.rb +80 -0
  38. data/lib/clearance/extensions/errors.rb +4 -0
  39. data/lib/clearance/extensions/rescue.rb +1 -0
  40. data/lib/clearance/user.rb +114 -0
  41. data/lib/clearance.rb +15 -0
  42. data/rails/init.rb +1 -0
  43. data/shoulda_macros/clearance.rb +248 -0
  44. metadata +129 -0
@@ -0,0 +1,19 @@
1
+ ActionController::Routing::Routes.draw do |map|
2
+ map.resources :passwords,
3
+ :controller => 'clearance/passwords',
4
+ :only => [:new, :create]
5
+
6
+ map.resource :session,
7
+ :controller => 'clearance/sessions',
8
+ :only => [:new, :create, :destroy]
9
+
10
+ map.resources :users, :controller => 'clearance/users' do |users|
11
+ users.resource :password,
12
+ :controller => 'clearance/passwords',
13
+ :only => [:create, :edit, :update]
14
+
15
+ users.resource :confirmation,
16
+ :controller => 'clearance/confirmations',
17
+ :only => [:new, :create]
18
+ end
19
+ end
@@ -0,0 +1 @@
1
+ script/generate clearance
@@ -0,0 +1,41 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/lib/insert_commands.rb")
2
+ require File.expand_path(File.dirname(__FILE__) + "/lib/rake_commands.rb")
3
+ require 'factory_girl'
4
+
5
+ class ClearanceGenerator < Rails::Generator::Base
6
+
7
+ def manifest
8
+ record do |m|
9
+ m.insert_into "app/controllers/application_controller.rb",
10
+ "include Clearance::Authentication"
11
+
12
+ user_model = "app/models/user.rb"
13
+ if File.exists?(user_model)
14
+ m.insert_into user_model, "include Clearance::User"
15
+ else
16
+ m.directory File.join("app", "models")
17
+ m.file "user.rb", user_model
18
+ end
19
+
20
+ m.directory File.join("test", "factories")
21
+ m.file "factories.rb", "test/factories/clearance.rb"
22
+
23
+ m.migration_template "migrations/#{migration_name}.rb",
24
+ 'db/migrate',
25
+ :migration_file_name => "clearance_#{migration_name}"
26
+
27
+ m.readme "README"
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def migration_name
34
+ if ActiveRecord::Base.connection.table_exists?(:users)
35
+ 'update_users'
36
+ else
37
+ 'create_users'
38
+ end
39
+ end
40
+
41
+ end
@@ -0,0 +1,103 @@
1
+ # Mostly pinched from http://github.com/ryanb/nifty-generators/tree/master
2
+
3
+ Rails::Generator::Commands::Base.class_eval do
4
+ def file_contains?(relative_destination, line)
5
+ File.read(destination_path(relative_destination)).include?(line)
6
+ end
7
+ end
8
+
9
+ Rails::Generator::Commands::Create.class_eval do
10
+
11
+ def route_resources(resource_list)
12
+ sentinel = 'ActionController::Routing::Routes.draw do |map|'
13
+
14
+ logger.route "map.resources #{resource_list}"
15
+ unless options[:pretend] || file_contains?('config/routes.rb', resource_list)
16
+ gsub_file 'config/routes.rb', /(#{Regexp.escape(sentinel)})/mi do |match|
17
+ "#{match}\n map.resources #{resource_list}"
18
+ end
19
+ end
20
+ end
21
+
22
+ def route_resource(resource_list)
23
+ sentinel = 'ActionController::Routing::Routes.draw do |map|'
24
+
25
+ logger.route "map.resource #{resource_list}"
26
+ unless options[:pretend] || file_contains?('config/routes.rb', resource_list)
27
+ gsub_file 'config/routes.rb', /(#{Regexp.escape(sentinel)})/mi do |match|
28
+ "#{match}\n map.resource #{resource_list}"
29
+ end
30
+ end
31
+ end
32
+
33
+ def route_name(name, path, route_options = {})
34
+ sentinel = 'ActionController::Routing::Routes.draw do |map|'
35
+
36
+ logger.route "map.#{name} '#{path}', :controller => '#{route_options[:controller]}', :action => '#{route_options[:action]}'"
37
+ unless options[:pretend]
38
+ gsub_file_once 'config/routes.rb', /(#{Regexp.escape(sentinel)})/mi do |match|
39
+ "#{match}\n map.#{name} '#{path}', :controller => '#{route_options[:controller]}', :action => '#{route_options[:action]}'"
40
+ end
41
+ end
42
+ end
43
+
44
+ def insert_into(file, line)
45
+ logger.insert "#{line} into #{file}"
46
+ unless options[:pretend] || file_contains?(file, line)
47
+ gsub_file file, /^(class|module) .+$/ do |match|
48
+ "#{match}\n #{line}"
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ Rails::Generator::Commands::Destroy.class_eval do
55
+ def route_resource(resource_list)
56
+ look_for = " map.resource #{resource_list}\n".gsub(/[\[\]]/, '\\\\\0')
57
+ logger.route "map.resource #{resource_list} #{look_for}"
58
+ unless options[:pretend]
59
+ gsub_file 'config/routes.rb', /(#{look_for})/mi, ''
60
+ end
61
+ end
62
+
63
+ def route_resources(resource_list)
64
+ look_for = " map.resources #{resource_list}\n".gsub(/[\[\]]/, '\\\\\0')
65
+ logger.route "map.resources #{resource_list} #{look_for}"
66
+ unless options[:pretend]
67
+ gsub_file 'config/routes.rb', /(#{look_for})/mi, ''
68
+ end
69
+ end
70
+
71
+ def route_name(name, path, route_options = {})
72
+ look_for = "\n map.#{name} '#{path}', :controller => '#{route_options[:controller]}', :action => '#{route_options[:action]}'"
73
+ logger.route "map.#{name} '#{path}', :controller => '#{route_options[:controller]}', :action => '#{route_options[:action]}'"
74
+ unless options[:pretend]
75
+ gsub_file 'config/routes.rb', /(#{look_for})/mi, ''
76
+ end
77
+ end
78
+
79
+ def insert_into(file, line)
80
+ logger.remove "#{line} from #{file}"
81
+ unless options[:pretend]
82
+ gsub_file file, "\n #{line}", ''
83
+ end
84
+ end
85
+ end
86
+
87
+ Rails::Generator::Commands::List.class_eval do
88
+ def route_resource(resources_list)
89
+ logger.route "map.resource #{resource_list}"
90
+ end
91
+
92
+ def route_resources(resources_list)
93
+ logger.route "map.resource #{resource_list}"
94
+ end
95
+
96
+ def route_name(name, path, options = {})
97
+ logger.route "map.#{name} '#{path}', :controller => '{options[:controller]}', :action => '#{options[:action]}'"
98
+ end
99
+
100
+ def insert_into(file, line)
101
+ logger.insert "#{line} into #{file}"
102
+ end
103
+ end
@@ -0,0 +1,22 @@
1
+ Rails::Generator::Commands::Create.class_eval do
2
+ def rake_db_migrate
3
+ logger.rake "db:migrate"
4
+ unless system("rake db:migrate")
5
+ logger.rake "db:migrate failed. Rolling back"
6
+ command(:destroy).invoke!
7
+ end
8
+ end
9
+ end
10
+
11
+ Rails::Generator::Commands::Destroy.class_eval do
12
+ def rake_db_migrate
13
+ logger.rake "db:rollback"
14
+ system "rake db:rollback"
15
+ end
16
+ end
17
+
18
+ Rails::Generator::Commands::List.class_eval do
19
+ def rake_db_migrate
20
+ logger.rake "db:migrate"
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+
2
+ *******************************************************************************
3
+
4
+ Ok, enough fancy automatic stuff. Time for some old school monkey copy-pasting.
5
+
6
+ 1. Define a HOST constant in your environments files.
7
+ In config/environments/test.rb and config/environments/development.rb it can be:
8
+
9
+ HOST = "localhost"
10
+
11
+ In production.rb it must be the actual host your application is deployed to.
12
+ The constant is used by mailers to generate URLs in emails.
13
+
14
+ 2. In config/environment.rb:
15
+
16
+ DO_NOT_REPLY = "donotreply@example.com"
17
+
18
+ 3. Define root_url to *something* in your config/routes.rb:
19
+
20
+ map.root :controller => 'home'
21
+
22
+ *******************************************************************************
@@ -0,0 +1,13 @@
1
+ Factory.sequence :email do |n|
2
+ "user#{n}@example.com"
3
+ end
4
+
5
+ Factory.define :user do |user|
6
+ user.email { Factory.next :email }
7
+ user.password { "password" }
8
+ user.password_confirmation { "password" }
9
+ end
10
+
11
+ Factory.define :email_confirmed_user, :parent => :user do |user|
12
+ user.email_confirmed { true }
13
+ end
@@ -0,0 +1,20 @@
1
+ class ClearanceCreateUsers < ActiveRecord::Migration
2
+ def self.up
3
+ create_table(:users) do |t|
4
+ t.string :email
5
+ t.string :encrypted_password, :limit => 128
6
+ t.string :salt, :limit => 128
7
+ t.string :token, :limit => 128
8
+ t.datetime :token_expires_at
9
+ t.boolean :email_confirmed, :default => false, :null => false
10
+ end
11
+
12
+ add_index :users, [:id, :token]
13
+ add_index :users, :email
14
+ add_index :users, :token
15
+ end
16
+
17
+ def self.down
18
+ drop_table :users
19
+ end
20
+ end
@@ -0,0 +1,41 @@
1
+ class ClearanceUpdateUsers < ActiveRecord::Migration
2
+ def self.up
3
+ <%
4
+ existing_columns = ActiveRecord::Base.connection.columns(:users).collect { |each| each.name }
5
+ columns = [
6
+ [:email, 't.string :email'],
7
+ [:encrypted_password, 't.string :encrypted_password, :limit => 128'],
8
+ [:salt, 't.string :salt, :limit => 128'],
9
+ [:token, 't.string :token, :limit => 128'],
10
+ [:token_expires_at, 't.datetime :token_expires_at'],
11
+ [:email_confirmed, 't.boolean :email_confirmed, :default => false, :null => false']
12
+ ].delete_if {|c| existing_columns.include?(c.first.to_s)}
13
+ -%>
14
+ change_table(:users) do |t|
15
+ <% columns.each do |c| -%>
16
+ <%= c.last %>
17
+ <% end -%>
18
+ end
19
+
20
+ <%
21
+ existing_indexes = ActiveRecord::Base.connection.indexes(:users)
22
+ index_names = existing_indexes.collect { |each| each.name }
23
+ new_indexes = [
24
+ [:index_users_on_id_and_token, 'add_index :users, [:id, :token]'],
25
+ [:index_users_on_email, 'add_index :users, :email'],
26
+ [:index_users_on_token, 'add_index :users, :token']
27
+ ].delete_if { |each| index_names.include?(each.first.to_s) }
28
+ -%>
29
+ <% new_indexes.each do |each| -%>
30
+ <%= each.last %>
31
+ <% end -%>
32
+ end
33
+
34
+ def self.down
35
+ change_table(:users) do |t|
36
+ <% unless columns.empty? -%>
37
+ t.remove <%= columns.collect { |each| ":#{each.first}" }.join(',') %>
38
+ <% end -%>
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ class User < ActiveRecord::Base
2
+ include Clearance::User
3
+ end
@@ -0,0 +1 @@
1
+ script/generate clearance_features
@@ -0,0 +1,20 @@
1
+ class ClearanceFeaturesGenerator < Rails::Generator::Base
2
+
3
+ def manifest
4
+ record do |m|
5
+ m.directory File.join("features", "step_definitions")
6
+ m.directory File.join("features", "support")
7
+
8
+ ["features/step_definitions/clearance_steps.rb",
9
+ "features/step_definitions/factory_girl_steps.rb",
10
+ "features/support/paths.rb",
11
+ "features/sign_in.feature",
12
+ "features/sign_out.feature",
13
+ "features/sign_up.feature",
14
+ "features/password_reset.feature"].each do |file|
15
+ m.file file, file
16
+ end
17
+ end
18
+ end
19
+
20
+ end
@@ -0,0 +1,31 @@
1
+ Feature: Password reset
2
+ In order to sign in even if user forgot their password
3
+ A user
4
+ Should be able to reset it
5
+
6
+ Scenario: User is not signed up
7
+ Given no user exists with an email of "email@person.com"
8
+ When I request password reset link to be sent to "email@person.com"
9
+ Then I should see "Unknown email"
10
+
11
+ Scenario: User is signed up and requests password reset
12
+ Given I signed up with "email@person.com/password"
13
+ When I request password reset link to be sent to "email@person.com"
14
+ Then I should see "instructions for changing your password"
15
+ And a password reset message should be sent to "email@person.com"
16
+
17
+ Scenario: User is signed up updated his password and types wrong confirmation
18
+ Given I signed up with "email@person.com/password"
19
+ When I follow the password reset link sent to "email@person.com"
20
+ And I update my password with "newpassword/wrongconfirmation"
21
+ Then I should see error messages
22
+ And I should not be signed in
23
+
24
+ Scenario: User is signed up and updates his password
25
+ Given I signed up with "email@person.com/password"
26
+ When I follow the password reset link sent to "email@person.com"
27
+ And I update my password with "newpassword/newpassword"
28
+ Then I should be signed in
29
+ When I sign out
30
+ And I sign in as "email@person.com/newpassword"
31
+ Then I should be signed in
@@ -0,0 +1,41 @@
1
+ Feature: Sign in
2
+ In order to get access to protected sections of the site
3
+ A user
4
+ Should be able to sign in
5
+
6
+ Scenario: User is not signed up
7
+ Given no user exists with an email of "email@person.com"
8
+ When I go to the sign in page
9
+ And I sign in as "email@person.com/password"
10
+ Then I should see "Bad email or password"
11
+ And I should not be signed in
12
+
13
+ Scenario: User is not confirmed
14
+ Given I signed up with "email@person.com/password"
15
+ When I go to the sign in page
16
+ And I sign in as "email@person.com/password"
17
+ Then I should see "User has not confirmed email"
18
+ And I should not be signed in
19
+
20
+ Scenario: User enters wrong password
21
+ Given I am signed up and confirmed as "email@person.com/password"
22
+ When I go to the sign in page
23
+ And I sign in as "email@person.com/wrongpassword"
24
+ Then I should see "Bad email or password"
25
+ And I should not be signed in
26
+
27
+ Scenario: User signs in successfully
28
+ Given I am signed up and confirmed as "email@person.com/password"
29
+ When I go to the sign in page
30
+ And I sign in as "email@person.com/password"
31
+ Then I should see "Signed in successfully"
32
+ And I should be signed in
33
+
34
+ Scenario: User signs in and checks "remember me"
35
+ Given I am signed up and confirmed as "email@person.com/password"
36
+ When I go to the sign in page
37
+ And I sign in with "remember me" as "email@person.com/password"
38
+ Then I should see "Signed in successfully"
39
+ And I should be signed in
40
+ When I return next time
41
+ Then I should be signed in
@@ -0,0 +1,22 @@
1
+ Feature: Sign out
2
+ To protect my account from unauthorized access
3
+ A signed in user
4
+ Should be able to sign out
5
+
6
+ Scenario: User signs out
7
+ Given I am signed up and confirmed as "email@person.com/password"
8
+ When I sign in as "email@person.com/password"
9
+ Then I should be signed in
10
+ And I sign out
11
+ Then I should see "You have been signed out"
12
+ And I should not be signed in
13
+
14
+ Scenario: User who was remembered signs out
15
+ Given I am signed up and confirmed as "email@person.com/password"
16
+ When I sign in with "remember me" as "email@person.com/password"
17
+ Then I should be signed in
18
+ And I sign out
19
+ Then I should see "You have been signed out"
20
+ And I should not be signed in
21
+ When I return next time
22
+ Then I should not be signed in
@@ -0,0 +1,30 @@
1
+ Feature: Sign up
2
+ In order to get access to protected sections of the site
3
+ A user
4
+ Should be able to sign up
5
+
6
+ Scenario: User signs up with invalid data
7
+ When I go to the sign up page
8
+ And I fill in "Email" with "invalidemail"
9
+ And I fill in "Password" with "password"
10
+ And I fill in "Confirm password" with ""
11
+ And I press "Sign Up"
12
+ Then I should see error messages
13
+
14
+ Scenario: User signs up with valid data
15
+ When I go to the sign up page
16
+ And I fill in "Email" with "email@person.com"
17
+ And I fill in "Password" with "password"
18
+ And I fill in "Confirm password" with "password"
19
+ And I press "Sign Up"
20
+ Then I should see "instructions for confirming"
21
+ And a confirmation message should be sent to "email@person.com"
22
+
23
+ Scenario: User confirms his account
24
+ Given I signed up with "email@person.com/password"
25
+ When I follow the confirmation link sent to "email@person.com"
26
+ Then I should see "Confirmed email and signed in"
27
+ And I should be signed in
28
+
29
+
30
+
@@ -0,0 +1,110 @@
1
+ # General
2
+
3
+ Then /^I should see error messages$/ do
4
+ assert_match /error(s)? prohibited/m, response.body
5
+ end
6
+
7
+ # Database
8
+
9
+ Given /^no user exists with an email of "(.*)"$/ do |email|
10
+ assert_nil User.find_by_email(email)
11
+ end
12
+
13
+ Given /^I signed up with "(.*)\/(.*)"$/ do |email, password|
14
+ user = Factory :user,
15
+ :email => email,
16
+ :password => password,
17
+ :password_confirmation => password
18
+ end
19
+
20
+ Given /^I am signed up and confirmed as "(.*)\/(.*)"$/ do |email, password|
21
+ user = Factory :email_confirmed_user,
22
+ :email => email,
23
+ :password => password,
24
+ :password_confirmation => password
25
+ end
26
+
27
+ # Session
28
+
29
+ Then /^I should be signed in$/ do
30
+ assert_not_nil request.session[:user_id]
31
+ end
32
+
33
+ Then /^I should not be signed in$/ do
34
+ assert_nil request.session[:user_id]
35
+ end
36
+
37
+ When /^session is cleared$/ do
38
+ request.session[:user_id] = nil
39
+ end
40
+
41
+ # Emails
42
+
43
+ Then /^a confirmation message should be sent to "(.*)"$/ do |email|
44
+ user = User.find_by_email(email)
45
+ sent = ActionMailer::Base.deliveries.first
46
+ assert_equal [user.email], sent.to
47
+ assert_match /confirm/i, sent.subject
48
+ assert !user.token.blank?
49
+ assert_match /#{user.token}/, sent.body
50
+ end
51
+
52
+ When /^I follow the confirmation link sent to "(.*)"$/ do |email|
53
+ user = User.find_by_email(email)
54
+ visit new_user_confirmation_path(:user_id => user, :token => user.token)
55
+ end
56
+
57
+ Then /^a password reset message should be sent to "(.*)"$/ do |email|
58
+ user = User.find_by_email(email)
59
+ sent = ActionMailer::Base.deliveries.first
60
+ assert_equal [user.email], sent.to
61
+ assert_match /password/i, sent.subject
62
+ assert !user.token.blank?
63
+ assert_match /#{user.token}/, sent.body
64
+ end
65
+
66
+ When /^I follow the password reset link sent to "(.*)"$/ do |email|
67
+ user = User.find_by_email(email)
68
+ visit edit_user_password_path(:user_id => user, :token => user.token)
69
+ end
70
+
71
+ When /^I try to change the password of "(.*)" without token$/ do |email|
72
+ user = User.find_by_email(email)
73
+ visit edit_user_password_path(:user_id => user)
74
+ end
75
+
76
+ Then /^I should be forbidden$/ do
77
+ assert_response :forbidden
78
+ end
79
+
80
+
81
+ # Actions
82
+
83
+ When /^I sign in( with "remember me")? as "(.*)\/(.*)"$/ do |remember, email, password|
84
+ When %{I go to the sign in page}
85
+ And %{I fill in "Email" with "#{email}"}
86
+ And %{I fill in "Password" with "#{password}"}
87
+ And %{I check "Remember me"} if remember
88
+ And %{I press "Sign In"}
89
+ end
90
+
91
+ When /^I sign out$/ do
92
+ visit '/session', :delete
93
+ end
94
+
95
+ When /^I request password reset link to be sent to "(.*)"$/ do |email|
96
+ When %{I go to the password reset request page}
97
+ And %{I fill in "Email address" with "#{email}"}
98
+ And %{I press "Reset password"}
99
+ end
100
+
101
+ When /^I update my password with "(.*)\/(.*)"$/ do |password, confirmation|
102
+ And %{I fill in "Choose password" with "#{password}"}
103
+ And %{I fill in "Confirm password" with "#{confirmation}"}
104
+ And %{I press "Save this password"}
105
+ end
106
+
107
+ When /^I return next time$/ do
108
+ When %{session is cleared}
109
+ And %{I go to the homepage}
110
+ end
@@ -0,0 +1,5 @@
1
+ Factory.factories.each do |name, factory|
2
+ Given /^an? #{name} exists with an? (.*) of "([^"]*)"$/ do |attr, value|
3
+ Factory(name, attr.gsub(' ', '_') => value)
4
+ end
5
+ end
@@ -0,0 +1,22 @@
1
+ module NavigationHelpers
2
+ def path_to(page_name)
3
+ case page_name
4
+
5
+ when /the homepage/i
6
+ root_path
7
+ when /the sign up page/i
8
+ new_user_path
9
+ when /the sign in page/i
10
+ new_session_path
11
+ when /the password reset request page/i
12
+ new_password_path
13
+
14
+ # Add more page name => path mappings here
15
+
16
+ else
17
+ raise "Can't find mapping from \"#{page_name}\" to a path."
18
+ end
19
+ end
20
+ end
21
+
22
+ World(NavigationHelpers)
@@ -0,0 +1,80 @@
1
+ module Clearance
2
+ module Authentication
3
+
4
+ def self.included(controller)
5
+ controller.send(:include, InstanceMethods)
6
+
7
+ controller.class_eval do
8
+ helper_method :current_user
9
+ helper_method :signed_in?
10
+
11
+ hide_action :current_user, :signed_in?
12
+ end
13
+ end
14
+
15
+ module InstanceMethods
16
+ def current_user
17
+ @_current_user ||= (user_from_cookie || user_from_session)
18
+ end
19
+
20
+ def signed_in?
21
+ ! current_user.nil?
22
+ end
23
+
24
+ protected
25
+
26
+ def authenticate
27
+ deny_access unless signed_in?
28
+ end
29
+
30
+ def user_from_session
31
+ if session[:user_id]
32
+ return nil unless user = ::User.find_by_id(session[:user_id])
33
+ return user if user.email_confirmed?
34
+ end
35
+ end
36
+
37
+ def user_from_cookie
38
+ if token = cookies[:remember_token]
39
+ return nil unless user = ::User.find_by_token(token)
40
+ return user if user.remember?
41
+ end
42
+ end
43
+
44
+ def sign_user_in(user)
45
+ sign_in(user)
46
+ end
47
+
48
+ def sign_in(user)
49
+ if user
50
+ session[:user_id] = user.id
51
+ end
52
+ end
53
+
54
+ def redirect_back_or(default)
55
+ session[:return_to] ||= params[:return_to]
56
+ if session[:return_to]
57
+ redirect_to(session[:return_to])
58
+ else
59
+ redirect_to(default)
60
+ end
61
+ session[:return_to] = nil
62
+ end
63
+
64
+ def redirect_to_root
65
+ redirect_to root_url
66
+ end
67
+
68
+ def store_location
69
+ session[:return_to] = request.request_uri if request.get?
70
+ end
71
+
72
+ def deny_access(flash_message = nil, opts = {})
73
+ store_location
74
+ flash[:failure] = flash_message if flash_message
75
+ redirect_to new_session_url
76
+ end
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,4 @@
1
+ module ActionController
2
+ class Forbidden < StandardError
3
+ end
4
+ end
@@ -0,0 +1 @@
1
+ ActionController::Base.rescue_responses.update('ActionController::Forbidden' => :forbidden)