loyal_devise 2.1.2 → 2.1.3

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 (188) hide show
  1. data/.gitignore +2 -0
  2. data/.travis.yml +14 -9
  3. data/.yardopts +9 -0
  4. data/CHANGELOG.rdoc +60 -5
  5. data/CONTRIBUTING.md +4 -2
  6. data/Gemfile +7 -7
  7. data/Gemfile.lock +107 -101
  8. data/MIT-LICENSE +1 -1
  9. data/README.md +110 -48
  10. data/Rakefile +1 -0
  11. data/app/controllers/devise/confirmations_controller.rb +2 -4
  12. data/app/controllers/devise/omniauth_callbacks_controller.rb +0 -1
  13. data/app/controllers/devise/passwords_controller.rb +16 -5
  14. data/app/controllers/devise/registrations_controller.rb +13 -7
  15. data/app/controllers/devise/sessions_controller.rb +6 -6
  16. data/app/controllers/devise/unlocks_controller.rb +3 -4
  17. data/app/controllers/devise_controller.rb +12 -33
  18. data/app/helpers/devise_helper.rb +0 -1
  19. data/app/mailers/devise/mailer.rb +7 -8
  20. data/app/views/devise/mailer/confirmation_instructions.html.erb +1 -1
  21. data/app/views/devise/mailer/reset_password_instructions.html.erb +1 -1
  22. data/app/views/devise/registrations/edit.html.erb +5 -1
  23. data/config/locales/en.yml +48 -48
  24. data/devise.gemspec +6 -6
  25. data/devise.png +0 -0
  26. data/gemfiles/{Gemfile.rails-3.1.x → Gemfile.rails-3.2.x} +8 -12
  27. data/gemfiles/Gemfile.rails-3.2.x.lock +156 -0
  28. data/lib/devise.rb +34 -11
  29. data/lib/devise/controllers/helpers.rb +33 -7
  30. data/lib/devise/controllers/rememberable.rb +6 -3
  31. data/lib/devise/controllers/scoped_views.rb +1 -2
  32. data/lib/devise/controllers/url_helpers.rb +0 -1
  33. data/lib/devise/delegator.rb +0 -1
  34. data/lib/devise/failure_app.rb +8 -2
  35. data/lib/devise/hooks/activatable.rb +1 -2
  36. data/lib/devise/hooks/forgetable.rb +0 -1
  37. data/lib/devise/hooks/lockable.rb +1 -2
  38. data/lib/devise/hooks/rememberable.rb +1 -2
  39. data/lib/devise/hooks/timeoutable.rb +0 -1
  40. data/lib/devise/hooks/trackable.rb +0 -1
  41. data/lib/devise/mailers/helpers.rb +18 -14
  42. data/lib/devise/mapping.rb +6 -7
  43. data/lib/devise/models.rb +0 -1
  44. data/lib/devise/models/authenticatable.rb +50 -27
  45. data/lib/devise/models/confirmable.rb +37 -16
  46. data/lib/devise/models/database_authenticatable.rb +17 -3
  47. data/lib/devise/models/lockable.rb +1 -2
  48. data/lib/devise/models/omniauthable.rb +1 -2
  49. data/lib/devise/models/recoverable.rb +10 -6
  50. data/lib/devise/models/registerable.rb +0 -1
  51. data/lib/devise/models/rememberable.rb +1 -2
  52. data/lib/devise/models/timeoutable.rb +1 -2
  53. data/lib/devise/models/token_authenticatable.rb +0 -1
  54. data/lib/devise/models/trackable.rb +0 -1
  55. data/lib/devise/models/validatable.rb +0 -1
  56. data/lib/devise/modules.rb +1 -2
  57. data/lib/devise/omniauth.rb +0 -1
  58. data/lib/devise/omniauth/config.rb +0 -1
  59. data/lib/devise/omniauth/url_helpers.rb +0 -1
  60. data/lib/devise/orm/active_record.rb +1 -2
  61. data/lib/devise/orm/mongoid.rb +1 -2
  62. data/lib/devise/{param_filter.rb → parameter_filter.rb} +10 -12
  63. data/lib/devise/parameter_sanitizer.rb +59 -0
  64. data/lib/devise/rails.rb +0 -1
  65. data/lib/devise/rails/routes.rb +22 -18
  66. data/lib/devise/rails/warden_compat.rb +0 -30
  67. data/lib/devise/strategies/authenticatable.rb +8 -6
  68. data/lib/devise/strategies/base.rb +1 -2
  69. data/lib/devise/strategies/database_authenticatable.rb +1 -2
  70. data/lib/devise/strategies/rememberable.rb +1 -2
  71. data/lib/devise/strategies/token_authenticatable.rb +38 -4
  72. data/lib/devise/test_helpers.rb +0 -1
  73. data/lib/devise/time_inflector.rb +1 -2
  74. data/lib/devise/version.rb +1 -2
  75. data/lib/generators/active_record/devise_generator.rb +1 -5
  76. data/lib/generators/active_record/templates/migration.rb +0 -1
  77. data/lib/generators/active_record/templates/migration_existing.rb +0 -1
  78. data/lib/generators/devise/devise_generator.rb +0 -1
  79. data/lib/generators/devise/install_generator.rb +0 -1
  80. data/lib/generators/devise/orm_helpers.rb +1 -2
  81. data/lib/generators/devise/views_generator.rb +8 -3
  82. data/lib/generators/mongoid/devise_generator.rb +1 -2
  83. data/lib/generators/templates/README +1 -1
  84. data/lib/generators/templates/devise.rb +10 -5
  85. data/lib/generators/templates/markerb/confirmation_instructions.markerb +1 -1
  86. data/lib/generators/templates/simple_form_for/confirmations/new.html.erb +1 -0
  87. data/lib/generators/templates/simple_form_for/registrations/edit.html.erb +6 -1
  88. data/lib/generators/templates/simple_form_for/unlocks/new.html.erb +1 -0
  89. data/loyal_devise.gemspec +27 -0
  90. data/test/controllers/custom_strategy_test.rb +0 -1
  91. data/test/controllers/helpers_test.rb +0 -1
  92. data/test/controllers/internal_helpers_test.rb +13 -4
  93. data/test/controllers/passwords_controller_test.rb +32 -0
  94. data/test/controllers/sessions_controller_test.rb +28 -1
  95. data/test/controllers/url_helpers_test.rb +0 -1
  96. data/test/delegator_test.rb +0 -1
  97. data/test/devise_test.rb +12 -2
  98. data/test/failure_app_test.rb +3 -4
  99. data/test/generators/active_record_generator_test.rb +1 -4
  100. data/test/generators/devise_generator_test.rb +0 -1
  101. data/test/generators/install_generator_test.rb +0 -1
  102. data/test/generators/mongoid_generator_test.rb +0 -1
  103. data/test/generators/views_generator_test.rb +16 -2
  104. data/test/helpers/devise_helper_test.rb +1 -2
  105. data/test/integration/authenticatable_test.rb +92 -27
  106. data/test/integration/confirmable_test.rb +7 -7
  107. data/test/integration/database_authenticatable_test.rb +8 -7
  108. data/test/integration/http_authenticatable_test.rb +19 -2
  109. data/test/integration/lockable_test.rb +1 -2
  110. data/test/integration/omniauthable_test.rb +2 -3
  111. data/test/integration/recoverable_test.rb +40 -12
  112. data/test/integration/registerable_test.rb +17 -14
  113. data/test/integration/rememberable_test.rb +16 -10
  114. data/test/integration/timeoutable_test.rb +11 -2
  115. data/test/integration/token_authenticatable_test.rb +45 -2
  116. data/test/integration/trackable_test.rb +1 -2
  117. data/test/mailers/confirmation_instructions_test.rb +11 -3
  118. data/test/mailers/reset_password_instructions_test.rb +11 -3
  119. data/test/mailers/unlock_instructions_test.rb +11 -2
  120. data/test/mapping_test.rb +0 -1
  121. data/test/models/authenticatable_test.rb +6 -1
  122. data/test/models/confirmable_test.rb +53 -2
  123. data/test/models/database_authenticatable_test.rb +57 -21
  124. data/test/models/lockable_test.rb +1 -2
  125. data/test/models/omniauthable_test.rb +0 -1
  126. data/test/models/recoverable_test.rb +21 -5
  127. data/test/models/registerable_test.rb +0 -1
  128. data/test/models/rememberable_test.rb +4 -4
  129. data/test/models/serializable_test.rb +8 -8
  130. data/test/models/timeoutable_test.rb +0 -1
  131. data/test/models/token_authenticatable_test.rb +0 -1
  132. data/test/models/trackable_test.rb +0 -1
  133. data/test/models/validatable_test.rb +16 -6
  134. data/test/models_test.rb +7 -24
  135. data/test/omniauth/config_test.rb +1 -2
  136. data/test/omniauth/url_helpers_test.rb +4 -2
  137. data/test/orm/active_record.rb +1 -1
  138. data/test/orm/mongoid.rb +2 -4
  139. data/test/parameter_sanitizer_test.rb +51 -0
  140. data/test/rails_app/Rakefile +0 -4
  141. data/test/rails_app/app/active_record/admin.rb +0 -1
  142. data/test/rails_app/app/active_record/shim.rb +1 -2
  143. data/test/rails_app/app/active_record/user.rb +0 -1
  144. data/test/rails_app/app/controllers/admins/sessions_controller.rb +1 -2
  145. data/test/rails_app/app/controllers/admins_controller.rb +0 -1
  146. data/test/rails_app/app/controllers/application_controller.rb +1 -1
  147. data/test/rails_app/app/controllers/home_controller.rb +0 -1
  148. data/test/rails_app/app/controllers/publisher/registrations_controller.rb +1 -2
  149. data/test/rails_app/app/controllers/publisher/sessions_controller.rb +1 -2
  150. data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +1 -2
  151. data/test/rails_app/app/controllers/users_controller.rb +8 -1
  152. data/test/rails_app/app/helpers/application_helper.rb +0 -1
  153. data/test/rails_app/app/mailers/users/mailer.rb +4 -1
  154. data/test/rails_app/app/mongoid/admin.rb +4 -3
  155. data/test/rails_app/app/mongoid/shim.rb +3 -5
  156. data/test/rails_app/app/mongoid/user.rb +2 -3
  157. data/test/rails_app/app/views/users/edit_form.html.erb +1 -0
  158. data/test/rails_app/bin/bundle +3 -0
  159. data/test/rails_app/bin/rails +4 -0
  160. data/test/rails_app/bin/rake +4 -0
  161. data/test/rails_app/config/application.rb +1 -3
  162. data/test/rails_app/config/boot.rb +3 -4
  163. data/test/rails_app/config/environment.rb +2 -3
  164. data/test/rails_app/config/environments/development.rb +23 -8
  165. data/test/rails_app/config/environments/production.rb +68 -18
  166. data/test/rails_app/config/environments/test.rb +18 -16
  167. data/test/rails_app/config/initializers/backtrace_silencers.rb +0 -1
  168. data/test/rails_app/config/initializers/devise.rb +0 -1
  169. data/test/rails_app/config/initializers/inflections.rb +0 -1
  170. data/test/rails_app/config/initializers/secret_token.rb +8 -3
  171. data/test/rails_app/config/initializers/session_store.rb +1 -0
  172. data/test/rails_app/config/routes.rb +20 -17
  173. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +0 -1
  174. data/test/rails_app/db/schema.rb +0 -1
  175. data/test/rails_app/lib/shared_admin.rb +0 -1
  176. data/test/rails_app/lib/shared_user.rb +0 -2
  177. data/test/routes_test.rb +22 -21
  178. data/test/support/assertions.rb +0 -1
  179. data/test/support/helpers.rb +1 -2
  180. data/test/support/integration.rb +0 -1
  181. data/test/support/webrat/integrations/rails.rb +0 -1
  182. data/test/test_helper.rb +8 -2
  183. data/test/test_helpers_test.rb +0 -1
  184. data/test/test_models.rb +26 -0
  185. metadata +65 -27
  186. data/gemfiles/Gemfile.rails-3.1.x.lock +0 -167
  187. data/test/indifferent_hash.rb +0 -34
  188. data/test/rails_app/script/rails +0 -10
