clearance 1.10.1 → 1.17.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of clearance might be problematic. Click here for more details.

Files changed (106) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.travis.yml +20 -8
  4. data/.yardopts +3 -0
  5. data/Appraisals +13 -16
  6. data/Gemfile +7 -5
  7. data/Gemfile.lock +124 -130
  8. data/NEWS.md +171 -2
  9. data/README.md +99 -42
  10. data/app/controllers/clearance/passwords_controller.rb +35 -21
  11. data/app/controllers/clearance/sessions_controller.rb +17 -3
  12. data/app/controllers/clearance/users_controller.rb +10 -4
  13. data/app/mailers/clearance_mailer.rb +2 -3
  14. data/app/views/clearance_mailer/change_password.text.erb +1 -1
  15. data/app/views/layouts/application.html.erb +0 -1
  16. data/bin/setup +6 -2
  17. data/clearance.gemspec +5 -2
  18. data/config/locales/clearance.en.yml +9 -0
  19. data/gemfiles/rails_4.2.gemfile +20 -0
  20. data/gemfiles/rails_5.0.gemfile +21 -0
  21. data/gemfiles/rails_5.1.gemfile +21 -0
  22. data/gemfiles/rails_5.2.gemfile +21 -0
  23. data/lib/clearance/authentication.rb +63 -3
  24. data/lib/clearance/authorization.rb +48 -5
  25. data/lib/clearance/back_door.rb +55 -6
  26. data/lib/clearance/configuration.rb +50 -10
  27. data/lib/clearance/constraints/signed_in.rb +21 -0
  28. data/lib/clearance/constraints/signed_out.rb +12 -0
  29. data/lib/clearance/constraints.rb +12 -0
  30. data/lib/clearance/controller.rb +13 -0
  31. data/lib/clearance/default_sign_in_guard.rb +17 -0
  32. data/lib/clearance/engine.rb +18 -5
  33. data/lib/clearance/password_strategies/bcrypt.rb +16 -21
  34. data/lib/clearance/password_strategies/bcrypt_migration_from_sha1.rb +10 -0
  35. data/lib/clearance/password_strategies/blowfish.rb +10 -1
  36. data/lib/clearance/password_strategies/sha1.rb +9 -0
  37. data/lib/clearance/password_strategies.rb +13 -0
  38. data/lib/clearance/rack_session.rb +13 -0
  39. data/lib/clearance/rspec.rb +15 -4
  40. data/lib/clearance/session.rb +62 -13
  41. data/lib/clearance/session_status.rb +7 -0
  42. data/lib/clearance/sign_in_guard.rb +65 -0
  43. data/lib/clearance/test_unit.rb +3 -3
  44. data/lib/clearance/testing/controller_helpers.rb +57 -0
  45. data/lib/clearance/testing/deny_access_matcher.rb +36 -2
  46. data/lib/clearance/testing/helpers.rb +9 -25
  47. data/lib/clearance/testing/view_helpers.rb +32 -0
  48. data/lib/clearance/token.rb +7 -0
  49. data/lib/clearance/user.rb +183 -4
  50. data/lib/clearance/version.rb +1 -1
  51. data/lib/generators/clearance/install/install_generator.rb +28 -9
  52. data/lib/generators/clearance/install/templates/README +1 -1
  53. data/lib/generators/clearance/install/templates/clearance.rb +1 -0
  54. data/lib/generators/clearance/install/templates/db/migrate/{add_clearance_to_users.rb → add_clearance_to_users.rb.erb} +3 -3
  55. data/lib/generators/clearance/install/templates/db/migrate/{create_users.rb → create_users.rb.erb} +2 -2
  56. data/lib/generators/clearance/install/templates/user.rb.erb +3 -0
  57. data/lib/generators/clearance/routes/routes_generator.rb +23 -0
  58. data/lib/generators/clearance/routes/templates/routes.rb +7 -7
  59. data/lib/generators/clearance/specs/templates/factories/clearance.rb +2 -2
  60. data/lib/generators/clearance/specs/templates/features/clearance/user_signs_out_spec.rb.tt +1 -1
  61. data/lib/generators/clearance/specs/templates/features/clearance/visitor_resets_password_spec.rb.tt +12 -3
  62. data/lib/generators/clearance/specs/templates/features/clearance/visitor_signs_in_spec.rb.tt +3 -3
  63. data/lib/generators/clearance/specs/templates/features/clearance/visitor_signs_up_spec.rb.tt +1 -1
  64. data/lib/generators/clearance/specs/templates/features/clearance/visitor_updates_password_spec.rb.tt +2 -2
  65. data/lib/generators/clearance/specs/templates/support/features/clearance_helpers.rb +2 -2
  66. data/spec/acceptance/clearance_installation_spec.rb +15 -7
  67. data/spec/app_templates/app/models/rails5/user.rb +5 -0
  68. data/spec/app_templates/config/initializers/clearance.rb +2 -0
  69. data/spec/app_templates/testapp/Gemfile +1 -1
  70. data/spec/app_templates/testapp/app/controllers/home_controller.rb +5 -1
  71. data/spec/clearance/back_door_spec.rb +70 -6
  72. data/spec/clearance/session_spec.rb +4 -16
  73. data/spec/clearance/testing/controller_helpers_spec.rb +38 -0
  74. data/spec/clearance/testing/view_helpers_spec.rb +37 -0
  75. data/spec/configuration_spec.rb +79 -86
  76. data/spec/controllers/apis_controller_spec.rb +6 -2
  77. data/spec/controllers/forgeries_controller_spec.rb +12 -3
  78. data/spec/controllers/passwords_controller_spec.rb +74 -38
  79. data/spec/controllers/permissions_controller_spec.rb +13 -3
  80. data/spec/controllers/sessions_controller_spec.rb +40 -11
  81. data/spec/controllers/users_controller_spec.rb +16 -8
  82. data/spec/dummy/app/controllers/application_controller.rb +5 -1
  83. data/spec/dummy/application.rb +9 -11
  84. data/spec/factories.rb +5 -5
  85. data/spec/generators/clearance/install/install_generator_spec.rb +29 -3
  86. data/spec/generators/clearance/routes/routes_generator_spec.rb +5 -1
  87. data/spec/helpers/helper_helpers_spec.rb +10 -0
  88. data/spec/{user_spec.rb → models/user_spec.rb} +10 -1
  89. data/spec/password_strategies/blowfish_spec.rb +1 -1
  90. data/spec/requests/cookie_options_spec.rb +52 -0
  91. data/spec/requests/csrf_rotation_spec.rb +35 -0
  92. data/spec/requests/password_maintenance_spec.rb +18 -0
  93. data/spec/requests/token_expiration_spec.rb +54 -0
  94. data/spec/spec_helper.rb +22 -4
  95. data/spec/support/environment.rb +12 -0
  96. data/spec/support/generator_spec_helpers.rb +13 -1
  97. data/spec/support/http_method_shim.rb +25 -0
  98. data/spec/support/request_with_remember_token.rb +5 -0
  99. data/spec/views/view_helpers_spec.rb +10 -0
  100. metadata +69 -15
  101. data/gemfiles/rails3.2.gemfile +0 -18
  102. data/gemfiles/rails4.0.gemfile +0 -19
  103. data/gemfiles/rails4.1.gemfile +0 -18
  104. data/gemfiles/rails4.2.gemfile +0 -18
  105. data/lib/generators/clearance/install/templates/user.rb +0 -3
  106. data/spec/clearance/testing/helpers_spec.rb +0 -38
