mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Correctly handle multiple attribute method prefix/suffixes which match
Active Record defines `attribute_method_suffix :?`. That suffix will match any predicate method when the lookup occurs in Active Model. This will make it incorrectly decide that `id_changed?` should not exist, because it attempts to determine if the attribute `id_changed` is present, rather than `id` with the `_changed?` suffix. Instead, we will look for any correct match.
This commit is contained in:
parent
08ff4ccbbb
commit
d1f003e67b
2 changed files with 14 additions and 6 deletions
|
@ -353,14 +353,12 @@ module ActiveModel
|
||||||
@attribute_method_matchers_cache ||= ThreadSafe::Cache.new(initial_capacity: 4)
|
@attribute_method_matchers_cache ||= ThreadSafe::Cache.new(initial_capacity: 4)
|
||||||
end
|
end
|
||||||
|
|
||||||
def attribute_method_matcher(method_name) #:nodoc:
|
def attribute_method_matchers_matching(method_name) #:nodoc:
|
||||||
attribute_method_matchers_cache.compute_if_absent(method_name) do
|
attribute_method_matchers_cache.compute_if_absent(method_name) do
|
||||||
# Must try to match prefixes/suffixes first, or else the matcher with no prefix/suffix
|
# Must try to match prefixes/suffixes first, or else the matcher with no prefix/suffix
|
||||||
# will match every time.
|
# will match every time.
|
||||||
matchers = attribute_method_matchers.partition(&:plain?).reverse.flatten(1)
|
matchers = attribute_method_matchers.partition(&:plain?).reverse.flatten(1)
|
||||||
match = nil
|
matchers.map { |method| method.match(method_name) }.compact
|
||||||
matchers.detect { |method| match = method.match(method_name) }
|
|
||||||
match
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -469,8 +467,8 @@ module ActiveModel
|
||||||
# Returns a struct representing the matching attribute method.
|
# Returns a struct representing the matching attribute method.
|
||||||
# The struct's attributes are prefix, base and suffix.
|
# The struct's attributes are prefix, base and suffix.
|
||||||
def match_attribute_method?(method_name)
|
def match_attribute_method?(method_name)
|
||||||
match = self.class.send(:attribute_method_matcher, method_name)
|
matches = self.class.send(:attribute_method_matchers_matching, method_name)
|
||||||
match if match && attribute_method?(match.attr_name)
|
matches.detect { |match| attribute_method?(match.attr_name) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def missing_attribute(attr_name, stack)
|
def missing_attribute(attr_name, stack)
|
||||||
|
|
|
@ -1527,4 +1527,14 @@ class BasicsTest < ActiveRecord::TestCase
|
||||||
test "records without an id have unique hashes" do
|
test "records without an id have unique hashes" do
|
||||||
assert_not_equal Post.new.hash, Post.new.hash
|
assert_not_equal Post.new.hash, Post.new.hash
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "resetting column information doesn't remove attribute methods" do
|
||||||
|
topic = topics(:first)
|
||||||
|
|
||||||
|
assert_not topic.id_changed?
|
||||||
|
|
||||||
|
Topic.reset_column_information
|
||||||
|
|
||||||
|
assert_not topic.id_changed?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue