loyal_devise 2.1.2 → 2.1.3

Sign up to get free protection for your applications and to get access to all the features.
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