devise 4.4.3 → 4.7.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 (222) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +98 -4
  3. data/MIT-LICENSE +2 -1
  4. data/README.md +96 -59
  5. data/app/controllers/devise/passwords_controller.rb +1 -0
  6. data/app/controllers/devise/registrations_controller.rb +26 -8
  7. data/app/controllers/devise_controller.rb +3 -3
  8. data/app/helpers/devise_helper.rb +21 -18
  9. data/app/mailers/devise/mailer.rb +5 -5
  10. data/app/views/devise/confirmations/new.html.erb +1 -1
  11. data/app/views/devise/passwords/edit.html.erb +3 -3
  12. data/app/views/devise/passwords/new.html.erb +1 -1
  13. data/app/views/devise/registrations/edit.html.erb +4 -4
  14. data/app/views/devise/registrations/new.html.erb +3 -3
  15. data/app/views/devise/sessions/new.html.erb +3 -3
  16. data/app/views/devise/shared/_error_messages.html.erb +15 -0
  17. data/app/views/devise/shared/_links.html.erb +7 -7
  18. data/app/views/devise/unlocks/new.html.erb +1 -1
  19. data/config/locales/en.yml +3 -2
  20. data/lib/devise.rb +4 -4
  21. data/lib/devise/controllers/helpers.rb +8 -8
  22. data/lib/devise/controllers/sign_in_out.rb +6 -3
  23. data/lib/devise/controllers/url_helpers.rb +1 -1
  24. data/lib/devise/failure_app.rb +25 -5
  25. data/lib/devise/hooks/timeoutable.rb +2 -2
  26. data/lib/devise/mapping.rb +1 -1
  27. data/lib/devise/models/authenticatable.rb +44 -45
  28. data/lib/devise/models/confirmable.rb +18 -3
  29. data/lib/devise/models/database_authenticatable.rb +50 -12
  30. data/lib/devise/models/lockable.rb +3 -3
  31. data/lib/devise/models/recoverable.rb +2 -2
  32. data/lib/devise/models/registerable.rb +2 -0
  33. data/lib/devise/models/rememberable.rb +1 -1
  34. data/lib/devise/models/trackable.rb +9 -2
  35. data/lib/devise/models/validatable.rb +1 -1
  36. data/lib/devise/parameter_filter.rb +2 -0
  37. data/lib/devise/parameter_sanitizer.rb +13 -1
  38. data/lib/devise/rails/routes.rb +6 -6
  39. data/lib/devise/secret_key_finder.rb +2 -0
  40. data/lib/devise/strategies/authenticatable.rb +1 -1
  41. data/lib/devise/strategies/database_authenticatable.rb +6 -1
  42. data/lib/devise/test/controller_helpers.rb +4 -2
  43. data/lib/devise/test/integration_helpers.rb +1 -1
  44. data/lib/devise/version.rb +1 -1
  45. data/lib/generators/active_record/devise_generator.rb +9 -9
  46. data/lib/generators/devise/controllers_generator.rb +1 -1
  47. data/lib/generators/devise/devise_generator.rb +1 -1
  48. data/lib/generators/devise/install_generator.rb +1 -5
  49. data/lib/generators/devise/orm_helpers.rb +2 -2
  50. data/lib/generators/devise/views_generator.rb +1 -1
  51. data/lib/generators/mongoid/devise_generator.rb +5 -5
  52. data/lib/generators/templates/README +9 -1
  53. data/lib/generators/templates/controllers/omniauth_callbacks_controller.rb +1 -1
  54. data/lib/generators/templates/devise.rb +34 -6
  55. data/lib/generators/templates/simple_form_for/confirmations/new.html.erb +5 -1
  56. data/lib/generators/templates/simple_form_for/passwords/edit.html.erb +10 -2
  57. data/lib/generators/templates/simple_form_for/passwords/new.html.erb +4 -1
  58. data/lib/generators/templates/simple_form_for/registrations/edit.html.erb +11 -3
  59. data/lib/generators/templates/simple_form_for/registrations/new.html.erb +11 -3
  60. data/lib/generators/templates/simple_form_for/sessions/new.html.erb +7 -2
  61. data/lib/generators/templates/simple_form_for/unlocks/new.html.erb +4 -1
  62. metadata +7 -312
  63. data/.gitignore +0 -10
  64. data/.travis.yml +0 -68
  65. data/.yardopts +0 -9
  66. data/CODE_OF_CONDUCT.md +0 -22
  67. data/CONTRIBUTING.md +0 -79
  68. data/Gemfile +0 -39
  69. data/Gemfile.lock +0 -193
  70. data/ISSUE_TEMPLATE.md +0 -19
  71. data/Rakefile +0 -37
  72. data/bin/test +0 -13
  73. data/devise.gemspec +0 -28
  74. data/devise.png +0 -0
  75. data/gemfiles/Gemfile.rails-4.1-stable +0 -32
  76. data/gemfiles/Gemfile.rails-4.1-stable.lock +0 -171
  77. data/gemfiles/Gemfile.rails-4.2-stable +0 -32
  78. data/gemfiles/Gemfile.rails-4.2-stable.lock +0 -192
  79. data/gemfiles/Gemfile.rails-5.0-stable +0 -33
  80. data/gemfiles/Gemfile.rails-5.0-stable.lock +0 -192
  81. data/gemfiles/Gemfile.rails-5.2-rc1 +0 -26
  82. data/gemfiles/Gemfile.rails-5.2-rc1.lock +0 -201
  83. data/guides/bug_report_templates/integration_test.rb +0 -106
  84. data/test/controllers/custom_registrations_controller_test.rb +0 -42
  85. data/test/controllers/custom_strategy_test.rb +0 -66
  86. data/test/controllers/helper_methods_test.rb +0 -24
  87. data/test/controllers/helpers_test.rb +0 -318
  88. data/test/controllers/inherited_controller_i18n_messages_test.rb +0 -53
  89. data/test/controllers/internal_helpers_test.rb +0 -129
  90. data/test/controllers/load_hooks_controller_test.rb +0 -21
  91. data/test/controllers/passwords_controller_test.rb +0 -34
  92. data/test/controllers/sessions_controller_test.rb +0 -108
  93. data/test/controllers/url_helpers_test.rb +0 -67
  94. data/test/delegator_test.rb +0 -21
  95. data/test/devise_test.rb +0 -109
  96. data/test/failure_app_test.rb +0 -340
  97. data/test/generators/active_record_generator_test.rb +0 -130
  98. data/test/generators/controllers_generator_test.rb +0 -50
  99. data/test/generators/devise_generator_test.rb +0 -41
  100. data/test/generators/install_generator_test.rb +0 -26
  101. data/test/generators/mongoid_generator_test.rb +0 -25
  102. data/test/generators/views_generator_test.rb +0 -105
  103. data/test/helpers/devise_helper_test.rb +0 -51
  104. data/test/integration/authenticatable_test.rb +0 -706
  105. data/test/integration/confirmable_test.rb +0 -326
  106. data/test/integration/database_authenticatable_test.rb +0 -97
  107. data/test/integration/http_authenticatable_test.rb +0 -114
  108. data/test/integration/lockable_test.rb +0 -242
  109. data/test/integration/mounted_engine_test.rb +0 -38
  110. data/test/integration/omniauthable_test.rb +0 -148
  111. data/test/integration/recoverable_test.rb +0 -349
  112. data/test/integration/registerable_test.rb +0 -365
  113. data/test/integration/rememberable_test.rb +0 -219
  114. data/test/integration/timeoutable_test.rb +0 -186
  115. data/test/integration/trackable_test.rb +0 -99
  116. data/test/mailers/confirmation_instructions_test.rb +0 -117
  117. data/test/mailers/email_changed_test.rb +0 -132
  118. data/test/mailers/mailer_test.rb +0 -20
  119. data/test/mailers/reset_password_instructions_test.rb +0 -98
  120. data/test/mailers/unlock_instructions_test.rb +0 -93
  121. data/test/mapping_test.rb +0 -136
  122. data/test/models/authenticatable_test.rb +0 -25
  123. data/test/models/confirmable_test.rb +0 -549
  124. data/test/models/database_authenticatable_test.rb +0 -283
  125. data/test/models/lockable_test.rb +0 -352
  126. data/test/models/omniauthable_test.rb +0 -9
  127. data/test/models/recoverable_test.rb +0 -263
  128. data/test/models/registerable_test.rb +0 -9
  129. data/test/models/rememberable_test.rb +0 -184
  130. data/test/models/serializable_test.rb +0 -60
  131. data/test/models/timeoutable_test.rb +0 -53
  132. data/test/models/trackable_test.rb +0 -62
  133. data/test/models/validatable_test.rb +0 -121
  134. data/test/models_test.rb +0 -155
  135. data/test/omniauth/config_test.rb +0 -61
  136. data/test/omniauth/url_helpers_test.rb +0 -53
  137. data/test/orm/active_record.rb +0 -24
  138. data/test/orm/mongoid.rb +0 -15
  139. data/test/parameter_sanitizer_test.rb +0 -77
  140. data/test/rails_app/Rakefile +0 -6
  141. data/test/rails_app/app/active_record/admin.rb +0 -8
  142. data/test/rails_app/app/active_record/shim.rb +0 -4
  143. data/test/rails_app/app/active_record/user.rb +0 -20
  144. data/test/rails_app/app/active_record/user_on_engine.rb +0 -9
  145. data/test/rails_app/app/active_record/user_on_main_app.rb +0 -9
  146. data/test/rails_app/app/active_record/user_with_validations.rb +0 -12
  147. data/test/rails_app/app/active_record/user_without_email.rb +0 -10
  148. data/test/rails_app/app/controllers/admins/sessions_controller.rb +0 -8
  149. data/test/rails_app/app/controllers/admins_controller.rb +0 -8
  150. data/test/rails_app/app/controllers/application_controller.rb +0 -13
  151. data/test/rails_app/app/controllers/application_with_fake_engine.rb +0 -32
  152. data/test/rails_app/app/controllers/custom/registrations_controller.rb +0 -33
  153. data/test/rails_app/app/controllers/home_controller.rb +0 -31
  154. data/test/rails_app/app/controllers/publisher/registrations_controller.rb +0 -4
  155. data/test/rails_app/app/controllers/publisher/sessions_controller.rb +0 -4
  156. data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +0 -16
  157. data/test/rails_app/app/controllers/users_controller.rb +0 -33
  158. data/test/rails_app/app/helpers/application_helper.rb +0 -5
  159. data/test/rails_app/app/mailers/users/from_proc_mailer.rb +0 -5
  160. data/test/rails_app/app/mailers/users/mailer.rb +0 -5
  161. data/test/rails_app/app/mailers/users/reply_to_mailer.rb +0 -6
  162. data/test/rails_app/app/mongoid/admin.rb +0 -31
  163. data/test/rails_app/app/mongoid/shim.rb +0 -25
  164. data/test/rails_app/app/mongoid/user.rb +0 -50
  165. data/test/rails_app/app/mongoid/user_on_engine.rb +0 -41
  166. data/test/rails_app/app/mongoid/user_on_main_app.rb +0 -41
  167. data/test/rails_app/app/mongoid/user_with_validations.rb +0 -37
  168. data/test/rails_app/app/mongoid/user_without_email.rb +0 -35
  169. data/test/rails_app/app/views/admins/index.html.erb +0 -1
  170. data/test/rails_app/app/views/admins/sessions/new.html.erb +0 -2
  171. data/test/rails_app/app/views/home/admin_dashboard.html.erb +0 -1
  172. data/test/rails_app/app/views/home/index.html.erb +0 -1
  173. data/test/rails_app/app/views/home/join.html.erb +0 -1
  174. data/test/rails_app/app/views/home/private.html.erb +0 -1
  175. data/test/rails_app/app/views/home/user_dashboard.html.erb +0 -1
  176. data/test/rails_app/app/views/layouts/application.html.erb +0 -24
  177. data/test/rails_app/app/views/users/edit_form.html.erb +0 -1
  178. data/test/rails_app/app/views/users/index.html.erb +0 -1
  179. data/test/rails_app/app/views/users/mailer/confirmation_instructions.erb +0 -1
  180. data/test/rails_app/app/views/users/sessions/new.html.erb +0 -1
  181. data/test/rails_app/bin/bundle +0 -3
  182. data/test/rails_app/bin/rails +0 -4
  183. data/test/rails_app/bin/rake +0 -4
  184. data/test/rails_app/config.ru +0 -4
  185. data/test/rails_app/config/application.rb +0 -48
  186. data/test/rails_app/config/boot.rb +0 -27
  187. data/test/rails_app/config/database.yml +0 -18
  188. data/test/rails_app/config/environment.rb +0 -7
  189. data/test/rails_app/config/environments/development.rb +0 -32
  190. data/test/rails_app/config/environments/production.rb +0 -88
  191. data/test/rails_app/config/environments/test.rb +0 -47
  192. data/test/rails_app/config/initializers/backtrace_silencers.rb +0 -9
  193. data/test/rails_app/config/initializers/devise.rb +0 -182
  194. data/test/rails_app/config/initializers/inflections.rb +0 -4
  195. data/test/rails_app/config/initializers/secret_token.rb +0 -5
  196. data/test/rails_app/config/initializers/session_store.rb +0 -3
  197. data/test/rails_app/config/routes.rb +0 -128
  198. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +0 -77
  199. data/test/rails_app/db/schema.rb +0 -57
  200. data/test/rails_app/lib/shared_admin.rb +0 -23
  201. data/test/rails_app/lib/shared_user.rb +0 -32
  202. data/test/rails_app/lib/shared_user_without_email.rb +0 -28
  203. data/test/rails_app/lib/shared_user_without_omniauth.rb +0 -15
  204. data/test/rails_app/public/404.html +0 -26
  205. data/test/rails_app/public/422.html +0 -26
  206. data/test/rails_app/public/500.html +0 -26
  207. data/test/rails_app/public/favicon.ico +0 -0
  208. data/test/rails_test.rb +0 -11
  209. data/test/routes_test.rb +0 -281
  210. data/test/secret_key_finder_test.rb +0 -97
  211. data/test/support/action_controller/record_identifier.rb +0 -12
  212. data/test/support/assertions.rb +0 -30
  213. data/test/support/helpers.rb +0 -83
  214. data/test/support/http_method_compatibility.rb +0 -53
  215. data/test/support/integration.rb +0 -95
  216. data/test/support/locale/en.yml +0 -8
  217. data/test/support/mongoid.yml +0 -6
  218. data/test/support/webrat/integrations/rails.rb +0 -35
  219. data/test/test/controller_helpers_test.rb +0 -193
  220. data/test/test/integration_helpers_test.rb +0 -34
  221. data/test/test_helper.rb +0 -36
  222. data/test/test_models.rb +0 -35
