aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel
diff options
context:
space:
mode:
authorSeb Jacobs <me@sebjacobs.com>2019-03-22 08:20:36 +0000
committerSeb Jacobs <me@sebjacobs.com>2019-03-22 08:28:13 +0000
commit4733e04dfaaa39b22292eef168bc5c1d1638c9b2 (patch)
treefd523644b0d00731ebd3cf8696f8404cac7caf62 /activemodel
parent0a0f115031b64b5335fa88543c40df4194dfb428 (diff)
downloadrails-4733e04dfaaa39b22292eef168bc5c1d1638c9b2.tar.gz
rails-4733e04dfaaa39b22292eef168bc5c1d1638c9b2.tar.bz2
rails-4733e04dfaaa39b22292eef168bc5c1d1638c9b2.zip
Reintroduce support for overriding `has_secure_password` attributes
In Rails 5.2.x calling `has_secure_password` would define attribute readers and writers on the superclass of the model, which meant that you could override these attributes in a model and call the superclass for example: ``` class Dog < ApplicationRecord has_secure_password def password=(new_password) @password_set = new_password.present? super end end ``` However this behaviour was broken in Rails 6 when the ability to customise the name of the attribute was introduced [1] since they are no longer being defined on the superclass you will now see the following error: ``` NoMethodError: super: no superclass method `password=' for #<Dog:0x00007ffbbc7ce290> Did you mean? password ``` In order to resolve this issue and retain support for setting a custom attribute name we can define these attribute readers/writers in a module and then ensure that the module is included in the inheritance chain. [1] https://www.github.com/rails/rails/commit/86a48b4da3 https://www.github.com/rails/rails/commit/9b63bf1dfd
Diffstat (limited to 'activemodel')
-rw-r--r--activemodel/lib/active_model/secure_password.rb56
1 files changed, 30 insertions, 26 deletions
diff --git a/activemodel/lib/active_model/secure_password.rb b/activemodel/lib/active_model/secure_password.rb
index 51d54f34f3..cc1368d3a0 100644
--- a/activemodel/lib/active_model/secure_password.rb
+++ b/activemodel/lib/active_model/secure_password.rb
@@ -69,38 +69,42 @@ module ActiveModel
raise
end
- attr_reader attribute
+ mod = Module.new do
+ attr_reader attribute
- define_method("#{attribute}=") do |unencrypted_password|
- if unencrypted_password.nil?
- self.send("#{attribute}_digest=", nil)
- elsif !unencrypted_password.empty?
- instance_variable_set("@#{attribute}", unencrypted_password)
- cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
- self.send("#{attribute}_digest=", BCrypt::Password.create(unencrypted_password, cost: cost))
+ define_method("#{attribute}=") do |unencrypted_password|
+ if unencrypted_password.nil?
+ self.send("#{attribute}_digest=", nil)
+ elsif !unencrypted_password.empty?
+ instance_variable_set("@#{attribute}", unencrypted_password)
+ cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
+ self.send("#{attribute}_digest=", BCrypt::Password.create(unencrypted_password, cost: cost))
+ end
end
- end
- define_method("#{attribute}_confirmation=") do |unencrypted_password|
- instance_variable_set("@#{attribute}_confirmation", unencrypted_password)
- end
+ define_method("#{attribute}_confirmation=") do |unencrypted_password|
+ instance_variable_set("@#{attribute}_confirmation", unencrypted_password)
+ end
+
+ # Returns +self+ if the password is correct, otherwise +false+.
+ #
+ # class User < ActiveRecord::Base
+ # has_secure_password validations: false
+ # end
+ #
+ # user = User.new(name: 'david', password: 'mUc3m00RsqyRe')
+ # user.save
+ # user.authenticate_password('notright') # => false
+ # user.authenticate_password('mUc3m00RsqyRe') # => user
+ define_method("authenticate_#{attribute}") do |unencrypted_password|
+ attribute_digest = send("#{attribute}_digest")
+ BCrypt::Password.new(attribute_digest).is_password?(unencrypted_password) && self
+ end
- # Returns +self+ if the password is correct, otherwise +false+.
- #
- # class User < ActiveRecord::Base
- # has_secure_password validations: false
- # end
- #
- # user = User.new(name: 'david', password: 'mUc3m00RsqyRe')
- # user.save
- # user.authenticate_password('notright') # => false
- # user.authenticate_password('mUc3m00RsqyRe') # => user
- define_method("authenticate_#{attribute}") do |unencrypted_password|
- attribute_digest = send("#{attribute}_digest")
- BCrypt::Password.new(attribute_digest).is_password?(unencrypted_password) && self
+ alias_method :authenticate, :authenticate_password if attribute == :password
end
- alias_method :authenticate, :authenticate_password if attribute == :password
+ include mod
if validations
include ActiveModel::Validations