Merge pull request #43779 from jonathanhefner/authenticate_by-call-attributes-to_h

Convert attributes to Hash in authenticate_by
This commit is contained in:
Rafael Mendonça França 2021-12-06 12:30:38 -05:00 committed by GitHub
commit d301b3b02b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 18 additions and 6 deletions

View File

@ -1,7 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "active_support/core_ext/hash/except"
module ActiveRecord module ActiveRecord
module SecurePassword module SecurePassword
extend ActiveSupport::Concern extend ActiveSupport::Concern
@ -37,15 +35,17 @@ module ActiveRecord
# User.authenticate_by(email: "jdoe@example.com") # => ArgumentError # User.authenticate_by(email: "jdoe@example.com") # => ArgumentError
# User.authenticate_by(password: "abc123") # => ArgumentError # User.authenticate_by(password: "abc123") # => ArgumentError
def authenticate_by(attributes) def authenticate_by(attributes)
passwords = attributes.select { |name, value| !has_attribute?(name) && has_attribute?("#{name}_digest") } passwords, identifiers = attributes.to_h.partition do |name, value|
!has_attribute?(name) && has_attribute?("#{name}_digest")
end.map(&:to_h)
raise ArgumentError, "One or more password arguments are required" if passwords.empty? raise ArgumentError, "One or more password arguments are required" if passwords.empty?
raise ArgumentError, "One or more finder arguments are required" if passwords.size == attributes.size raise ArgumentError, "One or more finder arguments are required" if identifiers.empty?
if record = find_by(attributes.except(*passwords.keys)) if record = find_by(identifiers)
record if passwords.count { |name, value| record.public_send(:"authenticate_#{name}", value) } == passwords.size record if passwords.count { |name, value| record.public_send(:"authenticate_#{name}", value) } == passwords.size
else else
self.new(passwords) new(passwords)
nil nil
end end
end end

View File

@ -64,4 +64,16 @@ class SecurePasswordTest < ActiveRecord::TestCase
User.authenticate_by(password: @user.password) User.authenticate_by(password: @user.password)
end end
end end
test "authenticate_by accepts any object that implements to_h" do
params = Enumerator.new { raise "must access via to_h" }
assert_called_with(params, :to_h, [[]], returns: { token: @user.token, password: @user.password }) do
assert_equal @user, User.authenticate_by(params)
end
assert_called_with(params, :to_h, [[]], returns: { token: "wrong", password: @user.password }) do
assert_nil User.authenticate_by(params)
end
end
end end