devise 4.5.0 → 4.9.2

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 (226) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +137 -3
  3. data/MIT-LICENSE +2 -1
  4. data/README.md +125 -60
  5. data/app/controllers/devise/confirmations_controller.rb +1 -0
  6. data/app/controllers/devise/passwords_controller.rb +3 -2
  7. data/app/controllers/devise/registrations_controller.rb +26 -8
  8. data/app/controllers/devise/sessions_controller.rb +1 -1
  9. data/app/controllers/devise/unlocks_controller.rb +1 -0
  10. data/app/controllers/devise_controller.rb +3 -2
  11. data/app/helpers/devise_helper.rb +21 -18
  12. data/app/mailers/devise/mailer.rb +5 -5
  13. data/app/views/devise/confirmations/new.html.erb +1 -1
  14. data/app/views/devise/passwords/edit.html.erb +2 -2
  15. data/app/views/devise/passwords/new.html.erb +1 -1
  16. data/app/views/devise/registrations/edit.html.erb +2 -2
  17. data/app/views/devise/registrations/new.html.erb +1 -1
  18. data/app/views/devise/sessions/new.html.erb +2 -2
  19. data/app/views/devise/shared/_error_messages.html.erb +15 -0
  20. data/app/views/devise/shared/_links.html.erb +8 -8
  21. data/app/views/devise/unlocks/new.html.erb +1 -1
  22. data/config/locales/en.yml +3 -2
  23. data/lib/devise/controllers/helpers.rb +8 -8
  24. data/lib/devise/controllers/responder.rb +35 -0
  25. data/lib/devise/controllers/sign_in_out.rb +6 -4
  26. data/lib/devise/controllers/url_helpers.rb +1 -1
  27. data/lib/devise/failure_app.rb +29 -7
  28. data/lib/devise/hooks/csrf_cleaner.rb +6 -1
  29. data/lib/devise/hooks/lockable.rb +2 -5
  30. data/lib/devise/hooks/timeoutable.rb +2 -2
  31. data/lib/devise/mapping.rb +1 -1
  32. data/lib/devise/models/authenticatable.rb +20 -24
  33. data/lib/devise/models/confirmable.rb +34 -40
  34. data/lib/devise/models/database_authenticatable.rb +47 -28
  35. data/lib/devise/models/lockable.rb +13 -5
  36. data/lib/devise/models/omniauthable.rb +2 -2
  37. data/lib/devise/models/recoverable.rb +8 -19
  38. data/lib/devise/models/registerable.rb +2 -0
  39. data/lib/devise/models/rememberable.rb +2 -2
  40. data/lib/devise/models/timeoutable.rb +1 -1
  41. data/lib/devise/models/trackable.rb +1 -1
  42. data/lib/devise/models/validatable.rb +4 -9
  43. data/lib/devise/models.rb +1 -0
  44. data/lib/devise/omniauth.rb +2 -5
  45. data/lib/devise/orm.rb +71 -0
  46. data/lib/devise/rails/deprecated_constant_accessor.rb +39 -0
  47. data/lib/devise/rails/routes.rb +6 -6
  48. data/lib/devise/strategies/authenticatable.rb +1 -1
  49. data/lib/devise/strategies/database_authenticatable.rb +3 -0
  50. data/lib/devise/test/controller_helpers.rb +4 -2
  51. data/lib/devise/test/integration_helpers.rb +1 -1
  52. data/lib/devise/version.rb +1 -1
  53. data/lib/devise.rb +34 -11
  54. data/lib/generators/active_record/devise_generator.rb +21 -6
  55. data/lib/generators/devise/controllers_generator.rb +1 -1
  56. data/lib/generators/devise/devise_generator.rb +1 -1
  57. data/lib/generators/devise/install_generator.rb +1 -5
  58. data/lib/generators/devise/views_generator.rb +1 -1
  59. data/lib/generators/templates/README +9 -1
  60. data/lib/generators/templates/controllers/omniauth_callbacks_controller.rb +1 -1
  61. data/lib/generators/templates/devise.rb +37 -14
  62. data/lib/generators/templates/simple_form_for/passwords/edit.html.erb +4 -1
  63. data/lib/generators/templates/simple_form_for/registrations/edit.html.erb +2 -2
  64. data/lib/generators/templates/simple_form_for/registrations/new.html.erb +1 -1
  65. metadata +23 -318
  66. data/.gitignore +0 -10
  67. data/.travis.yml +0 -69
  68. data/.yardopts +0 -9
  69. data/CODE_OF_CONDUCT.md +0 -22
  70. data/CONTRIBUTING.md +0 -79
  71. data/Gemfile +0 -39
  72. data/Gemfile.lock +0 -202
  73. data/ISSUE_TEMPLATE.md +0 -19
  74. data/Rakefile +0 -37
  75. data/bin/test +0 -13
  76. data/devise.gemspec +0 -28
  77. data/devise.png +0 -0
  78. data/gemfiles/Gemfile.rails-4.1-stable +0 -32
  79. data/gemfiles/Gemfile.rails-4.1-stable.lock +0 -171
  80. data/gemfiles/Gemfile.rails-4.2-stable +0 -32
  81. data/gemfiles/Gemfile.rails-4.2-stable.lock +0 -192
  82. data/gemfiles/Gemfile.rails-5.0-stable +0 -33
  83. data/gemfiles/Gemfile.rails-5.0-stable.lock +0 -192
  84. data/gemfiles/Gemfile.rails-5.2-rc1 +0 -26
  85. data/gemfiles/Gemfile.rails-5.2-rc1.lock +0 -201
  86. data/guides/bug_report_templates/integration_test.rb +0 -106
  87. data/test/controllers/custom_registrations_controller_test.rb +0 -42
  88. data/test/controllers/custom_strategy_test.rb +0 -66
  89. data/test/controllers/helper_methods_test.rb +0 -24
  90. data/test/controllers/helpers_test.rb +0 -318
  91. data/test/controllers/inherited_controller_i18n_messages_test.rb +0 -53
  92. data/test/controllers/internal_helpers_test.rb +0 -129
  93. data/test/controllers/load_hooks_controller_test.rb +0 -21
  94. data/test/controllers/passwords_controller_test.rb +0 -34
  95. data/test/controllers/sessions_controller_test.rb +0 -108
  96. data/test/controllers/url_helpers_test.rb +0 -67
  97. data/test/delegator_test.rb +0 -21
  98. data/test/devise_test.rb +0 -109
  99. data/test/failure_app_test.rb +0 -346
  100. data/test/generators/active_record_generator_test.rb +0 -130
  101. data/test/generators/controllers_generator_test.rb +0 -50
  102. data/test/generators/devise_generator_test.rb +0 -41
  103. data/test/generators/install_generator_test.rb +0 -26
  104. data/test/generators/mongoid_generator_test.rb +0 -25
  105. data/test/generators/views_generator_test.rb +0 -105
  106. data/test/helpers/devise_helper_test.rb +0 -51
  107. data/test/integration/authenticatable_test.rb +0 -706
  108. data/test/integration/confirmable_test.rb +0 -326
  109. data/test/integration/database_authenticatable_test.rb +0 -110
  110. data/test/integration/http_authenticatable_test.rb +0 -114
  111. data/test/integration/lockable_test.rb +0 -242
  112. data/test/integration/mounted_engine_test.rb +0 -38
  113. data/test/integration/omniauthable_test.rb +0 -148
  114. data/test/integration/recoverable_test.rb +0 -349
  115. data/test/integration/registerable_test.rb +0 -365
  116. data/test/integration/rememberable_test.rb +0 -219
  117. data/test/integration/timeoutable_test.rb +0 -186
  118. data/test/integration/trackable_test.rb +0 -99
  119. data/test/mailers/confirmation_instructions_test.rb +0 -117
  120. data/test/mailers/email_changed_test.rb +0 -132
  121. data/test/mailers/mailer_test.rb +0 -20
  122. data/test/mailers/reset_password_instructions_test.rb +0 -98
  123. data/test/mailers/unlock_instructions_test.rb +0 -93
  124. data/test/mapping_test.rb +0 -136
  125. data/test/models/authenticatable_test.rb +0 -25
  126. data/test/models/confirmable_test.rb +0 -549
  127. data/test/models/database_authenticatable_test.rb +0 -290
  128. data/test/models/lockable_test.rb +0 -352
  129. data/test/models/omniauthable_test.rb +0 -9
  130. data/test/models/recoverable_test.rb +0 -263
  131. data/test/models/registerable_test.rb +0 -9
  132. data/test/models/rememberable_test.rb +0 -184
  133. data/test/models/serializable_test.rb +0 -60
  134. data/test/models/timeoutable_test.rb +0 -53
  135. data/test/models/trackable_test.rb +0 -80
  136. data/test/models/validatable_test.rb +0 -121
  137. data/test/models_test.rb +0 -155
  138. data/test/omniauth/config_test.rb +0 -61
  139. data/test/omniauth/url_helpers_test.rb +0 -53
  140. data/test/orm/active_record.rb +0 -24
  141. data/test/orm/mongoid.rb +0 -15
  142. data/test/parameter_sanitizer_test.rb +0 -105
  143. data/test/rails_app/Rakefile +0 -6
  144. data/test/rails_app/app/active_record/admin.rb +0 -8
  145. data/test/rails_app/app/active_record/shim.rb +0 -4
  146. data/test/rails_app/app/active_record/user.rb +0 -20
  147. data/test/rails_app/app/active_record/user_on_engine.rb +0 -9
  148. data/test/rails_app/app/active_record/user_on_main_app.rb +0 -9
  149. data/test/rails_app/app/active_record/user_with_validations.rb +0 -12
  150. data/test/rails_app/app/active_record/user_without_email.rb +0 -10
  151. data/test/rails_app/app/controllers/admins/sessions_controller.rb +0 -8
  152. data/test/rails_app/app/controllers/admins_controller.rb +0 -8
  153. data/test/rails_app/app/controllers/application_controller.rb +0 -13
  154. data/test/rails_app/app/controllers/application_with_fake_engine.rb +0 -32
  155. data/test/rails_app/app/controllers/custom/registrations_controller.rb +0 -33
  156. data/test/rails_app/app/controllers/home_controller.rb +0 -31
  157. data/test/rails_app/app/controllers/publisher/registrations_controller.rb +0 -4
  158. data/test/rails_app/app/controllers/publisher/sessions_controller.rb +0 -4
  159. data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +0 -16
  160. data/test/rails_app/app/controllers/users_controller.rb +0 -33
  161. data/test/rails_app/app/helpers/application_helper.rb +0 -5
  162. data/test/rails_app/app/mailers/users/from_proc_mailer.rb +0 -5
  163. data/test/rails_app/app/mailers/users/mailer.rb +0 -5
  164. data/test/rails_app/app/mailers/users/reply_to_mailer.rb +0 -6
  165. data/test/rails_app/app/mongoid/admin.rb +0 -31
  166. data/test/rails_app/app/mongoid/shim.rb +0 -25
  167. data/test/rails_app/app/mongoid/user.rb +0 -50
  168. data/test/rails_app/app/mongoid/user_on_engine.rb +0 -41
  169. data/test/rails_app/app/mongoid/user_on_main_app.rb +0 -41
  170. data/test/rails_app/app/mongoid/user_with_validations.rb +0 -37
  171. data/test/rails_app/app/mongoid/user_without_email.rb +0 -35
  172. data/test/rails_app/app/views/admins/index.html.erb +0 -1
  173. data/test/rails_app/app/views/admins/sessions/new.html.erb +0 -2
  174. data/test/rails_app/app/views/home/admin_dashboard.html.erb +0 -1
  175. data/test/rails_app/app/views/home/index.html.erb +0 -1
  176. data/test/rails_app/app/views/home/join.html.erb +0 -1
  177. data/test/rails_app/app/views/home/private.html.erb +0 -1
  178. data/test/rails_app/app/views/home/user_dashboard.html.erb +0 -1
  179. data/test/rails_app/app/views/layouts/application.html.erb +0 -24
  180. data/test/rails_app/app/views/users/edit_form.html.erb +0 -1
  181. data/test/rails_app/app/views/users/index.html.erb +0 -1
  182. data/test/rails_app/app/views/users/mailer/confirmation_instructions.erb +0 -1
  183. data/test/rails_app/app/views/users/sessions/new.html.erb +0 -1
  184. data/test/rails_app/bin/bundle +0 -3
  185. data/test/rails_app/bin/rails +0 -4
  186. data/test/rails_app/bin/rake +0 -4
  187. data/test/rails_app/config/application.rb +0 -48
  188. data/test/rails_app/config/boot.rb +0 -27
  189. data/test/rails_app/config/database.yml +0 -18
  190. data/test/rails_app/config/environment.rb +0 -7
  191. data/test/rails_app/config/environments/development.rb +0 -32
  192. data/test/rails_app/config/environments/production.rb +0 -88
  193. data/test/rails_app/config/environments/test.rb +0 -47
  194. data/test/rails_app/config/initializers/backtrace_silencers.rb +0 -9
  195. data/test/rails_app/config/initializers/devise.rb +0 -187
  196. data/test/rails_app/config/initializers/inflections.rb +0 -4
  197. data/test/rails_app/config/initializers/secret_token.rb +0 -5
  198. data/test/rails_app/config/initializers/session_store.rb +0 -3
  199. data/test/rails_app/config/routes.rb +0 -128
  200. data/test/rails_app/config.ru +0 -4
  201. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +0 -77
  202. data/test/rails_app/db/schema.rb +0 -57
  203. data/test/rails_app/lib/lazy_load_test_module.rb +0 -5
  204. data/test/rails_app/lib/shared_admin.rb +0 -23
  205. data/test/rails_app/lib/shared_user.rb +0 -32
  206. data/test/rails_app/lib/shared_user_without_email.rb +0 -28
  207. data/test/rails_app/lib/shared_user_without_omniauth.rb +0 -15
  208. data/test/rails_app/public/404.html +0 -26
  209. data/test/rails_app/public/422.html +0 -26
  210. data/test/rails_app/public/500.html +0 -26
  211. data/test/rails_app/public/favicon.ico +0 -0
  212. data/test/rails_test.rb +0 -11
  213. data/test/routes_test.rb +0 -281
  214. data/test/secret_key_finder_test.rb +0 -121
  215. data/test/support/action_controller/record_identifier.rb +0 -12
  216. data/test/support/assertions.rb +0 -30
  217. data/test/support/helpers.rb +0 -83
  218. data/test/support/http_method_compatibility.rb +0 -53
  219. data/test/support/integration.rb +0 -95
  220. data/test/support/locale/en.yml +0 -8
  221. data/test/support/mongoid.yml +0 -6
  222. data/test/support/webrat/integrations/rails.rb +0 -35
  223. data/test/test/controller_helpers_test.rb +0 -193
  224. data/test/test/integration_helpers_test.rb +0 -34
  225. data/test/test_helper.rb +0 -36
  226. data/test/test_models.rb +0 -35