@@ -1,31 +1,15 @@
1
+ require "clerance/testing/controller_helpers"
2
+
1
3
  module Clearance
2
4
  module Testing
5
+ # @deprecated Use Clearance::Testing::ControllerHelpers
3
6
  module Helpers
4
- def setup_controller_request_and_response
5
- super
6
- @request.env[:clearance] = Clearance::Session.new(@request.env)
7
- end
8
-
9
- def sign_in
10
- unless defined?(FactoryGirl)
11
- raise(
12
- RuntimeError,
13
- "Clearance's `sign_in` helper requires factory_girl"
14
- )
15
- end
16
-
17
- factory = Clearance.configuration.user_model.to_s.underscore.to_sym
18
- sign_in_as FactoryGirl.create(factory)
19
- end
20
-
21
- def sign_in_as(user)
22
- @controller.sign_in user
23
- user
24
- end
25
-
26
- def sign_out
27
- @controller.sign_out
28
- end
7
+ warn(
8
+ "#{Kernel.caller.first} [DEPRECATION] Clearance::Testing::Helpers is "\
9
+ "deprecated and has been replaced with " \
10
+ "Clearance::Testing::ControllerHelpers. Require " \
11
+ "clearance/testing/controller_helpers instead."
12
+ )
29
13
  end