@@ -10,7 +10,7 @@ module Devise
10
10
  # cause exceptions to be thrown from this method; if you simply want to check
11
11
  # if a scope has already previously been authenticated without running
12
12
  # authentication hooks, you can directly call `warden.authenticated?(scope: scope)`
13
- def signed_in?(scope=nil)
13
+ def signed_in?(scope = nil)
14
14
  [scope || Devise.mappings.keys].flatten.any? do |_scope|
15
15
  warden.authenticate?(scope: _scope)
16
16
  end
@@ -19,6 +19,9 @@ module Devise
19
19
  # Sign in a user that already was authenticated. This helper is useful for logging
20
20
  # users in after sign up. All options given to sign_in is passed forward
21
21
  # to the set_user method in warden.
22
+ # If you are using a custom warden strategy and the timeoutable module, you have to
23
+ # set `env["devise.skip_timeout"] = true` in the request to use this method, like we do
24
+ # in the sessions controller: https://github.com/heartcombo/devise/blob/master/app/controllers/devise/sessions_controller.rb#L7
22
25
  #
23
26
  # Examples:
24
27
  #
@@ -74,7 +77,7 @@ module Devise
74
77
  # sign_out :user # sign_out(scope)
75
78
  # sign_out @user # sign_out(resource)
76
79
  #