@@ -50,12 +50,9 @@ class Devise::RegistrationsController < DeviseController
50
50
  resource_updated = update_resource(resource, account_update_params)
51
51
  yield resource if block_given?
52
52
  if resource_updated
53
- if is_flashing_format?
54
- flash_key = update_needs_confirmation?(resource, prev_unconfirmed_email) ?
55
- :update_needs_confirmation : :updated
56
- set_flash_message :notice, flash_key
57
- end
58
- bypass_sign_in resource, scope: resource_name
53
+ set_flash_message_for_update(resource, prev_unconfirmed_email)
54
+ bypass_sign_in resource, scope: resource_name if sign_in_after_change_password?
55
+
59
56
  respond_with resource, location: after_update_path_for(resource)
60
57
  else
61
58
  clean_up_passwords resource
@@ -70,7 +67,7 @@ class Devise::RegistrationsController < DeviseController
70
67
  Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
71
68
  set_flash_message! :notice, :destroyed
72
69
  yield resource if block_given?
73
- respond_with_navigational(resource){ redirect_to after_sign_out_path_for(resource_name) }
70
+ respond_with_navigational(resource){ redirect_to after_sign_out_path_for(resource_name), status: Devise.responder.redirect_status }
74
71
  end
75
72
 
76
73
  # GET /resource/cancel