30
14
  end
31
15
  end
@@ -0,0 +1,32 @@
1
+ module Clearance
2
+ module Testing
3
+ # Provides helpers to your view and helper specs.
4
+ # Using these helpers makes `current_user`, `signed_in?` and `signed_out?`
5
+ # behave properly in view and helper specs.
6
+ module ViewHelpers
7
+ # Sets current_user on the view under test to a new instance of your user
8
+ # model.
9
+ def sign_in
10
+ view.current_user = Clearance.configuration.user_model.new
11
+ end
12
+
13
+ # Sets current_user on the view under test to the supplied user.
14
+ def sign_in_as(user)
15
+ view.current_user = user
16
+ end
17
+
18
+ # @api private
19
+ module CurrentUser
20
+ attr_accessor :current_user
21
+
22
+ def signed_in?
23
+ current_user.present?
24
+ end
25
+
26
+ def signed_out?
27
+ !signed_in?
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,5 +1,12 @@
1
1
  module Clearance
2
+ # Random token used for password reset and remember tokens.
3
+ # Clearance tokens are also public API and are inteded to be used anywhere you
4
+ # need a random token to correspond to a given user (e.g. you added an email
5
+ # confirmation token).
2
6
  class Token
7
+ # Generate a new random, 20 byte hex token.
8
+ #
9
+ # @return [String]
3
10
  def self.new
4
11
  SecureRandom.hex(20).encode('UTF-8')
5
12
  end
@@ -1,25 +1,142 @@
1
1
  require 'digest/sha1'
2
+ require 'active_model'
2
3
  require 'email_validator'
3
4
  require 'clearance/token'
4
5
 
5
6
  module Clearance
