caleb-restful-authentication 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. data/CHANGELOG +68 -0
  2. data/README.textile +240 -0
  3. data/Rakefile +32 -0
  4. data/TODO +15 -0
  5. data/generators/authenticated/USAGE +1 -0
  6. data/generators/authenticated/authenticated_generator.rb +508 -0
  7. data/generators/authenticated/lib/insert_routes.rb +54 -0
  8. data/generators/authenticated/templates/_model_partial.html.erb +8 -0
  9. data/generators/authenticated/templates/activation.erb +3 -0
  10. data/generators/authenticated/templates/authenticated_system.rb +189 -0
  11. data/generators/authenticated/templates/authenticated_test_helper.rb +22 -0
  12. data/generators/authenticated/templates/controller.rb +43 -0
  13. data/generators/authenticated/templates/helper.rb +2 -0
  14. data/generators/authenticated/templates/login.html.erb +21 -0
  15. data/generators/authenticated/templates/mailer.rb +33 -0
  16. data/generators/authenticated/templates/migration.rb +29 -0
  17. data/generators/authenticated/templates/model.rb +101 -0
  18. data/generators/authenticated/templates/model_controller.rb +117 -0
  19. data/generators/authenticated/templates/model_helper.rb +93 -0
  20. data/generators/authenticated/templates/model_helper_spec.rb +158 -0
  21. data/generators/authenticated/templates/observer.rb +14 -0
  22. data/generators/authenticated/templates/signup.html.erb +21 -0
  23. data/generators/authenticated/templates/signup_notification.erb +8 -0
  24. data/generators/authenticated/templates/site_keys.rb +38 -0
  25. data/generators/authenticated/templates/spec/controllers/access_control_spec.rb +90 -0
  26. data/generators/authenticated/templates/spec/controllers/authenticated_system_spec.rb +102 -0
  27. data/generators/authenticated/templates/spec/controllers/sessions_controller_spec.rb +139 -0
  28. data/generators/authenticated/templates/spec/controllers/users_controller_spec.rb +200 -0
  29. data/generators/authenticated/templates/spec/fixtures/users.yml +66 -0
  30. data/generators/authenticated/templates/spec/helpers/users_helper_spec.rb +141 -0
  31. data/generators/authenticated/templates/spec/models/user_spec.rb +295 -0
  32. data/generators/authenticated/templates/stories/rest_auth_stories.rb +22 -0
  33. data/generators/authenticated/templates/stories/rest_auth_stories_helper.rb +81 -0
  34. data/generators/authenticated/templates/stories/steps/ra_navigation_steps.rb +49 -0
  35. data/generators/authenticated/templates/stories/steps/ra_resource_steps.rb +179 -0
  36. data/generators/authenticated/templates/stories/steps/ra_response_steps.rb +171 -0
  37. data/generators/authenticated/templates/stories/steps/user_steps.rb +153 -0
  38. data/generators/authenticated/templates/stories/users/accounts.story +194 -0
  39. data/generators/authenticated/templates/stories/users/sessions.story +134 -0
  40. data/generators/authenticated/templates/test/functional_test.rb +82 -0
  41. data/generators/authenticated/templates/test/mailer_test.rb +31 -0
  42. data/generators/authenticated/templates/test/model_functional_test.rb +95 -0
  43. data/generators/authenticated/templates/test/unit_test.rb +166 -0
  44. data/init.rb +1 -0
  45. data/lib/authentication.rb +40 -0
  46. data/lib/authentication/by_cookie_token.rb +82 -0
  47. data/lib/authentication/by_password.rb +64 -0
  48. data/lib/authorization.rb +14 -0
  49. data/lib/authorization/aasm_roles.rb +64 -0
  50. data/lib/authorization/stateful_roles.rb +63 -0
  51. data/lib/trustification.rb +14 -0
  52. data/lib/trustification/email_validation.rb +20 -0
  53. data/rails/init.rb +6 -0
  54. metadata +115 -0
@@ -0,0 +1,82 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ require '<%= controller_file_name %>_controller'
3
+
4
+ # Re-raise errors caught by the controller.
5
+ class <%= controller_class_name %>Controller; def rescue_action(e) raise e end; end
6
+
7
+ class <%= controller_class_name %>ControllerTest < ActionController::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 :<%= table_name %>
13
+
14
+ def test_should_login_and_redirect
15
+ post :create, :<%= options[:login_field_name] -%> => 'quentin<%= "@example.com" if options[:email_as_login] -%>', :password => 'monkey'
16
+ assert session[:<%= file_name %>_id]
17
+ assert_response :redirect
18
+ end
19
+
20
+ def test_should_fail_login_and_not_redirect
21
+ post :create, :<%= options[:login_field_name] -%> => 'quentin<%= "@example.com" if options[:email_as_login] -%>', :password => 'bad password'
22
+ assert_nil session[:<%= file_name %>_id]
23
+ assert_response :success
24
+ end
25
+
26
+ def test_should_logout
27
+ login_as :quentin
28
+ get :destroy
29
+ assert_nil session[:<%= file_name %>_id]
30
+ assert_response :redirect
31
+ end
32
+
33
+ def test_should_remember_me
34
+ @request.cookies["auth_token"] = nil
35
+ post :create, :<%= options[:login_field_name] -%> => 'quentin<%= "@example.com" if options[:email_as_login] -%>', :password => 'monkey', :remember_me => "1"
36
+ assert_not_nil @response.cookies["auth_token"]
37
+ end
38
+
39
+ def test_should_not_remember_me
40
+ @request.cookies["auth_token"] = nil
41
+ post :create, :<%= options[:login_field_name] -%> => 'quentin<%= "@example.com" if options[:email_as_login] -%>', :password => 'monkey', :remember_me => "0"
42
+ puts @response.cookies["auth_token"]
43
+ assert @response.cookies["auth_token"].blank?
44
+ end
45
+
46
+ def test_should_delete_token_on_logout
47
+ login_as :quentin
48
+ get :destroy
49
+ assert @response.cookies["auth_token"].blank?
50
+ end
51
+
52
+ def test_should_login_with_cookie
53
+ <%= table_name %>(:quentin).remember_me
54
+ @request.cookies["auth_token"] = cookie_for(:quentin)
55
+ get :new
56
+ assert @controller.send(:logged_in?)
57
+ end
58
+
59
+ def test_should_fail_expired_cookie_login
60
+ <%= table_name %>(:quentin).remember_me
61
+ <%= table_name %>(:quentin).update_attribute :remember_token_expires_at, 5.minutes.ago
62
+ @request.cookies["auth_token"] = cookie_for(:quentin)
63
+ get :new
64
+ assert !@controller.send(:logged_in?)
65
+ end
66
+
67
+ def test_should_fail_cookie_login
68
+ <%= table_name %>(:quentin).remember_me
69
+ @request.cookies["auth_token"] = auth_token('invalid_auth_token')
70
+ get :new
71
+ assert !@controller.send(:logged_in?)
72
+ end
73
+
74
+ protected
75
+ def auth_token(token)
76
+ CGI::Cookie.new('name' => 'auth_token', 'value' => token)
77
+ end
78
+
79
+ def cookie_for(<%= file_name %>)
80
+ auth_token <%= table_name %>(<%= file_name %>).remember_token
81
+ end
82
+ end
@@ -0,0 +1,31 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ require '<%= file_name %>_mailer'
3
+
4
+ class <%= class_name %>MailerTest < Test::Unit::TestCase
5
+ FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures'
6
+ CHARSET = "utf-8"
7
+
8
+ include ActionMailer::Quoting
9
+
10
+ def setup
11
+ ActionMailer::Base.delivery_method = :test
12
+ ActionMailer::Base.perform_deliveries = true
13
+ ActionMailer::Base.deliveries = []
14
+
15
+ @expected = TMail::Mail.new
16
+ @expected.set_content_type "text", "plain", { "charset" => CHARSET }
17
+ end
18
+
19
+ def test_dummy_test
20
+ #do nothing
21
+ end
22
+
23
+ private
24
+ def read_fixture(action)
25
+ IO.readlines("#{FIXTURES_PATH}/<%= file_name %>_mailer/#{action}")
26
+ end
27
+
28
+ def encode(subject)
29
+ quoted_printable(subject, CHARSET)
30
+ end
31
+ end
@@ -0,0 +1,95 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ require '<%= model_controller_file_name %>_controller'
3
+
4
+ # Re-raise errors caught by the controller.
5
+ class <%= model_controller_class_name %>Controller; def rescue_action(e) raise e end; end
6
+
7
+ class <%= model_controller_class_name %>ControllerTest < ActionController::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 :<%= table_name %>
13
+
14
+ def test_should_allow_signup
15
+ assert_difference '<%= class_name %>.count' do
16
+ create_<%= file_name %>
17
+ assert_response :redirect
18
+ end
19
+ end
20
+
21
+ <% unless options[:email_as_login] -%>
22
+ def test_should_require_login_on_signup
23
+ assert_no_difference '<%= class_name %>.count' do
24
+ create_<%= file_name %>(:login => nil)
25
+ assert assigns(:<%= file_name %>).errors.on(:login)
26
+ assert_response :success
27
+ end
28
+ end
29
+ <% end -%>
30
+
31
+ def test_should_require_password_on_signup
32
+ assert_no_difference '<%= class_name %>.count' do
33
+ create_<%= file_name %>(:password => nil)
34
+ assert assigns(:<%= file_name %>).errors.on(:password)
35
+ assert_response :success
36
+ end
37
+ end
38
+
39
+ def test_should_require_password_confirmation_on_signup
40
+ assert_no_difference '<%= class_name %>.count' do
41
+ create_<%= file_name %>(:password_confirmation => nil)
42
+ assert assigns(:<%= file_name %>).errors.on(:password_confirmation)
43
+ assert_response :success
44
+ end
45
+ end
46
+
47
+ def test_should_require_email_on_signup
48
+ assert_no_difference '<%= class_name %>.count' do
49
+ create_<%= file_name %>(:email => nil)
50
+ assert assigns(:<%= file_name %>).errors.on(:email)
51
+ assert_response :success
52
+ end
53
+ end
54
+ <% if options[:stateful] %>
55
+ def test_should_sign_up_user_in_pending_state
56
+ create_<%= file_name %>
57
+ assigns(:<%= file_name %>).reload
58
+ assert assigns(:<%= file_name %>).pending?
59
+ end<% end %>
60
+
61
+ <% if options[:include_activation] %>
62
+ def test_should_sign_up_user_with_activation_code
63
+ create_<%= file_name %>
64
+ assigns(:<%= file_name %>).reload
65
+ assert_not_nil assigns(:<%= file_name %>).activation_code
66
+ end
67
+
68
+ def test_should_activate_user
69
+ assert_nil <%= class_name %>.authenticate('aaron<%= "@example.com" if options[:email_as_login] -%>', 'test')
70
+ get :activate, :activation_code => <%= table_name %>(:aaron).activation_code
71
+ assert_redirected_to '/<%= controller_routing_path %>/new'
72
+ assert_not_nil flash[:notice]
73
+ assert_equal <%= table_name %>(:aaron), <%= class_name %>.authenticate('aaron<%= "@example.com" if options[:email_as_login] -%>', 'monkey')
74
+ end
75
+
76
+ def test_should_not_activate_user_without_key
77
+ get :activate
78
+ assert_nil flash[:notice]
79
+ rescue ActionController::RoutingError
80
+ # in the event your routes deny this, we'll just bow out gracefully.
81
+ end
82
+
83
+ def test_should_not_activate_user_with_blank_key
84
+ get :activate, :activation_code => ''
85
+ assert_nil flash[:notice]
86
+ rescue ActionController::RoutingError
87
+ # well played, sir
88
+ end<% end %>
89
+
90
+ protected
91
+ def create_<%= file_name %>(options = {})
92
+ post :create, :<%= file_name %> => { <% unless options[:email_as_login] -%>:login => 'quire', <% end -%>:email => 'quire@example.com',
93
+ :password => 'quire69', :password_confirmation => 'quire69' }.merge(options)
94
+ end
95
+ end
@@ -0,0 +1,166 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class <%= class_name %>Test < ActiveSupport::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 :<%= table_name %>
8
+
9
+ def test_should_create_<%= file_name %>
10
+ assert_difference '<%= class_name %>.count' do
11
+ <%= file_name %> = create_<%= file_name %>
12
+ assert !<%= file_name %>.new_record?, "#{<%= file_name %>.errors.full_messages.to_sentence}"
13
+ end
14
+ end
15
+ <% if options[:include_activation] %>
16
+ def test_should_initialize_activation_code_upon_creation
17
+ <%= file_name %> = create_<%= file_name %>
18
+ <%= file_name %>.reload
19
+ assert_not_nil <%= file_name %>.activation_code
20
+ end
21
+ <% end %><% if options[:stateful] %>
22
+ def test_should_create_and_start_in_pending_state
23
+ <%= file_name %> = create_<%= file_name %>
24
+ <%= file_name %>.reload
25
+ assert <%= file_name %>.pending?
26
+ end
27
+
28
+ <% end %>
29
+ <% unless options[:email_as_login] -%>
30
+ def test_should_require_login
31
+ assert_no_difference '<%= class_name %>.count' do
32
+ u = create_<%= file_name %>(:login => nil)
33
+ assert u.errors.on(:login)
34
+ end
35
+ end
36
+ <% end -%>
37
+
38
+ def test_should_require_password
39
+ assert_no_difference '<%= class_name %>.count' do
40
+ u = create_<%= file_name %>(:password => nil)
41
+ assert u.errors.on(:password)
42
+ end
43
+ end
44
+
45
+ def test_should_require_password_confirmation
46
+ assert_no_difference '<%= class_name %>.count' do
47
+ u = create_<%= file_name %>(:password_confirmation => nil)
48
+ assert u.errors.on(:password_confirmation)
49
+ end
50
+ end
51
+
52
+ def test_should_require_email
53
+ assert_no_difference '<%= class_name %>.count' do
54
+ u = create_<%= file_name %>(:email => nil)
55
+ assert u.errors.on(:email)
56
+ end
57
+ end
58
+
59
+ def test_should_reset_password
60
+ <%= table_name %>(:quentin).update_attributes(:password => 'new password', :password_confirmation => 'new password')
61
+ assert_equal <%= table_name %>(:quentin), <%= class_name %>.authenticate('quentin<%= "@example.com" if options[:email_as_login] -%>', 'new password')
62
+ end
63
+
64
+ def test_should_not_rehash_password
65
+ <%= table_name %>(:quentin).update_attributes(:<%= options[:login_field_name] -%> => 'quentin2')
66
+ assert_equal <%= table_name %>(:quentin), <%= class_name %>.authenticate('quentin2<%= "@example.com" if options[:email_as_login] -%>', 'monkey')
67
+ end
68
+
69
+ def test_should_authenticate_<%= file_name %>
70
+ assert_equal <%= table_name %>(:quentin), <%= class_name %>.authenticate('quentin<%= "@example.com" if options[:email_as_login] -%>', 'monkey')
71
+ end
72
+
73
+ def test_should_set_remember_token
74
+ <%= table_name %>(:quentin).remember_me
75
+ assert_not_nil <%= table_name %>(:quentin).remember_token
76
+ assert_not_nil <%= table_name %>(:quentin).remember_token_expires_at
77
+ end
78
+
79
+ def test_should_unset_remember_token
80
+ <%= table_name %>(:quentin).remember_me
81
+ assert_not_nil <%= table_name %>(:quentin).remember_token
82
+ <%= table_name %>(:quentin).forget_me
83
+ assert_nil <%= table_name %>(:quentin).remember_token
84
+ end
85
+
86
+ def test_should_remember_me_for_one_week
87
+ before = 1.week.from_now.utc
88
+ <%= table_name %>(:quentin).remember_me_for 1.week
89
+ after = 1.week.from_now.utc
90
+ assert_not_nil <%= table_name %>(:quentin).remember_token
91
+ assert_not_nil <%= table_name %>(:quentin).remember_token_expires_at
92
+ assert <%= table_name %>(:quentin).remember_token_expires_at.between?(before, after)
93
+ end
94
+
95
+ def test_should_remember_me_until_one_week
96
+ time = 1.week.from_now.utc
97
+ <%= table_name %>(:quentin).remember_me_until time
98
+ assert_not_nil <%= table_name %>(:quentin).remember_token
99
+ assert_not_nil <%= table_name %>(:quentin).remember_token_expires_at
100
+ assert_equal <%= table_name %>(:quentin).remember_token_expires_at, time
101
+ end
102
+
103
+ def test_should_remember_me_default_two_weeks
104
+ before = 2.weeks.from_now.utc
105
+ <%= table_name %>(:quentin).remember_me
106
+ after = 2.weeks.from_now.utc
107
+ assert_not_nil <%= table_name %>(:quentin).remember_token
108
+ assert_not_nil <%= table_name %>(:quentin).remember_token_expires_at
109
+ assert <%= table_name %>(:quentin).remember_token_expires_at.between?(before, after)
110
+ end
111
+ <% if options[:stateful] %>
112
+ def test_should_register_passive_<%= file_name %>
113
+ <%= file_name %> = create_<%= file_name %>(:password => nil, :password_confirmation => nil)
114
+ assert <%= file_name %>.passive?
115
+ <%= file_name %>.update_attributes(:password => 'new password', :password_confirmation => 'new password')
116
+ <%= file_name %>.register!
117
+ assert <%= file_name %>.pending?
118
+ end
119
+
120
+ def test_should_suspend_<%= file_name %>
121
+ <%= table_name %>(:quentin).suspend!
122
+ assert <%= table_name %>(:quentin).suspended?
123
+ end
124
+
125
+ def test_suspended_<%= file_name %>_should_not_authenticate
126
+ <%= table_name %>(:quentin).suspend!
127
+ assert_not_equal <%= table_name %>(:quentin), <%= class_name %>.authenticate('quentin<%= "@example.com" if options[:email_as_login] -%>', 'test')
128
+ end
129
+
130
+ def test_should_unsuspend_<%= file_name %>_to_active_state
131
+ <%= table_name %>(:quentin).suspend!
132
+ assert <%= table_name %>(:quentin).suspended?
133
+ <%= table_name %>(:quentin).unsuspend!
134
+ assert <%= table_name %>(:quentin).active?
135
+ end
136
+
137
+ def test_should_unsuspend_<%= file_name %>_with_nil_activation_code_and_activated_at_to_passive_state
138
+ <%= table_name %>(:quentin).suspend!
139
+ <%= class_name %>.update_all :activation_code => nil, :activated_at => nil
140
+ assert <%= table_name %>(:quentin).suspended?
141
+ <%= table_name %>(:quentin).reload.unsuspend!
142
+ assert <%= table_name %>(:quentin).passive?
143
+ end
144
+
145
+ def test_should_unsuspend_<%= file_name %>_with_activation_code_and_nil_activated_at_to_pending_state
146
+ <%= table_name %>(:quentin).suspend!
147
+ <%= class_name %>.update_all :activation_code => 'foo-bar', :activated_at => nil
148
+ assert <%= table_name %>(:quentin).suspended?
149
+ <%= table_name %>(:quentin).reload.unsuspend!
150
+ assert <%= table_name %>(:quentin).pending?
151
+ end
152
+
153
+ def test_should_delete_<%= file_name %>
154
+ assert_nil <%= table_name %>(:quentin).deleted_at
155
+ <%= table_name %>(:quentin).delete!
156
+ assert_not_nil <%= table_name %>(:quentin).deleted_at
157
+ assert <%= table_name %>(:quentin).deleted?
158
+ end
159
+ <% end %>
160
+ protected
161
+ def create_<%= file_name %>(options = {})
162
+ record = <%= class_name %>.new({ <% unless options[:email_as_login] -%>:login => 'quire', <% end -%>:email => 'quire@example.com', :password => 'quire69', :password_confirmation => 'quire69' }.merge(options))
163
+ record.<% if options[:stateful] %>register! if record.valid?<% else %>save<% end %>
164
+ record
165
+ end
166
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), "rails", "init")
@@ -0,0 +1,40 @@
1
+ module Authentication
2
+ mattr_accessor :login_regex, :bad_login_message,
3
+ :name_regex, :bad_name_message,
4
+ :email_name_regex, :domain_head_regex, :domain_tld_regex, :email_regex, :bad_email_message
5
+
6
+ self.login_regex = /\A\w[\w\.\-_@]+\z/ # ASCII, strict
7
+ # self.login_regex = /\A[[:alnum:]][[:alnum:]\.\-_@]+\z/ # Unicode, strict
8
+ # self.login_regex = /\A[^[:cntrl:]\\<>\/&]*\z/ # Unicode, permissive
9
+
10
+ self.bad_login_message = "use only letters, numbers, and .-_@ please.".freeze
11
+
12
+ self.name_regex = /\A[^[:cntrl:]\\<>\/&]*\z/ # Unicode, permissive
13
+ self.bad_name_message = "avoid non-printing characters and \\&gt;&lt;&amp;/ please.".freeze
14
+
15
+ self.email_name_regex = '[\w\.%\+\-]+'.freeze
16
+ self.domain_head_regex = '(?:[A-Z0-9\-]+\.)+'.freeze
17
+ self.domain_tld_regex = '(?:[A-Z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|jobs|museum)'.freeze
18
+ self.email_regex = /\A#{email_name_regex}@#{domain_head_regex}#{domain_tld_regex}\z/i
19
+ self.bad_email_message = "should look like an email address.".freeze
20
+
21
+ def self.included(recipient)
22
+ recipient.extend(ModelClassMethods)
23
+ recipient.class_eval do
24
+ include ModelInstanceMethods
25
+ end
26
+ end
27
+
28
+ module ModelClassMethods
29
+ def secure_digest(*args)
30
+ Digest::SHA1.hexdigest(args.flatten.join('--'))
31
+ end
32
+
33
+ def make_token
34
+ secure_digest(Time.now, (1..10).map{ rand.to_s })
35
+ end
36
+ end # class methods
37
+
38
+ module ModelInstanceMethods
39
+ end # instance methods
40
+ end
@@ -0,0 +1,82 @@
1
+ # -*- coding: mule-utf-8 -*-
2
+ module Authentication
3
+ module ByCookieToken
4
+ # Stuff directives into including module
5
+ def self.included(recipient)
6
+ recipient.extend(ModelClassMethods)
7
+ recipient.class_eval do
8
+ include ModelInstanceMethods
9
+ end
10
+ end
11
+
12
+ #
13
+ # Class Methods
14
+ #
15
+ module ModelClassMethods
16
+ end # class methods
17
+
18
+ #
19
+ # Instance Methods
20
+ #
21
+ module ModelInstanceMethods
22
+ def remember_token?
23
+ (!remember_token.blank?) &&
24
+ remember_token_expires_at && (Time.now.utc < remember_token_expires_at.utc)
25
+ end
26
+
27
+ # These create and unset the fields required for remembering users between browser closes
28
+ def remember_me
29
+ remember_me_for 2.weeks
30
+ end
31
+
32
+ def remember_me_for(time)
33
+ remember_me_until time.from_now.utc
34
+ end
35
+
36
+ def remember_me_until(time)
37
+ self.remember_token_expires_at = time
38
+ self.remember_token = self.class.make_token
39
+ save(false)
40
+ end
41
+
42
+ # refresh token (keeping same expires_at) if it exists
43
+ def refresh_token
44
+ if remember_token?
45
+ self.remember_token = self.class.make_token
46
+ save(false)
47
+ end
48
+ end
49
+
50
+ #
51
+ # Deletes the server-side record of the authentication token. The
52
+ # client-side (browser cookie) and server-side (this remember_token) must
53
+ # always be deleted together.
54
+ #
55
+ def forget_me
56
+ self.remember_token_expires_at = nil
57
+ self.remember_token = nil
58
+ save(false)
59
+ end
60
+ end # instance methods
61
+ end
62
+
63
+ module ByCookieTokenController
64
+ # Stuff directives into including module
65
+ def self.included( recipient )
66
+ recipient.extend( ControllerClassMethods )
67
+ recipient.class_eval do
68
+ include ControllerInstanceMethods
69
+ end
70
+ end
71
+
72
+ #
73
+ # Class Methods
74
+ #
75
+ module ControllerClassMethods
76
+ end # class methods
77
+
78
+ module ControllerInstanceMethods
79
+ end # instance methods
80
+ end
81
+ end
82
+