@@ -1,4 +1,3 @@
1
- # -*- encoding : utf-8 -*-
2
1
  module Devise
3
2
  module Controllers
4
3
  # Create url helpers to be used with resource/scope configuration. Acts as
@@ -1,4 +1,3 @@
1
- # -*- encoding : utf-8 -*-
2
1
  module Devise
3
2
  # Checks the scope in the given environment and returns the associated failure app.
4
3
  class Delegator
@@ -1,4 +1,3 @@
1
- # -*- encoding : utf-8 -*-
2
1
  require "action_controller/metal"
3
2
 
4
3
  module Devise
@@ -79,7 +78,14 @@ module Devise
79
78
  def redirect_url
80
79
  if warden_message == :timeout
81
80
  flash[:timedout] = true
82
- attempted_path || scope_path
81
+
82
+ path = if request.get?
83
+ attempted_path
84
+ else
85
+ request.referrer
86
+ end
87
+
88
+ path || scope_path
83
89
  else
84
90
  scope_path
85
91
  end
@@ -1,4 +1,3 @@
1
- # -*- encoding : utf-8 -*-
2
1
  # Deny user access whenever his account is not active yet. All strategies that inherits from
3
2
  # Devise::Strategies::Authenticatable and uses the validate already check if the user is active_for_authentication?