77
- def sign_out(resource_or_scope=nil)
80
+ def sign_out(resource_or_scope = nil)
78
81
  return sign_out_all_scopes unless resource_or_scope
79
82
  scope = Devise::Mapping.find_scope!(resource_or_scope)
80
83
  user = warden.user(scope: scope, run_callbacks: false) # If there is no user
@@ -89,7 +92,7 @@ module Devise
89
92
  # Sign out all active users or scopes. This helper is useful for signing out all roles
90
93
  # in one click. This signs out ALL scopes in warden. Returns true if there was at least one logout
91
94
  # and false if there was no user logged in on all scopes.
92
- def sign_out_all_scopes(lock=true)
95
+ def sign_out_all_scopes(lock = true)
93
96
  users = Devise.mappings.keys.map { |s| warden.user(scope: s, run_callbacks: false) }
94
97
 
95
98
  warden.logout
@@ -34,7 +34,7 @@ module Devise
34
34
  end
35
35
  end
36
36
 
37
- def self.generate_helpers!(routes=nil)
37
+ def self.generate_helpers!(routes = nil)
38
38
  routes ||= begin
39
39
  mappings = Devise.mappings.values.map(&:used_helpers).flatten.uniq
40
40
  Devise::URL_HELPERS.slice(*mappings)
