Skip to content

Commit 2df70dd

Browse files
committed
Generate secure token only once regardless of on: :initialize or on: :create
Follow-up to rails#47420. Whereas the original behavior (`on: :create`) is invoked only once before a record is persisted, the new behavior (`on: :initialize`) is invoked not only new record but also persisted records. It should be invoked only once for new record consistently.
1 parent 2fbb25b commit 2df70dd

File tree

2 files changed

+19
-1
lines changed

2 files changed

+19
-1
lines changed

activerecord/lib/active_record/secure_token.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ def has_secure_token(attribute = :token, length: MINIMUM_TOKEN_LENGTH, on: Activ
5252
require "active_support/core_ext/securerandom"
5353
define_method("regenerate_#{attribute}") { update! attribute => self.class.generate_unique_secure_token(length: length) }
5454
set_callback on, on == :initialize ? :after : :before do
55-
send("#{attribute}=", self.class.generate_unique_secure_token(length: length)) if has_attribute?(attribute) && !send("#{attribute}?")
55+
if new_record? && !query_attribute(attribute)
56+
write_attribute(attribute, self.class.generate_unique_secure_token(length: length))
57+
end
5658
end
5759
end
5860

activerecord/test/cases/secure_token_test.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,22 @@ def test_generating_token_on_initialize_does_not_affect_reading_from_the_column
2525
assert_equal token, User.find(@user.id).token
2626
end
2727

28+
def test_generating_token_on_initialize_happens_only_once
29+
model = Class.new(ActiveRecord::Base) do
30+
self.table_name = "users"
31+
has_secure_token on: :initialize
32+
end
33+
34+
token = " "
35+
36+
user = model.new
37+
user.update!(token: token)
38+
39+
assert_equal token, user.token
40+
assert_equal token, user.reload.token
41+
assert_equal token, model.find(user.id).token
42+
end
43+
2844
def test_generating_token_on_initialize_is_skipped_if_column_was_not_selected
2945
model = Class.new(ActiveRecord::Base) do
3046
self.table_name = "users"

0 commit comments

Comments
 (0)