4
3
  # before actively signing him in. However, we need this as hook to validate the user activity
@@ -9,4 +8,4 @@ Warden::Manager.after_set_user do |record, warden, options|
9
8
  warden.logout(scope)
10
9
  throw :warden, :scope => scope, :message => record.inactive_message
11
10
  end
12
- end
11
+ end
@@ -1,4 +1,3 @@
1
- # -*- encoding : utf-8 -*-
2
1
  # Before logout hook to forget the user in the given scope, if it responds
3
2
  # to forget_me! Also clear remember token to ensure the user won't be
4
3
  # remembered again. Notice that we forget the user unless the record is not persisted.
@@ -1,8 +1,7 @@
1
- # -*- encoding : utf-8 -*-
2
1
  # After each sign in, if resource responds to failed_attempts, sets it to 0
3
2
  # This is only triggered when the user is explicitly set (with set_user)
4
3
  Warden::Manager.after_set_user :except => :fetch do |record, warden, options|
5
4
  if record.respond_to?(:failed_attempts) && warden.authenticated?(options[:scope])
6
- record.update_attribute(:failed_attempts, 0)
5
+ record.update_attribute(:failed_attempts, 0) unless record.failed_attempts.zero?
7
6
  end
8
7
  end
@@ -1,7 +1,6 @@
1
- # -*- encoding : utf-8 -*-
2
1
  Warden::Manager.after_set_user :except => :fetch do |record, warden, options|