7
+ # Required to be included in your configued user class, which is `User` by
8
+ # default, but can be changed with {Configuration#user_model=}.
9
+ #
10
+ # class User
11
+ # include Clearance::User
12
+ #
13
+ # # ...
14
+ # end
15
+ #
16
+ # This will also include methods exposed by your password strategy, which can
17
+ # be configured with {Configuration#password_strategy=}. By default, this is
18
+ # {PasswordStrategies::BCrypt}.
19
+ #
20
+ # ## Validations
21
+ #
22
+ # These validations are added to the class that the {User} module is mixed
23
+ # into.
24
+ #
25
+ # * If {#email_optional?} is false, {#email} is validated for presence,
26
+ # uniqueness and email format (using the `email_validator` gem in strict
27
+ # mode).
28
+ # * If {#skip_password_validation?} is false, {#password} is validated
29
+ # for presence.
30
+ #
31
+ # ## Callbacks
32
+ #
33
+ # * {#normalize_email} will be called on `before_validation`
34
+ # * {#generate_remember_token} will be called on `before_create`
35
+ #
36
+ # @!attribute email
37
+ # @return [String] The user's email.
38
+ #
39
+ # @!attribute encrypted_password
40
+ # @return [String] The user's encrypted password.
41
+ #
42
+ # @!attribute remember_token
43
+ # @return [String] The value used to identify this user in their {Session}
44
+ # cookie.
45
+ #
46
+ # @!attribute confirmation_token
47
+ # @return [String] The value used to identify this user in the password
48
+ # reset link.
49
+ #
50
+ # @!attribute password_changing
51
+ # @deprecated Dirty tracking is now handled automatically.
52
+ #
53
+ # @!attribute [r] password
54
+ # @return [String] Transient (non-persisted) attribute that is set when
55
+ # updating a user's password. Only the {#encrypted_password} is persisted.
56
+ #
57
+ # @!method password=
58
+ # Sets the user's encrypted_password by using the configured Password
59
+ # Strategy's `password=` method. By default, this will be
60
+ # {PasswordStrategies::BCrypt#password=}, but can be changed with
61
+ # {Configuration#password_strategy}.
62
+ #
63
+ # @see PasswordStrategies
64
+ # @return [void]
65
+ #
66
+ # @!method authenticated?
67
+ # Check's the provided password against the user's encrypted password using
68
+ # the configured password strategy. By default, this will be
69
+ # {PasswordStrategies::BCrypt#authenticated?}, but can be changed with
70
+ # {Configuration#password_strategy}.
71
+ #
72
+ # @see PasswordStrategies
73
+ # @param [String] password
74
+ # The password to check.
75
+ # @return [Boolean]
76
+ # True if the password provided is correct for the user.
77
+ #
78
+ # @!method self.authenticate
79
+ # Finds the user with the given email and authenticates them with the
80
+ # provided password. If the email corresponds to a user and the provided
81
+ # password is correct for that user, this method will return that user.
82
+ # Otherwise it will return nil.
83
+ #
84
+ # @return [User, nil]
85
+ #
86
+ # @!method self.find_by_normalized_email
87
+ # Finds the user with the given email. The email with be normalized via
88
+ # {#normalize_email}.
89
+ #
90
+ # @return [User, nil]
91
+ #
92
+ # @!method self.normalize_email
93
+ # Normalizes the provided email by downcasing and removing all spaces.
94
+ # This is used by {find_by_normalized_email} and is also called when
95
+ # validating a user to ensure only normalized emails are stored in the
96
+ # database.
97
+ #
98
+ # @return [String]
99
+ #
6
100
  module User
7
101
  extend ActiveSupport::Concern
8
102
 
9
103
  included do
10
- attr_accessor :password_changing
11
104
  attr_reader :password
12
105
 
13
106
  include Validations
14
107
  include Callbacks
15
108
  include password_strategy
109
+
110
+ def password=(value)
111
+ encrypted_password_will_change!
112
+ super
113
+ end
114
+
115
+ def password_changing
116
+ warn "#{Kernel.caller.first}: [DEPRECATION] " \
117
+ "The `password_changing` attribute is deprecated. Clearance uses " \
118
+ "the dirty state of the `encrypted_password` field to track this " \
119
+ "automatically."
120
+
121
+ @password_changing
122
+ end
123
+
124
+ def password_changing=(value)
125
+ warn "#{Kernel.caller.first}: [DEPRECATION] " \
126
+ "The `password_changing` attribute is deprecated. Clearance uses " \
127
+ "the dirty state of the `encrypted_password` field to track this " \
128
+ "automatically."
129
+
130
+ @password_changing = value
131
+ end
16
132
  end
17
133
 
134
+ # @api private
18
135
  module ClassMethods
19
136
  def authenticate(email, password)
20
137
  if user = find_by_normalized_email(email)
21
138
  if password.present? && user.authenticated?(password)
22
- return user
139
+ user
23
140
  end
24
141
  end
25
142
  end
@@ -39,6 +156,7 @@ module Clearance
39
156
  end
40
157
  end
41
158
 
159
+ # @api private
42
160
  module Validations
43
161
  extend ActiveSupport::Concern
44
162
 
@@ -53,6 +171,7 @@ module Clearance
53
171
  end
54
172
  end
55
173
 
174
+ # @api private
56
175
  module Callbacks
57
176
  extend ActiveSupport::Concern
58
177
 
@@ -62,18 +181,48 @@ module Clearance
62
181
  end
63
182
  end
64
183
 