@@ -71,7 +71,6 @@ module Devise
71
71
  end
72
72
 
73
73
  flash.now[:alert] = i18n_message(:invalid) if is_flashing_format?
74
- # self.response = recall_app(warden_options[:recall]).call(env)
75
74
  self.response = recall_app(warden_options[:recall]).call(request.env)
76
75
  end
77
76
 
@@ -107,7 +106,7 @@ module Devise
107
106
  options[:authentication_keys] = keys.join(I18n.translate(:"support.array.words_connector"))
108
107
  options = i18n_options(options)
109
108
 
110
- I18n.t(:"#{scope}.#{message}", options)
109
+ I18n.t(:"#{scope}.#{message}", **options)
111
110
  else
112
111
  message.to_s
113
112
  end
@@ -144,11 +143,20 @@ module Devise
144
143
 
145
144
  opts[:format] = request_format unless skip_format?
146
145
 
147
- opts[:script_name] = relative_url_root if relative_url_root?
148
-
149
146
  router_name = Devise.mappings[scope].router_name || Devise.available_router_name
150
147
  context = send(router_name)
151
148
 
149
+ if relative_url_root?
150
+ opts[:script_name] = relative_url_root
151
+
152
+ # We need to add the rootpath to `script_name` manually for applications that use a Rails
153
+ # version lower than 5.1. Otherwise, it is going to generate a wrong path for Engines
154
+ # that use Devise. Remove it when the support of Rails 5.0 is dropped.
155
+ elsif root_path_defined?(context) && !rails_51_and_up?
156
+ rootpath = context.routes.url_helpers.root_path
157
+ opts[:script_name] = rootpath.chomp('/') if rootpath.length > 1
158
+ end
159
+
152
160
  if context.respond_to?(route)