3
2
  scope = options[:scope]
4
3
  if record.respond_to?(:remember_me) && record.remember_me && warden.authenticated?(scope)
5
4
  Devise::Controllers::Rememberable::Proxy.new(warden).remember_me(record)
6
5
  end
7
- end
6
+ end
@@ -1,4 +1,3 @@
1
- # -*- encoding : utf-8 -*-
2
1
  # Each time a record is set we check whether its session has already timed out
3
2
  # or not, based on last request time. If so, the record is logged out and
4
3
  # redirected to the sign in page. Also, each time the request comes and the
@@ -1,4 +1,3 @@
1
- # -*- encoding : utf-8 -*-
2
1
  # After each sign in, update sign in time, sign in count and sign in IP.
3
2
  # This is only triggered when the user is explicitly set (with set_user)
4
3
  # and on authentication. Retrieving the user from session (:fetch) does
@@ -1,4 +1,3 @@
1
- # -*- encoding : utf-8 -*-
2
1
  module Devise
3
2
  module Mailers
4
3
  module Helpers
@@ -12,9 +11,9 @@ module Devise
12
11
  protected
13
12
 
14
13
  # Configure default email options
15
- def devise_mail(record, action)
14
+ def devise_mail(record, action, opts={})
16
15
  initialize_from_record(record)
17
- mail headers_for(action)
16
+ mail headers_for(action, opts)
18
17
  end
19
18
 
20
19
  def initialize_from_record(record)
@@ -26,33 +25,38 @@ module Devise
26
25
  @devise_mapping ||= Devise.mappings[scope_name]
27
26
  end
28
27
 
