Skip to content

Commit a21c40b

Browse files
authored
Merge pull request rails#48912 from seanpdoyle/has-secure-token-default-on-initialize
Change `has_secure_token` default to `on: :initialize`
2 parents 3bc6401 + e85a3ec commit a21c40b

File tree

8 files changed

+78
-3
lines changed

8 files changed

+78
-3
lines changed

activerecord/CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
* Change `has_secure_token` default to `on: :initialize`
2+
3+
Change the new default value from `on: :create` to `on: :initialize`
4+
5+
Can be controlled by the `config.active_record.generate_secure_token_on`
6+
configuration:
7+
8+
```ruby
9+
config.active_record.generate_secure_token_on = :create
10+
```
11+
12+
*Sean Doyle*
13+
114
* Fix `change_column` not setting `precision: 6` on `datetime` columns when
215
using 7.0+ Migrations and SQLite.
316

activerecord/lib/active_record.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,13 @@ def self.suppress_multiple_database_warning=(value)
447447
singleton_class.attr_accessor :yaml_column_permitted_classes
448448
self.yaml_column_permitted_classes = [Symbol]
449449

450+
##
451+
# :singleton-method:
452+
# Controls when to generate a value for <tt>has_secure_token</tt>
453+
# declarations. Defaults to <tt>:create</tt>.
454+
singleton_class.attr_accessor :generate_secure_token_on
455+
self.generate_secure_token_on = :create
456+
450457
def self.marshalling_format_version
451458
Marshalling.format_version
452459
end

activerecord/lib/active_record/railtie.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class Railtie < Rails::Railtie # :nodoc:
3838
config.active_record.cache_query_log_tags = false
3939
config.active_record.raise_on_assign_to_attr_readonly = false
4040
config.active_record.belongs_to_required_validates_foreign_key = true
41+
config.active_record.generate_secure_token_on = :create
4142

4243
config.active_record.queues = ActiveSupport::InheritableOptions.new
4344

activerecord/lib/active_record/secure_token.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,10 @@ module ClassMethods
4040
# The callback when the value is generated. When called with <tt>on:
4141
# :initialize</tt>, the value is generated in an
4242
# <tt>after_initialize</tt> callback, otherwise the value will be used
43-
# in a <tt>before_</tt> callback. It will default to <tt>:create</tt>.
44-
#
45-
def has_secure_token(attribute = :token, length: MINIMUM_TOKEN_LENGTH, on: :create)
43+
# in a <tt>before_</tt> callback. When not specified, +:on+ will use the value of
44+
# <tt>config.active_record.generate_secure_token_on</tt>, which defaults to +:initialize+
45+
# starting in \Rails 7.1.
46+
def has_secure_token(attribute = :token, length: MINIMUM_TOKEN_LENGTH, on: ActiveRecord.generate_secure_token_on)
4647
if length < MINIMUM_TOKEN_LENGTH
4748
raise MinimumLengthError, "Token requires a minimum length of #{MINIMUM_TOKEN_LENGTH} characters."
4849
end

activerecord/test/cases/secure_token_test.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ def test_token_values_are_generated_for_specified_attributes_and_persisted_on_sa
1616
assert_equal 36, @user.auth_token.size
1717
end
1818

19+
def test_generating_token_on_initialize_does_not_affect_reading_from_the_column
20+
token = "abc123"
21+
22+
@user.update! token: token
23+
24+
assert_equal token, @user.reload.token
25+
assert_equal token, User.find(@user.id).token
26+
end
27+
1928
def test_regenerating_the_secure_token
2029
@user.save
2130
old_token = @user.token

guides/source/configuring.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ Below are the default values associated with each target version. In cases of co
7373
- [`config.active_record.default_column_serializer`](#config-active-record-default-column-serializer): `nil`
7474
- [`config.active_record.encryption.hash_digest_class`](#config-active-record-encryption-hash-digest-class): `OpenSSL::Digest::SHA256`
7575
- [`config.active_record.encryption.support_sha1_for_non_deterministic_encryption`](#config-active-record-encryption-support-sha1-for-non-deterministic-encryption): `false`
76+
- [`config.active_record.generate_secure_token_on`](#config-active-record-generate-secure-token-on): `:initialize`
7677
- [`config.active_record.marshalling_format_version`](#config-active-record-marshalling-format-version): `7.1`
7778
- [`config.active_record.query_log_tags_format`](#config-active-record-query-log-tags-format): `:sqlcommenter`
7879
- [`config.active_record.raise_on_assign_to_attr_readonly`](#config-active-record-raise-on-assign-to-attr-readonly): `true`
@@ -1513,6 +1514,44 @@ Defaults to `true`. Determines whether to raise an exception or not when
15131514
the PostgreSQL adapter is provided an integer that is wider than signed
15141515
64bit representation.
15151516

1517+
#### `config.active_record.generate_secure_token_on`
1518+
1519+
Controls when to generate a value for `has_secure_token` declarations. By
1520+
default, generate the value when the model is initialized:
1521+
1522+
```ruby
1523+
class User < ApplicationRecord
1524+
has_secure_token
1525+
end
1526+
1527+
record = User.new
1528+
record.token # => "fwZcXX6SkJBJRogzMdciS7wf"
1529+
```
1530+
1531+
With `config.active_record.generate_secure_token_on = :create`, generate the
1532+
value when the model is created:
1533+
1534+
```ruby
1535+
# config/application.rb
1536+
1537+
config.active_record.generate_secure_token_on = :create
1538+
1539+
# app/models/user.rb
1540+
class User < ApplicationRecord
1541+
has_secure_token on: :create
1542+
end
1543+
1544+
record = User.new
1545+
record.token # => nil
1546+
record.save!
1547+
record.token # => "fwZcXX6SkJBJRogzMdciS7wf"
1548+
```
1549+
1550+
| Starting with version | The default value is |
1551+
| --------------------- | -------------------- |
1552+
| (original) | `:create` |
1553+
| 7.1 | `:initialize` |
1554+
15161555
#### `ActiveRecord::ConnectionAdapters::Mysql2Adapter.emulate_booleans` and `ActiveRecord::ConnectionAdapters::TrilogyAdapter.emulate_booleans`
15171556

15181557
Controls whether the Active Record MySQL adapter will consider all `tinyint(1)` columns as booleans. Defaults to `true`.

railties/lib/rails/application/configuration.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ def load_defaults(target_version)
291291
active_record.encryption.support_sha1_for_non_deterministic_encryption = false
292292
active_record.marshalling_format_version = 7.1
293293
active_record.run_after_transaction_callbacks_in_order_defined = true
294+
active_record.generate_secure_token_on = :initialize
294295
end
295296

296297
if respond_to?(:action_dispatch)

railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_1.rb.tt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,10 @@
174174
#
175175
# Rails.application.config.active_record.commit_transaction_on_non_local_return = true
176176

177+
# Controls when to generate a value for <tt>has_secure_token</tt> declarations.
178+
#
179+
# Rails.application.config.active_record.generate_secure_token_on = :initialize
180+
177181
# ** Please read carefully, this must be configured in config/application.rb **
178182
# Change the format of the cache entry.
179183
# Changing this default means that all new cache entries added to the cache

0 commit comments

Comments
 (0)