153
161
  context.send(route, opts)
154
162
  elsif respond_to?(:root_url)
@@ -242,7 +250,7 @@ module Devise
242
250
  # Check if flash messages should be emitted. Default is to do it on
243
251
  # navigational formats
244
252
  def is_flashing_format?
245
- is_navigational_format?
253
+ request.respond_to?(:flash) && is_navigational_format?
246
254
  end
247
255
 
248
256
  def request_format
@@ -260,5 +268,17 @@ module Devise
260
268
  def relative_url_root?
261
269
  relative_url_root.present?
262
270
  end
271
+
272
+ ActiveSupport.run_load_hooks(:devise_failure_app, self)
273
+
274
+ private
275
+
276
+ def root_path_defined?(context)
277
+ defined?(context.routes) && context.routes.url_helpers.respond_to?(:root_path)
278
+ end
279
+
280
+ def rails_51_and_up?
281
+ Rails.gem_version >= Gem::Version.new("5.1")
282
+ end
263
283
  end
264
284
  end
@@ -21,8 +21,8 @@ Warden::Manager.after_set_user do |record, warden, options|
21
21
 
22
22
  proxy = Devise::Hooks::Proxy.new(warden)
23
23
 
24
- if record.timedout?(last_request_at) &&
25
- !env['devise.skip_timeout'] &&
24
+ if !env['devise.skip_timeout'] &&
25
+ record.timedout?(last_request_at) &&
26
26
  !proxy.remember_me_is_active?(record)
27
27
  Devise.sign_out_all_scopes ? proxy.sign_out : proxy.sign_out(scope)
28
28
  throw :warden, scope: scope, message: :timeout
@@ -46,7 +46,7 @@ module Devise
46
46
  raise "Could not find a valid mapping for #{obj.inspect}"
47
47
  end
48
48
 
49
- def self.find_by_path!(path, path_type=:fullpath)
49
+ def self.find_by_path!(path, path_type = :fullpath)
50
50
  Devise.mappings.each_value { |m| return m if path.include?(m.send(path_type)) }
51
51
  raise "Could not find a valid mapping for path #{path.inspect}"
52
52
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_model/version'
4
3
  require 'devise/hooks/activatable'
5
4
  require 'devise/hooks/csrf_cleaner'
6
5
 
@@ -105,7 +104,7 @@ module Devise
105
104
  # given to :except will simply add names to exempt to Devise internal list.
106
105
  def serializable_hash(options = nil)
107
106
  options = options.try(:dup) || {}
108
- options[:except] = Array(options[:except])
107
+ options[:except] = Array(options[:except]).dup
109
108
 
110
109
  if options[:force_except]
111
110
  options[:except].concat Array(options[:force_except])
@@ -134,16 +133,18 @@ module Devise
134
133
  # This is an internal method called every time Devise needs
135
134
  # to send a notification/mail. This can be overridden if you
136
135
  # need to customize the e-mail delivery logic. For instance,