29
- def headers_for(action)
28
+ def headers_for(action, opts)
30
29
  headers = {
31
- :subject => translate(devise_mapping, action),
30
+ :subject => subject_for(action),
32
31
  :to => resource.email,
33
32
  :from => mailer_sender(devise_mapping),
34
33
  :reply_to => mailer_reply_to(devise_mapping),
35
- :template_path => template_paths
36
- }
34
+ :template_path => template_paths,
35
+ :template_name => action
36
+ }.merge(opts)
37
37
 
38
38
  if resource.respond_to?(:headers_for)
39
+ ActiveSupport::Deprecation.warn "Calling headers_for in the model is no longer supported. " <<
40
+ "Please customize your mailer instead."
39
41
  headers.merge!(resource.headers_for(action))
40
42
  end
41
43
 
44
+ @email = headers[:to]
42
45
  headers
43
46
  end
44
47
 
45
48
  def mailer_reply_to(mapping)
46
49
  mailer_sender(mapping, :reply_to)
47
50
  end
48
-
51
+
49
52
  def mailer_from(mapping)
50
53
  mailer_sender(mapping, :from)
51
54
  end
52
55
 
53
56
  def mailer_sender(mapping, sender = :from)
54
- if default_params[sender].present?
55
- default_params[sender]
57
+ default_sender = default_params[sender]
58
+ if default_sender.present?
59
+ default_sender.respond_to?(:to_proc) ? instance_eval(&default_sender) : default_sender
56
60
  elsif Devise.mailer_sender.is_a?(Proc)
57
61
  Devise.mailer_sender.call(mapping.name)
58
62
  else
@@ -61,12 +65,12 @@ module Devise
61
65
  end
62
66
 
63
67
  def template_paths
64
- template_path = [self.class.mailer_name]
68
+ template_path = _prefixes.dup
65
69
  template_path.unshift "#{@devise_mapping.scoped_path}/mailer" if self.class.scoped_views?
66
70
  template_path
67
71
  end
68
72
 
69
- # Setup a subject doing an I18n lookup. At first, it attemps to set a subject
73
+ # Setup a subject doing an I18n lookup. At first, it attempts to set a subject
70
74
  # based on the current mapping:
71
75
  #
72
76
  # en:
@@ -83,8 +87,8 @@ module Devise
83
87
  # confirmation_instructions:
84
88
  # subject: '...'
85
89
  #