@@ -127,7 +124,7 @@ class Devise::RegistrationsController < DeviseController
127
124
  # The default url to be used after updating a resource. You need to overwrite
128
125
  # this method in your own RegistrationsController.
129
126
  def after_update_path_for(resource)
130
- signed_in_root_path(resource)
127
+ sign_in_after_change_password? ? signed_in_root_path(resource) : new_session_path(resource_name)
131
128
  end
132
129
 
133
130
  # Authenticates the current scope and gets the current resource from the session.
@@ -147,4 +144,25 @@ class Devise::RegistrationsController < DeviseController
147
144
  def translation_scope
148
145
  'devise.registrations'
149
146
  end
147
+
148
+ private
149
+
150
+ def set_flash_message_for_update(resource, prev_unconfirmed_email)
151
+ return unless is_flashing_format?
152
+
153
+ flash_key = if update_needs_confirmation?(resource, prev_unconfirmed_email)
154
+ :update_needs_confirmation
155
+ elsif sign_in_after_change_password?
156
+ :updated
157
+ else
158
+ :updated_but_not_signed_in
159
+ end
160
+ set_flash_message :notice, flash_key
161
+ end
162
+
163
+ def sign_in_after_change_password?
164
+ return true if account_update_params[:password].blank?
165
+
166
+ Devise.sign_in_after_change_password
167
+ end
150
168
  end