137
- # if you are using a queue to deliver e-mails (delayed job,
138
- # sidekiq, resque, etc), you must add the delivery to the queue
136
+ # if you are using a queue to deliver e-mails (active job, delayed
137
+ # job, sidekiq, resque, etc), you must add the delivery to the queue
139
138
  # just after the transaction was committed. To achieve this,
140
139
  # you can override send_devise_notification to store the
141
- # deliveries until the after_commit callback is triggered:
140
+ # deliveries until the after_commit callback is triggered.
141
+ #
142
+ # The following example uses Active Job's `deliver_later` :
142
143
  #
143
144
  # class User
144
145
  # devise :database_authenticatable, :confirmable
145
146
  #
146
- # after_commit :send_pending_notifications
147
+ # after_commit :send_pending_devise_notifications
147
148
  #
148
149
  # protected
149
150
  #
@@ -151,39 +152,45 @@ module Devise
151
152
  # # If the record is new or changed then delay the
152
153
  # # delivery until the after_commit callback otherwise
153
154
  # # send now because after_commit will not be called.
154
- # if new_record? || changed?
155
- # pending_notifications << [notification, args]
155
+ # # For Rails < 6 use `changed?` instead of `saved_changes?`.
156
+ # if new_record? || saved_changes?
157
+ # pending_devise_notifications << [notification, args]
156
158
  # else
157
- # message = devise_mailer.send(notification, self, *args)
158
- # Remove once we move to Rails 4.2+ only.
159
- # if message.respond_to?(:deliver_now)
160
- # message.deliver_now
161
- # else
162
- # message.deliver
163
- # end
159
+ # render_and_send_devise_message(notification, *args)
164
160
  # end
165
161
  # end
166
162
  #
167
- # def send_pending_notifications
168
- # pending_notifications.each do |notification, args|
169
- # message = devise_mailer.send(notification, self, *args)
170
- # Remove once we move to Rails 4.2+ only.
171
- # if message.respond_to?(:deliver_now)
172
- # message.deliver_now
173
- # else
174
- # message.deliver
175
- # end
163
+ # private
164
+ #
165
+ # def send_pending_devise_notifications
166
+ # pending_devise_notifications.each do |notification, args|
167
+ # render_and_send_devise_message(notification, *args)
176
168
  # end
177
169
  #
178
170
  # # Empty the pending notifications array because the
179
171
  # # after_commit hook can be called multiple times which
180
172
  # # could cause multiple emails to be sent.
181
- # pending_notifications.clear
173
+ # pending_devise_notifications.clear
182
174
  # end
183
175
  #
184
- # def pending_notifications
185
- # @pending_notifications ||= []
176
+ # def pending_devise_notifications
177
+ # @pending_devise_notifications ||= []
186
178
  # end
179
+ #
180
+ # def render_and_send_devise_message(notification, *args)
181
+ # message = devise_mailer.send(notification, self, *args)
182
+ #
183
+ # # Deliver later with Active Job's `deliver_later`
184
+ # if message.respond_to?(:deliver_later)
185
+ # message.deliver_later
186
+ # # Remove once we move to Rails 4.2+ only, as `deliver` is deprecated.
187
+ # elsif message.respond_to?(:deliver_now)
188
+ # message.deliver_now
189
+ # else
190
+ # message.deliver
191
+ # end
192
+ # end
193
+ #
187
194
  # end
188
195
  #
189
196
  def send_devise_notification(notification, *args)
@@ -265,39 +272,31 @@ module Devise
265
272
  find_first_by_auth_conditions(tainted_conditions)
266
273
  end
267
274
 
268
- def find_first_by_auth_conditions(tainted_conditions, opts={})
275
+ def find_first_by_auth_conditions(tainted_conditions, opts = {})
269
276
  to_adapter.find_first(devise_parameter_filter.filter(tainted_conditions).merge(opts))
270
277
  end
271
278
 
272
279
  # Find or initialize a record setting an error if it can't be found.
273
- def find_or_initialize_with_error_by(attribute, value, error=:invalid) #:nodoc:
280
+ def find_or_initialize_with_error_by(attribute, value, error = :invalid) #:nodoc:
274
281
  find_or_initialize_with_errors([attribute], { attribute => value }, error)
275
282
  end
276
283
 
277
284
  # Find or initialize a record with group of attributes based on a list of required attributes.