86
- def translate(mapping, key)
87
- I18n.t(:"#{mapping.name}_subject", :scope => [:devise, :mailer, key],
90
+ def subject_for(key)
91
+ I18n.t(:"#{devise_mapping.name}_subject", :scope => [:devise, :mailer, key],
88
92
  :default => [:subject, key.to_s.humanize])
89
93
  end
90
94
  end
@@ -1,4 +1,3 @@
1
- # -*- encoding : utf-8 -*-
2
1
  module Devise
3
2
  # Responsible for handling devise mappings and routes configuration. Each
4
3
  # resource configured by devise_for in routes is actually creating a mapping
@@ -30,17 +29,17 @@ module Devise
30
29
 
31
30
  # Receives an object and find a scope for it. If a scope cannot be found,
32
31
  # raises an error. If a symbol is given, it's considered to be the scope.
33
- def self.find_scope!(duck)
34
- case duck
32
+ def self.find_scope!(obj)
33
+ case obj
35
34
  when String, Symbol
36
- return duck
35
+ return obj
37
36
  when Class
38
- Devise.mappings.each_value { |m| return m.name if duck <= m.to }
37
+ Devise.mappings.each_value { |m| return m.name if obj <= m.to }
39
38
  else
40
- Devise.mappings.each_value { |m| return m.name if duck.is_a?(m.to) }
39
+ Devise.mappings.each_value { |m| return m.name if obj.is_a?(m.to) }
41
40
  end
42
41
 
43
- raise "Could not find a valid mapping for #{duck.inspect}"
42
+ raise "Could not find a valid mapping for #{obj.inspect}"
44
43
  end
45
44
 
46
45
  def self.find_by_path!(path, path_type=:fullpath)
@@ -1,4 +1,3 @@
1
- # -*- encoding : utf-8 -*-
2
1
  module Devise
3
2
  module Models
4
3
  class MissingAttribute < StandardError
@@ -1,4 +1,3 @@
1
- # -*- encoding : utf-8 -*-
2
1
  require 'devise/hooks/activatable'
3
2
 
4
3
  module Devise
@@ -11,15 +10,18 @@ module Devise
11
10
  #
12
11
  # * +authentication_keys+: parameters used for authentication. By default [:email].
13
12
  #
13
+ # * +http_authentication_key+: map the username passed via HTTP Auth to this parameter. Defaults to
14
+ # the first element in +authentication_keys+.
15
+ #
14
16
  # * +request_keys+: parameters from the request object used for authentication.
15
17
  # By specifying a symbol (which should be a request method), it will automatically be
16
18
  # passed to find_for_authentication method and considered in your model lookup.
17
19
  #
18
20
  # For instance, if you set :request_keys to [:subdomain], :subdomain will be considered
19
- # as key on authentication. This can also be a hash where the value is a boolean expliciting
21
+ # as key on authentication. This can also be a hash where the value is a boolean specifying
20
22
  # if the value is required or not.
21
23
  #
22
- # * +http_authenticatable+: if this model allows http authentication. By default true.
24
+ # * +http_authenticatable+: if this model allows http authentication. By default false.
23
25
  # It also accepts an array specifying the strategies that should allow http.
24
26
  #
25
27
  # * +params_authenticatable+: if this model allows authentication through request params. By default true.
@@ -33,7 +35,7 @@ module Devise
33
35
  # == active_for_authentication?
34
36
  #
35
37
  # After authenticating a user and in each request, Devise checks if your model is active by
36
- # calling model.active_for_authentication?. This method is overwriten by other devise modules. For instance,
38
+ # calling model.active_for_authentication?. This method is overwritten by other devise modules. For instance,
37
39
  # :confirmable overwrites .active_for_authentication? to only return true if your model was confirmed.
38
40
  #
39
41
  # You overwrite this method yourself, but if you do, don't forget to call super:
@@ -94,10 +96,6 @@ module Devise
94
96
  def authenticatable_salt
95
97
  end
96
98
 
97
- def headers_for(name)
98
- {}
99
- end
100
-
101
99
  array = %w(serializable_hash)
102
100
  # to_xml does not call serializable_hash on 3.1
103
101
  array << "to_xml" if Rails::VERSION::STRING[0,3] == "3.1"
@@ -145,14 +143,26 @@ module Devise
145
143
  #
146
144
  # protected
147
145
  #
148
- # def send_devise_notification(notification)
149
- # pending_notifications << notification
146
+ # def send_devise_notification(notification, opts = {})
147
+ # # if the record is new or changed then delay the
148
+ # # delivery until the after_commit callback otherwise
149
+ # # send now because after_commit will not be called.
150
+ # if new_record? || changed?
151
+ # pending_notifications << [notification, opts]
152
+ # else
153
+ # devise_mailer.send(notification, self, opts).deliver
154
+ # end
150
155
  # end
151
156
  #
152
157
  # def send_pending_notifications
153
- # pending_notifications.each do |n|
154
- # devise_mailer.send(n, self).deliver
158
+ # pending_notifications.each do |n, opts|
159
+ # devise_mailer.send(n, self, opts).deliver
155
160
  # end
161
+ #
162
+ # # Empty the pending notifications array because the
163
+ # # after_commit hook can be called multiple times which
164
+ # # could cause multiple emails to be sent.
165
+ # pending_notifications.clear
156
166
  # end
157
167
  #
158
168
  # def pending_notifications
@@ -160,21 +170,35 @@ module Devise
160
170
  # end
161
171
  # end
162
172
  #
163
- def send_devise_notification(notification)
164
- devise_mailer.send(notification, self).deliver
173
+ def send_devise_notification(notification, opts={})
174
+ devise_mailer.send(notification, self, opts).deliver
165
175
  end
166
176
 
167
177
  def downcase_keys
168
- self.class.case_insensitive_keys.each { |k| self[k].try(:downcase!) }
178
+ self.class.case_insensitive_keys.each { |k| apply_to_attribute_or_variable(k, :downcase!) }
169
179
  end
170
180
 
171
181
  def strip_whitespace
172
- self.class.strip_whitespace_keys.each { |k| self[k].try(:strip!) }
182
+ self.class.strip_whitespace_keys.each { |k| apply_to_attribute_or_variable(k, :strip!) }
183
+ end
184
+
185
+ def apply_to_attribute_or_variable(attr, method)
186
+ if self[attr]
187
+ self[attr].try(method)
188
+
189
+ # Use respond_to? here to avoid a regression where globally
190
+ # configured strip_whitespace_keys or case_insensitive_keys were
191
+ # attempting to strip! or downcase! when a model didn't have the
192
+ # globally configured key.
193
+ elsif respond_to?(attr)
194
+ send(attr).try(method)
195
+ end
173
196
  end
174
197
 
175
198
  module ClassMethods
176
199
  Devise::Models.config(self, :authentication_keys, :request_keys, :strip_whitespace_keys,
177
- :case_insensitive_keys, :http_authenticatable, :params_authenticatable, :skip_session_storage)
200
+ :case_insensitive_keys, :http_authenticatable, :params_authenticatable, :skip_session_storage,
201
+ :http_authentication_key)
178
202
 
179
203
  def serialize_into_session(record)
180
204
  [record.to_key, record.authenticatable_salt]
@@ -200,27 +224,26 @@ module Devise
200
224
  # it may be wrapped as well. For instance, database authenticatable
201
225
  # provides a `find_for_database_authentication` that wraps a call to
202
226
  # this method. This allows you to customize both database authenticatable
203
- # or the whole authenticate stack by customize `find_for_authentication.`
227
+ # or the whole authenticate stack by customize `find_for_authentication.`
204
228
  #
205
229
  # Overwrite to add customized conditions, create a join, or maybe use a
206
230
  # namedscope to filter records while authenticating.
207
231
  # Example:
208
232
  #
209
- # def self.find_for_authentication(conditions={})
210
- # conditions[:active] = true
211
- # super
233
+ # def self.find_for_authentication(tainted_conditions)
234
+ # find_first_by_auth_conditions(tainted_conditions, :active => true)
212
235
  # end
213
236
  #
214
237
  # Finally, notice that Devise also queries for users in other scenarios
215
238
  # besides authentication, for example when retrieving an user to send
216
239
  # an e-mail for password reset. In such cases, find_for_authentication
217
240
  # is not called.
218
- def find_for_authentication(conditions)
219
- find_first_by_auth_conditions(conditions)
241
+ def find_for_authentication(tainted_conditions)
242
+ find_first_by_auth_conditions(tainted_conditions)
220
243
  end
221
244
 
222
- def find_first_by_auth_conditions(conditions)
223
- to_adapter.find_first devise_param_filter.filter(conditions)
245
+ def find_first_by_auth_conditions(tainted_conditions, opts={})
246
+ to_adapter.find_first(devise_parameter_filter.filter(tainted_conditions).merge(opts))
224
247
  end
225
248
 
226
249
  # Find an initialize a record setting an error if it can't be found.
@@ -252,8 +275,8 @@ module Devise
252
275
 
253
276
  protected
254
277
 
255
- def devise_param_filter
256
- @devise_param_filter ||= Devise::ParamFilter.new(case_insensitive_keys, strip_whitespace_keys)
278
+ def devise_parameter_filter
279
+ @devise_parameter_filter ||= Devise::ParameterFilter.new(case_insensitive_keys, strip_whitespace_keys)
257
280
  end
258
281
 
259
282
  # Generate a token by looping and ensuring does not already exist.
@@ -1,4 +1,3 @@
1
- # -*- encoding : utf-8 -*-
2
1
  module Devise
3
2
  module Models
4
3
  # Confirmable is responsible to verify if an account is already confirmed to
@@ -35,11 +34,18 @@ module Devise
35
34
 
36
35
  included do
37
36
  before_create :generate_confirmation_token, :if => :confirmation_required?
38
- after_create :send_on_create_confirmation_instructions, :if => :confirmation_required?
37
+ after_create :send_on_create_confirmation_instructions, :if => :send_confirmation_notification?
39
38
  before_update :postpone_email_change_until_confirmation, :if => :postpone_email_change?
40
39
  after_update :send_confirmation_instructions, :if => :reconfirmation_required?
41
40
  end
42
41
 
42
+ def initialize(*args, &block)
43
+ @bypass_postpone = false
44
+ @reconfirmation_required = false
45
+ @skip_confirmation_notification = false
46
+ super
47
+ end
48
+
43
49
  def self.required_fields(klass)
44
50
  required_methods = [:confirmation_token, :confirmed_at, :confirmation_sent_at]
45
51
  required_methods << :unconfirmed_email if klass.reconfirmable
@@ -87,8 +93,10 @@ module Devise
87
93
  self.confirmation_token = nil if reconfirmation_required?
88
94
  @reconfirmation_required = false
89
95
 
90
- generate_confirmation_token! if self.confirmation_token.blank?
91
- send_devise_notification(:confirmation_instructions)
96
+ ensure_confirmation_token!
97
+
98
+ opts = pending_reconfirmation? ? { :to => unconfirmed_email } : { }
99
+ send_devise_notification(:confirmation_instructions, opts)
92
100
  end
93
101
 
94
102
  # Resend confirmation token. This method does not need to generate a new token.
@@ -98,6 +106,11 @@ module Devise
98
106
  send_confirmation_instructions
99
107
  end
100
108
  end
109
+
110
+ # Generate a confirmation token unless already exists and save the record.
111
+ def ensure_confirmation_token!
112
+ generate_confirmation_token! if should_generate_confirmation_token?
113
+ end
101
114
 
102
115
  # Overwrites active_for_authentication? for confirmation
103
116
  # by verifying whether a user is active to sign in or not. If the user
@@ -118,21 +131,22 @@ module Devise
118
131
  self.confirmed_at = Time.now.utc
119
132
  end
120
133
 
134
+ # Skips sending the confirmation notification email after_create. Unlike
135
+ # #skip_confirmation!, record still requires confirmation.
136
+ def skip_confirmation_notification!
137
+ @skip_confirmation_notification = true
138
+ end
139
+
121
140
  # If you don't want reconfirmation to be sent, neither a code
122
141
  # to be generated, call skip_reconfirmation!
123
142
  def skip_reconfirmation!
124
143
  @bypass_postpone = true
125
144
  end
126
145
 
127
- def headers_for(action)
128
- headers = super
129
- if action == :confirmation_instructions && pending_reconfirmation?
130
- headers[:to] = unconfirmed_email
131
- end
132
- headers
133
- end
134
-
135
146
  protected
147
+ def should_generate_confirmation_token?
148
+ confirmation_token.nil? || confirmation_period_expired?
149
+ end
136
150
 
137
151
  # A callback method used to deliver confirmation
138
152
  # instructions on creation. This can be overriden
@@ -165,8 +179,11 @@ module Devise
165
179
  # # allow_unconfirmed_access_for = 0.days
166
180
  # confirmation_period_valid? # will always return false
167
181
  #
182
+ # # allow_unconfirmed_access_for = nil
183
+ # confirmation_period_valid? # will always return true
184
+ #
168
185
  def confirmation_period_valid?
169
- confirmation_sent_at && confirmation_sent_at.utc >= self.class.allow_unconfirmed_access_for.ago
186
+ self.class.allow_unconfirmed_access_for.nil? || (confirmation_sent_at && confirmation_sent_at.utc >= self.class.allow_unconfirmed_access_for.ago)
170
187
  end
171
188
 
172
189
  # Checks if the user confirmation happens before the token becomes invalid
@@ -218,13 +235,17 @@ module Devise
218
235
  end
219
236
 
220
237
  def postpone_email_change?
221
- postpone = self.class.reconfirmable && email_changed? && !@bypass_postpone
222
- @bypass_postpone = nil
238
+ postpone = self.class.reconfirmable && email_changed? && !@bypass_postpone && !self.email.blank?
239
+ @bypass_postpone = false
223
240
  postpone
224
241
  end
225
242
 
226
243
  def reconfirmation_required?
227
- self.class.reconfirmable && @reconfirmation_required
244
+ self.class.reconfirmable && @reconfirmation_required && !self.email.blank?
245
+ end
246
+
247
+ def send_confirmation_notification?
248
+ confirmation_required? && !@skip_confirmation_notification && !self.email.blank?
228
249
  end
229
250
 
230
251
  module ClassMethods