@@ -77,7 +77,7 @@ class Devise::SessionsController < DeviseController
77
77
  # support returning empty response on GET request
78
78
  respond_to do |format|
79
79
  format.all { head :no_content }
80
- format.any(*navigational_formats) { redirect_to after_sign_out_path_for(resource_name) }
80
+ format.any(*navigational_formats) { redirect_to after_sign_out_path_for(resource_name), status: Devise.responder.redirect_status }
81
81
  end
82
82
  end
83
83
  end
@@ -29,6 +29,7 @@ class Devise::UnlocksController < DeviseController
29
29
  set_flash_message! :notice, :unlocked
30
30
  respond_with_navigational(resource){ redirect_to after_unlock_path_for(resource) }
31
31
  else
32
+ # TODO: use `error_status` when the default changes to `:unprocessable_entity`.
32
33
  respond_with_navigational(resource.errors, status: :unprocessable_entity){ render :new }
33
34
  end
34
35
  end
@@ -15,6 +15,7 @@ class DeviseController < Devise.parent_controller.constantize
15
15
  end
16
16
 
17
17
  prepend_before_action :assert_is_devise_resource!
18
+ self.responder = Devise.responder
18
19
  respond_to :html if mimes_for_respond_to.empty?
19
20
 
20
21
  # Override prefixes to consider the scoped view.
@@ -112,7 +113,7 @@ MESSAGE
112
113
  end
113
114
 
114
115
  if authenticated && resource = warden.user(resource_name)
115
- flash[:alert] = I18n.t("devise.failure.already_authenticated")
116
+ set_flash_message(:alert, 'already_authenticated', scope: 'devise.failure')
116
117
  redirect_to after_sign_in_path_for(resource)
117
118
  end
118
119
  end
@@ -184,7 +185,7 @@ MESSAGE
184
185
  options[:default] = Array(options[:default]).unshift(kind.to_sym)
185
186
  options[:resource_name] = resource_name
186
187
  options = devise_i18n_options(options)