278
- def find_or_initialize_with_errors(required_attributes, attributes, error=:invalid) #:nodoc:
279
- attributes = if attributes.respond_to? :permit!
280
- attributes.slice(*required_attributes).permit!.to_h.with_indifferent_access
281
- else
282
- attributes.with_indifferent_access.slice(*required_attributes)
283
- end
284
- attributes.delete_if { |key, value| value.blank? }
285
+ def find_or_initialize_with_errors(required_attributes, attributes, error = :invalid) #:nodoc:
286
+ attributes.try(:permit!)
287
+ attributes = attributes.to_h.with_indifferent_access
288
+ .slice(*required_attributes)
289
+ .delete_if { |key, value| value.blank? }
285
290
 
286
291
  if attributes.size == required_attributes.size
287
- record = find_first_by_auth_conditions(attributes)
292
+ record = find_first_by_auth_conditions(attributes) and return record
288
293
  end
289
294
 
290
- unless record
291
- record = new
292
-
295
+ new(devise_parameter_filter.filter(attributes)).tap do |record|
293
296
  required_attributes.each do |key|
294
- value = attributes[key]
295
- record.send("#{key}=", value)
296
- record.errors.add(key, value.present? ? error : :blank)
297
+ record.errors.add(key, attributes[key].blank? ? :blank : error)
297
298
  end
298
299
  end
299
-
300
- record
301
300
  end
302
301
 
303
302
  protected
@@ -76,7 +76,7 @@ module Devise
76
76
  # Confirm a user by setting it's confirmed_at to actual time. If the user
77
77
  # is already confirmed, add an error to email field. If the user is invalid
78
78
  # add errors
79
- def confirm(args={})
79
+ def confirm(args = {})
80
80
  pending_any_confirmation do
81
81
  if confirmation_period_expired?
82
82
  self.errors.add(:email, :confirmation_period_expired,
@@ -211,7 +211,10 @@ module Devise
211
211
  # confirmation_period_valid? # will always return true
212
212
  #
213
213
  def confirmation_period_valid?
214
- self.class.allow_unconfirmed_access_for.nil? || (confirmation_sent_at && confirmation_sent_at.utc >= self.class.allow_unconfirmed_access_for.ago)
214
+ return true if self.class.allow_unconfirmed_access_for.nil?
215
+ return false if self.class.allow_unconfirmed_access_for == 0.days
216
+
217
+ confirmation_sent_at && confirmation_sent_at.utc >= self.class.allow_unconfirmed_access_for.ago
215
218
  end
216
219
 
217
220
  # Checks if the user confirmation happens before the token becomes invalid
@@ -331,7 +334,7 @@ module Devise
331
334
  # confirmation instructions to it. If not, try searching for a user by unconfirmed_email
332
335
  # field. If no user is found, returns a new user with an email not found error.
333
336
  # Options must contain the user email
334
- def send_confirmation_instructions(attributes={})
337
+ def send_confirmation_instructions(attributes = {})
335
338
  confirmable = find_by_unconfirmed_email_with_errors(attributes) if reconfirmable
336
339
  unless confirmable.try(:persisted?)
337
340
  confirmable = find_or_initialize_with_errors(confirmation_keys, attributes, :not_found)
@@ -345,7 +348,19 @@ module Devise
345
348
  # If the user is already confirmed, create an error for the user
346
349
  # Options must have the confirmation_token
347
350
  def confirm_by_token(confirmation_token)
351
+ # When the `confirmation_token` parameter is blank, if there are any users with a blank
352
+ # `confirmation_token` in the database, the first one would be confirmed here.
353
+ # The error is being manually added here to ensure no users are confirmed by mistake.
354
+ # This was done in the model for convenience, since validation errors are automatically
355
+ # displayed in the view.
356
+ if confirmation_token.blank?
357
+ confirmable = new
358
+ confirmable.errors.add(:confirmation_token, :blank)
359
+ return confirmable
360
+ end
361
+
348
362
  confirmable = find_first_by_auth_conditions(confirmation_token: confirmation_token)
363
+
349
364
  unless confirmable
350
365
  confirmation_digest = Devise.token_generator.digest(self, :confirmation_token, confirmation_token)
351
366
  confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_digest)
@@ -7,6 +7,10 @@ module Devise
7
7
  # Authenticatable Module, responsible for hashing the password and
8
8
  # validating the authenticity of a user while signing in.
9
9
  #
10
+ # This module defines a `password=` method. This method will hash the argument
11
+ # and store it in the `encrypted_password` column, bypassing any pre-existing
12
+ # `password` column if it exists.
13
+ #
10
14
  # == Options
11
15
  #
12
16
  # DatabaseAuthenticatable adds the following options to devise_for:
@@ -35,6 +39,22 @@ module Devise
35
39
  attr_accessor :password_confirmation
36
40
  end