184
+ # Generates a {#confirmation_token} for the user, which allows them to reset
185
+ # their password via an email link.
186
+ #
187
+ # Calling `forgot_password!` will cause the user model to be saved without
188
+ # validations. Any other changes you made to this user instance will also
189
+ # be persisted, without validation. It is inteded to be called on an
190
+ # instance with no changes (`dirty? == false`).
191
+ #
192
+ # @return [Boolean] Was the save successful?
65
193
  def forgot_password!
66
194
  generate_confirmation_token
67
195
  save validate: false
68
196
  end
69
197
 
198
+ # Generates a new {#remember_token} for the user, which will have the effect
199
+ # of signing all of the user's current sessions out. This is called
200
+ # internally by {Session#sign_out}.
201
+ #
202
+ # Calling `reset_remember_token!` will cause the user model to be saved
203
+ # without validations. Any other changes you made to this user instance will
204
+ # also be persisted, without validation. It is inteded to be called on an
205
+ # instance with no changes (`dirty? == false`).
206
+ #
207
+ # @return [Boolean] Was the save successful?
70
208
  def reset_remember_token!
71
209
  generate_remember_token
72
210
  save validate: false
73
211
  end
74
212
 
213
+ # Sets the user's password to the new value, using the `password=` method on
214
+ # the configured password strategy. By default, this is
215
+ # {PasswordStrategies::BCrypt#password=}.
216
+ #
217
+ # This also has the side-effect of blanking the {#confirmation_token} and
218
+ # rotating the `#remember_token`.
219
+ #
220
+ # Validations will be run as part of this update. If the user instance is
221
+ # not valid, the password change will not be persisted, and this method will
222
+ # return `false`.
223
+ #
224
+ # @return [Boolean] Was the save successful?
75
225
  def update_password(new_password)
76
- self.password_changing = true
77
226
  self.password = new_password
78
227
 
79
228
  if valid?
@@ -86,28 +235,58 @@ module Clearance
86
235
 
87
236
  private
88
237
 
238
+ # Sets the email on this instance to the value returned by
239
+ # {.normalize_email}
240
+ #
241
+ # @return [String]
89
242
  def normalize_email
90
243
  self.email = self.class.normalize_email(email)
91
244
  end
92
245
 
246
+ # Always false. Override this method in your user model to allow for other
247
+ # forms of user authentication (username, Facebook, etc).
248
+ #
249
+ # @return [false]
93
250
  def email_optional?
94
251
  false
95
252
  end
96
253
 
254
+ # Always false. Override this method in your user model to allow for other
255
+ # forms of user authentication (username, Facebook, etc).
256
+ #
257
+ # @return [false]
97
258
  def password_optional?
98
259
  false
99
260
  end
100
261
 
262
+ # True if {#password_optional?} is true or if the user already has an
263
+ # {#encrypted_password} that is not changing.
264
+ #
265
+ # @return [Boolean]
101
266
  def skip_password_validation?
102
- password_optional? || (encrypted_password.present? && !password_changing)
267
+ password_optional? ||
268
+ (encrypted_password.present? && !encrypted_password_changed?)
103
269
  end
104
270
 
271
+ # Sets the {#confirmation_token} on the instance to a new value generated by
272
+ # {Token.new}. The change is not automatically persisted. If you would like
273
+ # to generate and save in a single method call, use {#forgot_password!}.
274
+ #
275
+ # @return [String] The new confirmation token
105
276
  def generate_confirmation_token
106
277
  self.confirmation_token = Clearance::Token.new
107
278
  end
108
279
 
280
+ # Sets the {#remember_token} on the instance to a new value generated by
281
+ # {Token.new}. The change is not automatically persisted. If you would like
282
+ # to generate and save in a single method call, use
283
+ # {#reset_remember_token!}.
284
+ #
285
+ # @return [String] The new remember token
109
286
  def generate_remember_token
110
287
  self.remember_token = Clearance::Token.new
111
288
  end
289
+
290
+ private_constant :Callbacks, :ClassMethods, :Validations
112
291
  end
113
292
  end
@@ -1,3 +1,3 @@
1
1
  module Clearance
2
- VERSION = "1.10.1"
2
+ VERSION = "1.17.0".freeze
3
3
  end
@@ -23,11 +23,12 @@ module Clearance
23
23
  if File.exist? "app/models/user.rb"
24
24
  inject_into_file(
25
25
  "app/models/user.rb",
26
- "include Clearance::User\n\n",
27
- after: "class User < ActiveRecord::Base\n"
26
+ " include Clearance::User\n\n",
27
+ after: "class User < #{models_inherit_from}\n",
28
28
  )
29
29
  else
30
- copy_file 'user.rb', 'app/models/user.rb'
30
+ @inherit_from = models_inherit_from
31
+ template("user.rb.erb", "app/models/user.rb")
31
32
  end
32
33
  end
33
34
 
@@ -35,7 +36,7 @@ module Clearance
35
36
  if users_table_exists?
36
37
  create_add_columns_migration
37
38
  else
38
- copy_migration 'create_users.rb'
39
+ copy_migration "create_users"
39
40
  end
40
41
  end
41
42
 
@@ -52,16 +53,16 @@ module Clearance
52
53
  new_indexes: new_indexes
53
54
  }
54
55
 
55
- copy_migration('add_clearance_to_users.rb', config)
56
+ copy_migration("add_clearance_to_users", config)
56
57
  end
57
58
  end
58
59
 
59
60
  def copy_migration(migration_name, config = {})
60
61
  unless migration_exists?(migration_name)
61
62
  migration_template(
62
- "db/migrate/#{migration_name}",
63
- "db/migrate/#{migration_name}",
64
- config
63
+ "db/migrate/#{migration_name}.rb.erb",
64
+ "db/migrate/#{migration_name}.rb",
65
+ config.merge(migration_version: migration_version),
65
66
  )
66
67
  end
67
68
  end
@@ -101,7 +102,11 @@ module Clearance
101
102
  end
102
103
 
103
104
  def users_table_exists?
104
- ActiveRecord::Base.connection.table_exists?(:users)
105
+ if ActiveRecord::Base.connection.respond_to?(:data_source_exists?)
106
+ ActiveRecord::Base.connection.data_source_exists?(:users)
107
+ else
108
+ ActiveRecord::Base.connection.table_exists?(:users)
109
+ end
105
110
  end
106
111
 
107
112
  def existing_users_columns
@@ -116,6 +121,20 @@ module Clearance
116
121
  def self.next_migration_number(dir)
117
122
  ActiveRecord::Generators::Base.next_migration_number(dir)
118
123
  end
124
+
125
+ def migration_version
126
+ if Rails.version >= "5.0.0"
127
+ "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
128
+ end
129
+ end
130
+
131
+ def models_inherit_from
132
+ if Rails.version >= "5.0.0"
133
+ "ApplicationRecord"
134
+ else
135
+ "ActiveRecord::Base"
136
+ end
137
+ end
119
138
  end
120
139
  end
121
140
  end
@@ -27,6 +27,6 @@ Next steps:
27
27
 
28
28
  3. Migrate:
29
29
 
30
- rake db:migrate
30
+ rails db:migrate
31
31
 
32
32
  *******************************************************************************
@@ -1,3 +1,4 @@
1
1
  Clearance.configure do |config|
2
2
  config.mailer_sender = "reply@example.com"
3
+ config.rotate_csrf_on_sign_in = true
3
4
  end
@@ -1,6 +1,6 @@
1
- class AddClearanceToUsers < ActiveRecord::Migration
1
+ class AddClearanceToUsers < ActiveRecord::Migration<%= migration_version %>
2
2
  def self.up
3
- change_table :users do |t|
3
+ change_table :users do |t|
4
4
  <% config[:new_columns].values.each do |column| -%>
5
5
  <%= column %>
6
6
  <% end -%>
@@ -24,7 +24,7 @@ class AddClearanceToUsers < ActiveRecord::Migration
24
24
  def self.down
25
25
  change_table :users do |t|
26
26
  <% if config[:new_columns].any? -%>
27
- t.remove <%= new_columns.keys.map { |column| ":#{column}" }.join(",") %>
27
+ t.remove <%= new_columns.keys.map { |column| ":#{column}" }.join(", ") %>
28
28
  <% end -%>
29
29
  end
30
30
  end
@@ -1,6 +1,6 @@
1
- class CreateUsers < ActiveRecord::Migration
1
+ class CreateUsers < ActiveRecord::Migration<%= migration_version %>
2
2
  def change
3
- create_table :users do |t|
3
+ create_table :users do |t|
4
4
  t.timestamps null: false
5
5
  t.string :email, null: false
6
6
  t.string :encrypted_password, limit: 128, null: false
@@ -0,0 +1,3 @@
1
+ class User < <%= @inherit_from %>
2
+ include Clearance::User
3
+ end
@@ -9,6 +9,14 @@ module Clearance
9
9
  route(clearance_routes)
10
10
  end
11
11
 
12
+ def disable_clearance_internal_routes
13
+ inject_into_file(
14
+ "config/initializers/clearance.rb",
15
+ " config.routes = false\n",
16
+ after: "Clearance.configure do |config|\n",
17
+ )
18
+ end
19
+
12
20
  private
13
21
 
14
22
  def clearance_routes
@@ -18,6 +26,21 @@ module Clearance
18
26
  def routes_file_path
19
27
  File.expand_path(find_in_source_paths('routes.rb'))
20
28
  end
29
+
30
+ def route(routing_code)
31
+ log :route, "all clearance routes"
32
+ sentinel = /\.routes\.draw do\s*\n/m
33
+
34
+ in_root do
35
+ inject_into_file(
36
+ "config/routes.rb",
37
+ routing_code,
38
+ after: sentinel,
39
+ verbose: false,
40
+ force: true,
41
+ )
42
+ end
43
+ end
21
44
  end
22
45
  end
23
46
  end
@@ -1,12 +1,12 @@
1
- resources :passwords, controller: 'clearance/passwords', only: [:create, :new]
2
- resource :session, controller: 'clearance/sessions', only: [:create]
1
+ resources :passwords, controller: "clearance/passwords", only: [:create, :new]
2
+ resource :session, controller: "clearance/sessions", only: [:create]
3
3
 
4
- resources :users, controller: 'clearance/users', only: [:create] do
4
+ resources :users, controller: "clearance/users", only: [:create] do
5
5
  resource :password,
6
- controller: 'clearance/passwords',
6
+ controller: "clearance/passwords",
7
7
  only: [:create, :edit, :update]
8
8
  end
9
9
 
10
- get '/sign_in' => 'clearance/sessions#new', as: 'sign_in'
11
- delete '/sign_out' => 'clearance/sessions#destroy', as: 'sign_out'
12
- get '/sign_up' => 'clearance/users#new', as: 'sign_up'
10
+ get "/sign_in" => "clearance/sessions#new", as: "sign_in"
11
+ delete "/sign_out" => "clearance/sessions#destroy", as: "sign_out"
12
+ get "/sign_up" => "clearance/users#new", as: "sign_up"
@@ -1,10 +1,10 @@
1
- FactoryGirl.define do
1
+ FactoryBot.define do
2
2
  sequence :email do |n|
3
3
  "user#{n}@example.com"
4
4
  end
5
5
 
6
6
  factory :user do
7
7
  email
8
- password "password"
8
+ password { "password" }
9
9
  end
10
10
  end
@@ -1,7 +1,7 @@
1
1
  require "<%= @helper_file %>"
2
2
  require "support/features/clearance_helpers"
3
3
 
4
- feature "User signs out" do
4
+ RSpec.feature "User signs out" do
5
5
  scenario "signs out" do
6
6
  sign_in
7
7
  sign_out
@@ -1,8 +1,17 @@
1
1
  require "<%= @helper_file %>"
2
2
  require "support/features/clearance_helpers"
3
3
 
