Skip to content

Commit cfccb00

Browse files
committed
alias_attribute: handle user defined source methods
`alias_attribute` used to define a "jump method", e.g. `alias_attribute :foo, :bar` was pretty much a macro to generate ```ruby def foo bar end ``` This is convienient because it's easy, it doesn't impose an order of declaration or anything like that. But it's also much less efficient than a true `alias_method`. It also used to cause cache size explosion which we fixed in rails#52118, but making it behave like Ruby's `alias_method`, by doing a real alias. But this breaks some expectations (literally from the documentation): ```ruby attr_accessor :name attribute_method_suffix '_short?' define_attribute_methods :name alias_attribute :nickname, :name ``` Here we're not aliasing a generated method, but a user defined one. A solution is to check if the method exist in the class itself, and if it does, alias that user defined method instead of generating one. It solves the issue at hand, but still is more restrictive than the original implementation, as the user method has to be defined before the `alias_attribute` call, but I think that's an OK limitation. Another limitation is that user defined methods have to be defined in the class itself. If they are defined in an ancestor the issue remains.
1 parent 17ba9d2 commit cfccb00

File tree

1 file changed

+11
-1
lines changed

1 file changed

+11
-1
lines changed

activemodel/lib/active_model/attribute_methods.rb

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,17 @@ def eagerly_generate_alias_attribute_methods(new_name, old_name) # :nodoc:
215215
end
216216

217217
def generate_alias_attribute_methods(code_generator, new_name, old_name)
218-
define_attribute_method(old_name, _owner: code_generator, as: new_name)
218+
ActiveSupport::CodeGenerator.batch(code_generator, __FILE__, __LINE__) do |owner|
219+
attribute_method_patterns.each do |pattern|
220+
old_attribute_method = pattern.method_name(old_name)
221+
if method_defined?(old_attribute_method, false)
222+
alias_method(pattern.method_name(new_name), old_attribute_method)
223+
else
224+
define_attribute_method_pattern(pattern, old_name, owner: owner, as: new_name)
225+
end
226+
end
227+
attribute_method_patterns_cache.clear
228+
end
219229
end
220230

221231
def alias_attribute_method_definition(code_generator, pattern, new_name, old_name) # :nodoc:

0 commit comments

Comments
 (0)