37
41
 
42
+ def initialize(*args, &block)
43
+ @skip_email_changed_notification = false
44
+ @skip_password_change_notification = false
45
+ super
46
+ end
47
+
48
+ # Skips sending the email changed notification after_update
49
+ def skip_email_changed_notification!
50
+ @skip_email_changed_notification = true
51
+ end
52
+
53
+ # Skips sending the password change notification after_update
54
+ def skip_password_change_notification!
55
+ @skip_password_change_notification = true
56
+ end
57
+
38
58
  def self.required_fields(klass)
39
59
  [:encrypted_password] + klass.authentication_keys
40
60
  end
@@ -65,6 +85,15 @@ module Devise
65
85
  # their password). In case the password field is rejected, the confirmation
66
86
  # is also rejected as long as it is also blank.
67
87
  def update_with_password(params, *options)
88
+ if options.present?
89
+ ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
90
+ [Devise] The second argument of `DatabaseAuthenticatable#update_with_password`
91
+ (`options`) is deprecated and it will be removed in the next major version.
92
+ It was added to support a feature deprecated in Rails 4, so you can safely remove it
93
+ from your code.
94
+ DEPRECATION
95
+ end
96
+
68
97
  current_password = params.delete(:current_password)
69
98
 
70
99
  if params[:password].blank?
@@ -73,11 +102,11 @@ module Devise
73
102
  end
74
103
 
75
104
  result = if valid_password?(current_password)
76
- update_attributes(params, *options)
105
+ update(params, *options)
77
106
  else
78
- self.assign_attributes(params, *options)
79
- self.valid?
80
- self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
107
+ assign_attributes(params, *options)
108
+ valid?
109
+ errors.add(:current_password, current_password.blank? ? :blank : :invalid)
81
110
  false
82
111
  end
83
112
 
@@ -98,10 +127,19 @@ module Devise
98
127
  # end
99
128
  #
100
129
  def update_without_password(params, *options)
130
+ if options.present?
131
+ ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
132
+ [Devise] The second argument of `DatabaseAuthenticatable#update_without_password`
133
+ (`options`) is deprecated and it will be removed in the next major version.
134
+ It was added to support a feature deprecated in Rails 4, so you can safely remove it
135
+ from your code.
136
+ DEPRECATION
137
+ end
138
+
101
139
  params.delete(:password)
102
140
  params.delete(:password_confirmation)
103
141
 
104
- result = update_attributes(params, *options)
142
+ result = update(params, *options)
105
143
  clean_up_passwords
106
144
  result
107
145
  end
@@ -113,8 +151,8 @@ module Devise
113
151
  result = if valid_password?(current_password)
114
152
  destroy
115
153
  else
116
- self.valid?
117
- self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
154
+ valid?
155
+ errors.add(:current_password, current_password.blank? ? :blank : :invalid)
118
156
  false
119
157
  end
120
158
 
@@ -161,7 +199,7 @@ module Devise
161
199
  # Hashes the password using bcrypt. Custom hash functions should override
162
200
  # this method to apply their own algorithm.
163
201
  #
164
- # See https://github.com/plataformatec/devise-encryptable for examples
202
+ # See https://github.com/heartcombo/devise-encryptable for examples
165
203
  # of other hashing engines.
166
204
  def password_digest(password)
167
205
  Devise::Encryptor.digest(self.class, password)
@@ -169,21 +207,21 @@ module Devise
169
207
 
170
208
  if Devise.activerecord51?
171
209
  def send_email_changed_notification?
172
- self.class.send_email_changed_notification && saved_change_to_email?
210
+ self.class.send_email_changed_notification && saved_change_to_email? && !@skip_email_changed_notification
173
211
  end
174
212
  else
175
213
  def send_email_changed_notification?
176
- self.class.send_email_changed_notification && email_changed?
214
+ self.class.send_email_changed_notification && email_changed? && !@skip_email_changed_notification
177
215
  end
178
216
  end
179
217
 
180
218
  if Devise.activerecord51?
181
219
  def send_password_change_notification?
182
- self.class.send_password_change_notification && saved_change_to_encrypted_password?
220
+ self.class.send_password_change_notification && saved_change_to_encrypted_password? && !@skip_password_change_notification
183
221
  end
184
222
  else
185
223
  def send_password_change_notification?
186
- self.class.send_password_change_notification && encrypted_password_changed?
224
+ self.class.send_password_change_notification && encrypted_password_changed? && !@skip_password_change_notification
187
225
  end
188
226
  end
189
227