4
- feature "Visitor resets password" do
4
+ RSpec.feature "Visitor resets password" do
5
5
  before { ActionMailer::Base.deliveries.clear }
6
+ <% if defined?(ActiveJob) -%>
7
+
8
+ around do |example|
9
+ original_adapter = ActiveJob::Base.queue_adapter
10
+ ActiveJob::Base.queue_adapter = :inline
11
+ example.run
12
+ ActiveJob::Base.queue_adapter = original_adapter
13
+ end
14
+ <% end -%>
6
15
 
7
16
  scenario "by navigating to the page" do
8
17
  visit sign_in_path
@@ -33,7 +42,7 @@ feature "Visitor resets password" do
33
42
  expect_mailer_to_have_delivery(
34
43
  user.email,
35
44
  "password",
36
- user.confirmation_token
45
+ user.confirmation_token,
37
46
  )
38
47
  end
39
48
 
@@ -47,7 +56,7 @@ feature "Visitor resets password" do
47
56
  message = ActionMailer::Base.deliveries.any? do |email|
48
57
  email.to == [recipient] &&
49
58
  email.subject =~ /#{subject}/i &&
50
- email.html_part.body =~ /#{body}/
59
+ email.html_part.body =~ /#{body}/ &&
51
60
  email.text_part.body =~ /#{body}/
52
61
  end
53
62
 
@@ -1,7 +1,7 @@
1
1
  require "<%= @helper_file %>"
2
2
  require "support/features/clearance_helpers"
3
3
 
4
- feature "Visitor signs in" do
4
+ RSpec.feature "Visitor signs in" do
5
5
  scenario "with valid email and password" do
6
6
  create_user "user@example.com", "password"
7
7
  sign_in_with "user@example.com", "password"
@@ -34,12 +34,12 @@ feature "Visitor signs in" do
34
34
  private
35
35
 
36
36
  def create_user(email, password)
37
- FactoryGirl.create(:user, email: email, password: password)
37
+ FactoryBot.create(:user, email: email, password: password)
38
38
  end
39
39
 
40
40
  def expect_page_to_display_sign_in_error
41
41
  expect(page.body).to include(
42
- I18n.t("flashes.failure_after_create", sign_up_path: sign_up_path)
42
+ I18n.t("flashes.failure_after_create", sign_up_path: sign_up_path),
43
43
  )
44
44
  end
45
45
  end
@@ -1,7 +1,7 @@
1
1
  require "<%= @helper_file %>"
2
2
  require "support/features/clearance_helpers"
3
3
 
4
- feature "Visitor signs up" do
4
+ RSpec.feature "Visitor signs up" do
5
5
  scenario "by navigating to the page" do
6
6
  visit sign_in_path
7
7
 
@@ -1,7 +1,7 @@
1
1
  require "<%= @helper_file %>"
2
2
  require "support/features/clearance_helpers"
3
3
 
4
- feature "Visitor updates password" do
4
+ RSpec.feature "Visitor updates password" do
5
5
  scenario "with valid password" do
6
6
  user = user_with_reset_password
7
7
  update_password user, "newpassword"
@@ -37,7 +37,7 @@ feature "Visitor updates password" do
37
37
  def visit_password_reset_page_for(user)
38
38
  visit edit_user_password_path(
39
39
  user_id: user,
40
- token: user.confirmation_token
40
+ token: user.confirmation_token,
41
41
  )
42
42
  end
43
43
 
@@ -8,7 +8,7 @@ module Features
8
8
 
9
9
  def sign_in
10
10
  password = "password"
11
- user = FactoryGirl.create(:user, password: password)
11
+ user = FactoryBot.create(:user, password: password)
12
12
  sign_in_with user.email, password
13
13
  end
14
14
 
@@ -40,7 +40,7 @@ module Features
40
40
  end
41
41
 
42
42
  def user_with_reset_password
43
- user = FactoryGirl.create(:user)
43
+ user = FactoryBot.create(:user)
44
44
  reset_password_for user.email
45
45
  user.reload
46
46
  end