187
- I18n.t("#{options[:resource_name]}.#{kind}", options)
188
+ I18n.t("#{options[:resource_name]}.#{kind}", **options)
188
189
  end
189
190
 
190
191
  # Controllers inheriting DeviseController are advised to override this
@@ -1,27 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DeviseHelper
4
- # A simple way to show error messages for the current devise resource. If you need
5
- # to customize this method, you can either overwrite it in your application helpers or
6
- # copy the views to your application.
7
- #
8
- # This method is intended to stay simple and it is unlikely that we are going to change
9
- # it to add more behavior or options.
4
+ # Retain this method for backwards compatibility, deprecated in favor of modifying the
5
+ # devise/shared/error_messages partial.
10
6
  def devise_error_messages!
11
- return "" if resource.errors.empty?
7
+ ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
8
+ [Devise] `DeviseHelper#devise_error_messages!` is deprecated and will be
9
+ removed in the next major version.
10
+
11
+ Devise now uses a partial under "devise/shared/error_messages" to display
12
+ error messages by default, and make them easier to customize. Update your
13
+ views changing calls from:
14
+
15
+ <%= devise_error_messages! %>
12
16
 
13
- messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join
14
- sentence = I18n.t("errors.messages.not_saved",
15
- count: resource.errors.count,
16
- resource: resource.class.model_name.human.downcase)
17
+ to:
17
18
 
18
- html = <<-HTML
19
- <div id="error_explanation">
20
- <h2>#{sentence}</h2>
21
- <ul>#{messages}</ul>
22
- </div>
23
- HTML
19
+ <%= render "devise/shared/error_messages", resource: resource %>
20
+
21
+ To start customizing how errors are displayed, you can copy the partial
22
+ from devise to your `app/views` folder. Alternatively, you can run
23
+ `rails g devise:views` which will copy all of them again to your app.
24
+ DEPRECATION
25
+
26
+ return "" if resource.errors.empty?
24
27
 
25
- html.html_safe
28
+ render "devise/shared/error_messages", resource: resource
26
29
  end
27
30
  end
@@ -4,26 +4,26 @@ if defined?(ActionMailer)
4
4
  class Devise::Mailer < Devise.parent_mailer.constantize
5
5
  include Devise::Mailers::Helpers
6
6
 
7
- def confirmation_instructions(record, token, opts={})
7
+ def confirmation_instructions(record, token, opts = {})
8
8
  @token = token
9
9
  devise_mail(record, :confirmation_instructions, opts)
10
10
  end
11
11
 
12
- def reset_password_instructions(record, token, opts={})
12
+ def reset_password_instructions(record, token, opts = {})
13
13
  @token = token
14
14
  devise_mail(record, :reset_password_instructions, opts)
15
15
  end
16
16
 
17
- def unlock_instructions(record, token, opts={})
17
+ def unlock_instructions(record, token, opts = {})
18
18
  @token = token
19
19
  devise_mail(record, :unlock_instructions, opts)
20
20
  end
21
21
 
22
- def email_changed(record, opts={})
22
+ def email_changed(record, opts = {})
23
23
  devise_mail(record, :email_changed, opts)
24
24
  end
25
25
 
26
- def password_change(record, opts={})
26
+ def password_change(record, opts = {})
27
27
  devise_mail(record, :password_change, opts)
28
28
  end
29
29
  end
@@ -1,7 +1,7 @@
1
1
  <h2>Resend confirmation instructions</h2>
2
2
 
3
3
  <%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
4
- <%= devise_error_messages! %>
4
+ <%= render "devise/shared/error_messages", resource: resource %>
5
5
 
6
6
  <div class="field">
7
7
  <%= f.label :email %><br />
@@ -1,7 +1,7 @@
1
1
  <h2>Change your password</h2>
2
2
 
3
3
  <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %>
4
- <%= devise_error_messages! %>
4
+ <%= render "devise/shared/error_messages", resource: resource %>
5
5
  <%= f.hidden_field :reset_password_token %>
6
6
 
7
7
  <div class="field">
@@ -14,7 +14,7 @@
14
14
 
15
15
  <div class="field">
16
16
  <%= f.label :password_confirmation, "Confirm new password" %><br />
17
- <%= f.password_field :password_confirmation, autocomplete: "off" %>
17
+ <%= f.password_field :password_confirmation, autocomplete: "new-password" %>
18
18
  </div>
19
19
 
20
20
  <div class="actions">
@@ -1,7 +1,7 @@
1
1
  <h2>Forgot your password?</h2>
2
2
 
3
3
  <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %>
4
- <%= devise_error_messages! %>
4
+ <%= render "devise/shared/error_messages", resource: resource %>
5
5
 
6
6
  <div class="field">
7
7
  <%= f.label :email %><br />
@@ -1,7 +1,7 @@
1
1
  <h2>Edit <%= resource_name.to_s.humanize %></h2>
2
2
 
3
3
  <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
4
- <%= devise_error_messages! %>
4
+ <%= render "devise/shared/error_messages", resource: resource %>
5
5
 
6
6
  <div class="field">
7
7
  <%= f.label :email %><br />
@@ -38,6 +38,6 @@
38
38
 
39
39
  <h3>Cancel my account</h3>
40
40
 
41
- <p>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %></p>
41
+ <div>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure?" }, method: :delete %></div>
42
42
 
43
43
  <%= link_to "Back", :back %>
@@ -1,7 +1,7 @@
1
1
  <h2>Sign up</h2>
2
2
 
3
3
  <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
4
- <%= devise_error_messages! %>
4
+ <%= render "devise/shared/error_messages", resource: resource %>
5
5
 
6
6
  <div class="field">
7
7
  <%= f.label :email %><br />
@@ -11,12 +11,12 @@
11
11
  <%= f.password_field :password, autocomplete: "current-password" %>
12
12
  </div>
13
13
 
14
- <% if devise_mapping.rememberable? -%>
14
+ <% if devise_mapping.rememberable? %>
15
15
  <div class="field">
16
16
  <%= f.check_box :remember_me %>
17
17
  <%= f.label :remember_me %>
18
18
  </div>
19
- <% end -%>
19
+ <% end %>
20
20
 
21
21
  <div class="actions">
22
22
  <%= f.submit "Log in" %>
@@ -0,0 +1,15 @@
1
+ <% if resource.errors.any? %>
2
+ <div id="error_explanation" data-turbo-cache="false">
3
+ <h2>
4
+ <%= I18n.t("errors.messages.not_saved",
5
+ count: resource.errors.count,
6
+ resource: resource.class.model_name.human.downcase)
7
+ %>
8
+ </h2>
9
+ <ul>
10
+ <% resource.errors.full_messages.each do |message| %>
11
+ <li><%= message %></li>
12
+ <% end %>
13
+ </ul>
14
+ </div>
15
+ <% end %>
@@ -1,25 +1,25 @@
1
1
  <%- if controller_name != 'sessions' %>
2
2
  <%= link_to "Log in", new_session_path(resource_name) %><br />
3
- <% end -%>
3
+ <% end %>
4
4
 
5
5
  <%- if devise_mapping.registerable? && controller_name != 'registrations' %>
6
6
  <%= link_to "Sign up", new_registration_path(resource_name) %><br />
7
- <% end -%>
7
+ <% end %>
8
8
 
9
9
  <%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
10
10
  <%= link_to "Forgot your password?", new_password_path(resource_name) %><br />
11
- <% end -%>
11
+ <% end %>
12
12
 
13
13
  <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
14
14
  <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %><br />
15
- <% end -%>
15
+ <% end %>
16
16
 
17
17
  <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
18
18
  <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %><br />
19
- <% end -%>
19
+ <% end %>
20
20
 
21
21
  <%- if devise_mapping.omniauthable? %>
22
22
  <%- resource_class.omniauth_providers.each do |provider| %>
23
- <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider) %><br />
24
- <% end -%>
25
- <% end -%>
23
+ <%= button_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), data: { turbo: false } %><br />
24
+ <% end %>
25
+ <% end %>
@@ -1,7 +1,7 @@
1
1
  <h2>Resend unlock instructions</h2>
2
2
 
3
3
  <%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %>
4
- <%= devise_error_messages! %>
4
+ <%= render "devise/shared/error_messages", resource: resource %>
5
5
 
6
6
  <div class="field">
7
7
  <%= f.label :email %><br />
@@ -1,4 +1,4 @@
1
- # Additional translations at https://github.com/plataformatec/devise/wiki/I18n
1
+ # Additional translations at https://github.com/heartcombo/devise/wiki/I18n
2
2
 
3
3
  en:
4
4
  devise:
@@ -42,8 +42,9 @@ en:
42
42
  signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated."
43
43
  signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked."
44
44
  signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account."
45
- update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirm link to confirm your new email address."
45
+ update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirmation link to confirm your new email address."
46
46
  updated: "Your account has been updated successfully."
47
+ updated_but_not_signed_in: "Your account has been updated successfully, but since your password was changed, you need to sign in again."
47
48
  sessions:
48
49
  signed_in: "Signed in successfully."
49
50
  signed_out: "Signed out successfully."
@@ -36,14 +36,14 @@ module Devise
36
36
  # before_action ->{ authenticate_blogger! :admin } # Redirects to the admin login page
37
37
  # current_blogger :user # Preferably returns a User if one is signed in
38
38
  #
39
- def devise_group(group_name, opts={})
39
+ def devise_group(group_name, opts = {})
40
40
  mappings = "[#{ opts[:contains].map { |m| ":#{m}" }.join(',') }]"
41
41
 
42
42
  class_eval <<-METHODS, __FILE__, __LINE__ + 1
43
- def authenticate_#{group_name}!(favourite=nil, opts={})
43
+ def authenticate_#{group_name}!(favorite = nil, opts = {})
44
44
  unless #{group_name}_signed_in?
45
45
  mappings = #{mappings}
