Skip to content

Commit

Permalink
If an attribute alias reaches method missing, send the original
Browse files Browse the repository at this point in the history
  • Loading branch information
justinko committed May 4, 2024
1 parent d65fec4 commit 78b6d93
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 5 deletions.
6 changes: 5 additions & 1 deletion activemodel/lib/active_model/attribute_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,10 @@ def method_missing(method, ...)
if respond_to_without_attributes?(method, true)
super
else
# If the missing method is an attribute alias, let's dispatch the original.
if self.class.attribute_alias?(method) && self.class.send(:instance_method_already_implemented?, method)
method = self.class.attribute_alias(method).to_sym
end
match = matched_attribute_method(method.name)
match ? attribute_missing(match, ...) : super
end
Expand All @@ -505,7 +509,7 @@ def respond_to?(method, include_private_methods = false)
# but found among all methods. Which means that the given method is private.
false
else
!matched_attribute_method(method.to_s).nil?
self.class.send(:instance_method_already_implemented?, method) || !matched_attribute_method(method.to_s).nil?
end
end

Expand Down
31 changes: 27 additions & 4 deletions activemodel/test/cases/attribute_methods_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ def attributes
def attribute(name)
attributes[name.to_sym]
end

def attribute_method?(name)
attributes.include?(name.to_sym)
end
end

class ModelWithAttributes2
Expand Down Expand Up @@ -236,11 +240,11 @@ def foo
end

test "#undefine_attribute_methods removes attribute methods" do
ModelWithAttributes.define_attribute_methods(:foo)
ModelWithAttributes.undefine_attribute_methods
ModelWithoutAttributesMethod.define_attribute_methods(:foo)
assert_respond_to ModelWithoutAttributesMethod.new, :foo

assert_not_respond_to ModelWithAttributes.new, :foo
assert_raises(NoMethodError) { ModelWithAttributes.new.foo }
ModelWithoutAttributesMethod.undefine_attribute_methods
assert_not_respond_to ModelWithoutAttributesMethod.new, :foo
end

test "#undefine_attribute_methods undefines alias attribute methods" do
Expand Down Expand Up @@ -341,6 +345,25 @@ def m.attribute_missing(match, *args, &block)
assert_equal "attribute_test", match.proxy_target
end

test "should use attribute_missing to dispatch a missing attribute alias" do
klass = Class.new(ModelWithAttributes) do
define_attribute_method(:foo)
alias_attribute :foo2, :foo
end

m = klass.new
def m.attribute_missing(match, ...)
match
end
klass.undef_method :foo
klass.undef_method :foo2

match = m.foo2

assert_equal "foo", match.attr_name
assert_equal "attribute", match.proxy_target
end

module NameClash
class Model1
include ActiveModel::AttributeMethods
Expand Down

0 comments on commit 78b6d93

Please sign in to comment.