46
- mappings.unshift mappings.delete(favourite.to_sym) if favourite
46
+ mappings.unshift mappings.delete(favorite.to_sym) if favorite
47
47
  mappings.each do |mapping|
48
48
  opts[:scope] = mapping
49
49
  warden.authenticate!(opts) if !devise_controller? || opts.delete(:force)
@@ -57,9 +57,9 @@ module Devise
57
57
  end
58
58
  end
59
59
 
60
- def current_#{group_name}(favourite=nil)
60
+ def current_#{group_name}(favorite = nil)
61
61
  mappings = #{mappings}
62
- mappings.unshift mappings.delete(favourite.to_sym) if favourite
62
+ mappings.unshift mappings.delete(favorite.to_sym) if favorite
63
63
  mappings.each do |mapping|
64
64
  current = warden.authenticate(scope: mapping)
65
65
  return current if current
@@ -113,7 +113,7 @@ module Devise
113
113
  mapping = mapping.name
114
114
 
115
115
  class_eval <<-METHODS, __FILE__, __LINE__ + 1
116
- def authenticate_#{mapping}!(opts={})
116
+ def authenticate_#{mapping}!(opts = {})
117
117
  opts[:scope] = :#{mapping}
118
118
  warden.authenticate!(opts) if !devise_controller? || opts.delete(:force)
119
119
  end
@@ -252,7 +252,7 @@ module Devise
252
252
  # Overwrite Rails' handle unverified request to sign out all scopes,
253
253
  # clear run strategies and remove cached variables.
254
254
  def handle_unverified_request
255
- super # call the default behaviour which resets/nullifies/raises
255
+ super # call the default behavior which resets/nullifies/raises
256
256
  request.env["devise.skip_storage"] = true
257
257
  sign_out_all_scopes(false)
258
258
  end
@@ -268,7 +268,7 @@ module Devise
268
268
  # Check if flash messages should be emitted. Default is to do it on
269
269
  # navigational formats
270
270
  def is_flashing_format?
271
- is_navigational_format?
271
+ request.respond_to?(:flash) && is_navigational_format?
272
272
  end
273
273
 
274
274
  private
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Devise
4
+ module Controllers
5
+ # Custom Responder to configure default statuses that only apply to Devise,
6
+ # and allow to integrate more easily with Hotwire/Turbo.
7
+ class Responder < ActionController::Responder
8
+ if respond_to?(:error_status=) && respond_to?(:redirect_status=)
9
+ self.error_status = :ok
10
+ self.redirect_status = :found
11
+ else
12
+ # TODO: remove this support for older Rails versions, which aren't supported by Turbo
13
+ # and/or responders. It won't allow configuring a custom response, but it allows Devise
14
+ # to use these methods and defaults across the implementation more easily.
15
+ def self.error_status
16
+ :ok
17
+ end
18
+
19
+ def self.redirect_status
20
+ :found
21
+ end
22
+
23
+ def self.error_status=(*)
24
+ warn "[DEVISE] Setting the error status on the Devise responder has no effect with this " \
25
+ "version of `responders`, please make sure you're using a newer version. Check the changelog for more info."
26
+ end
27
+
28
+ def self.redirect_status=(*)
29
+ warn "[DEVISE] Setting the redirect status on the Devise responder has no effect with this " \
30
+ "version of `responders`, please make sure you're using a newer version. Check the changelog for more info."
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -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
@@ -21,7 +21,7 @@ module Devise
21
21
  # to the set_user method in warden.
22
22
  # If you are using a custom warden strategy and the timeoutable module, you have to
23
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/plataformatec/devise/blob/master/app/controllers/devise/sessions_controller.rb#L7
24
+ # in the sessions controller: https://github.com/heartcombo/devise/blob/main/app/controllers/devise/sessions_controller.rb#L7
25
25
  #
26
26
  # Examples:
27
27
  #
@@ -77,7 +77,7 @@ module Devise
77
77
  # sign_out :user # sign_out(scope)
78
78
  # sign_out @user # sign_out(resource)
79
79
  #
80
- def sign_out(resource_or_scope=nil)
80
+ def sign_out(resource_or_scope = nil)
81
81
  return sign_out_all_scopes unless resource_or_scope
82
82
  scope = Devise::Mapping.find_scope!(resource_or_scope)
83
83
  user = warden.user(scope: scope, run_callbacks: false) # If there is no user
@@ -92,7 +92,7 @@ module Devise
92
92
  # Sign out all active users or scopes. This helper is useful for signing out all roles
93
93
  # in one click. This signs out ALL scopes in warden. Returns true if there was at least one logout
94
94
  # and false if there was no user logged in on all scopes.
95
- def sign_out_all_scopes(lock=true)
95
+ def sign_out_all_scopes(lock = true)
96
96
  users = Devise.mappings.keys.map { |s| warden.user(scope: s, run_callbacks: false) }
97
97
 
98
98
  warden.logout
@@ -106,10 +106,12 @@ module Devise
106
106
  private
107
107
 
108
108
  def expire_data_after_sign_in!
109
+ # TODO: remove once Rails 5.2+ and forward are only supported.
109
110
  # session.keys will return an empty array if the session is not yet loaded.
110
111
  # This is a bug in both Rack and Rails.
111
112
  # A call to #empty? forces the session to be loaded.
112
113
  session.empty?
114
+
113
115
  session.keys.grep(/^devise\./).each { |k| session.delete(k) }
114
116
  end
115
117
 
@@ -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,8 +71,11 @@ 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
- self.response = recall_app(warden_options[:recall]).call(request.env)
74
+ self.response = recall_app(warden_options[:recall]).call(request.env).tap { |response|
75
+ response[0] = Rack::Utils.status_code(
76
+ response[0].in?(300..399) ? Devise.responder.redirect_status : Devise.responder.error_status
77
+ )
78
+ }
76
79
  end
77
80
 
78
81
  def redirect
@@ -107,7 +110,7 @@ module Devise
107
110
  options[:authentication_keys] = keys.join(I18n.translate(:"support.array.words_connector"))
108
111
  options = i18n_options(options)
109
112
 
110
- I18n.t(:"#{scope}.#{message}", options)
113
+ I18n.t(:"#{scope}.#{message}", **options)
111
114
  else
112
115
  message.to_s
113
116
  end
@@ -144,11 +147,20 @@ module Devise
144
147
 
145
148
  opts[:format] = request_format unless skip_format?
146
149
 
147
- opts[:script_name] = relative_url_root if relative_url_root?
148
-
149
150
  router_name = Devise.mappings[scope].router_name || Devise.available_router_name
150
151
  context = send(router_name)
151
152
 
153
+ if relative_url_root?
154
+ opts[:script_name] = relative_url_root
155
+
156
+ # We need to add the rootpath to `script_name` manually for applications that use a Rails
157
+ # version lower than 5.1. Otherwise, it is going to generate a wrong path for Engines
158
+ # that use Devise. Remove it when the support of Rails 5.0 is dropped.
159
+ elsif root_path_defined?(context) && !rails_51_and_up?
160
+ rootpath = context.routes.url_helpers.root_path
161
+ opts[:script_name] = rootpath.chomp('/') if rootpath.length > 1
162
+ end
163
+
152
164
  if context.respond_to?(route)
153
165
  context.send(route, opts)
154
166
  elsif respond_to?(:root_url)
@@ -159,7 +171,7 @@ module Devise
159
171
  end
160
172
 
161
173
  def skip_format?
162
- %w(html */*).include? request_format.to_s
174
+ %w(html */* turbo_stream).include? request_format.to_s
163
175
  end
164
176
 
165
177
  # Choose whether we should respond in an HTTP authentication fashion,
@@ -242,7 +254,7 @@ module Devise
242
254
  # Check if flash messages should be emitted. Default is to do it on
243
255
  # navigational formats
244
256
  def is_flashing_format?
245
- is_navigational_format?
257
+ request.respond_to?(:flash) && is_navigational_format?
246
258
  end
247
259
 
248
260
  def request_format
@@ -262,5 +274,15 @@ module Devise
262
274
  end
263
275
 
264
276
  ActiveSupport.run_load_hooks(:devise_failure_app, self)
277
+
278
+ private
279
+
280
+ def root_path_defined?(context)
281
+ defined?(context.routes) && context.routes.url_helpers.respond_to?(:root_path)
282
+ end
283
+
284
+ def rails_51_and_up?
285
+ Rails.gem_version >= Gem::Version.new("5.1")
286
+ end
265
287
  end
266
288
  end
@@ -4,6 +4,11 @@ Warden::Manager.after_authentication do |record, warden, options|
4
4
  clean_up_for_winning_strategy = !warden.winning_strategy.respond_to?(:clean_up_csrf?) ||
5
5
  warden.winning_strategy.clean_up_csrf?
6
6
  if Devise.clean_up_csrf_token_on_authentication && clean_up_for_winning_strategy
7
- warden.request.session.try(:delete, :_csrf_token)
7
+ if warden.request.respond_to?(:reset_csrf_token)
8
+ # Rails 7.1+
9
+ warden.request.reset_csrf_token
10
+ else
11
+ warden.request.session.try(:delete, :_csrf_token)
12
+ end
8
13
  end
9
14
  end
@@ -3,10 +3,7 @@
3
3
  # After each sign in, if resource responds to failed_attempts, sets it to 0
4
4
  # This is only triggered when the user is explicitly set (with set_user)
5
5
  Warden::Manager.after_set_user except: :fetch do |record, warden, options|
6
- if record.respond_to?(:failed_attempts) && warden.authenticated?(options[:scope])
7
- unless record.failed_attempts.to_i.zero?
8
- record.failed_attempts = 0
9
- record.save(validate: false)
10
- end
6
+ if record.respond_to?(:reset_failed_attempts!) && warden.authenticated?(options[:scope])
7
+ record.reset_failed_attempts!
11
8
  end
12
9
  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