Skip to content

Commit 304f0a3

Browse files
authored
Merge pull request rails#49173 from Shopify/define-alias-attribute-methods-in-define_attribute_methods
Define alias attribute methods in `define_attribute_methods`
2 parents 9044d35 + 0f5563b commit 304f0a3

File tree

5 files changed

+63
-10
lines changed

5 files changed

+63
-10
lines changed

activemodel/lib/active_model/attribute_methods.rb

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,10 @@ def attribute_method_affix(*affixes)
202202
# person.name_short? # => true
203203
# person.nickname_short? # => true
204204
def alias_attribute(new_name, old_name)
205-
self.attribute_aliases = attribute_aliases.merge(new_name.to_s => old_name.to_s)
206-
self.local_attribute_aliases = local_attribute_aliases.merge(new_name.to_s => old_name.to_s)
205+
old_name = old_name.to_s
206+
new_name = new_name.to_s
207+
self.attribute_aliases = attribute_aliases.merge(new_name => old_name)
208+
aliases_by_attribute_name[old_name] << new_name
207209
eagerly_generate_alias_attribute_methods(new_name, old_name)
208210
end
209211

@@ -282,7 +284,12 @@ def attribute_alias(name)
282284
# end
283285
def define_attribute_methods(*attr_names)
284286
ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |owner|
285-
attr_names.flatten.each { |attr_name| define_attribute_method(attr_name, _owner: owner) }
287+
attr_names.flatten.each do |attr_name|
288+
define_attribute_method(attr_name, _owner: owner)
289+
aliases_by_attribute_name[attr_name.to_s].each do |aliased_name|
290+
generate_alias_attribute_methods owner, aliased_name, attr_name
291+
end
292+
end
286293
end
287294
end
288295

@@ -365,13 +372,11 @@ def undefine_attribute_methods
365372
attribute_method_patterns_cache.clear
366373
end
367374

368-
def local_attribute_aliases # :nodoc:
369-
@local_attribute_aliases ||= {}
375+
def aliases_by_attribute_name # :nodoc:
376+
@aliases_by_attribute_name ||= Hash.new { |h, k| h[k] = [] }
370377
end
371378

372379
private
373-
attr_writer :local_attribute_aliases # :nodoc:
374-
375380
def inherited(base) # :nodoc:
376381
super
377382
base.class_eval do

activemodel/test/cases/attribute_methods_test.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,34 @@ class AttributeMethodsTest < ActiveModel::TestCase
119119
ModelWithAttributes.undefine_attribute_methods
120120
end
121121

122+
test "#define_attribute_methods defines alias attribute methods after undefining" do
123+
topic_class = Class.new do
124+
include ActiveModel::AttributeMethods
125+
define_attribute_methods :title
126+
alias_attribute :aliased_title_to_be_redefined, :title
127+
128+
def attributes
129+
{ title: "Active Model Topic" }
130+
end
131+
132+
private
133+
def attribute(name)
134+
attributes[name.to_sym]
135+
end
136+
end
137+
138+
topic = topic_class.new
139+
assert_equal("Active Model Topic", topic.aliased_title_to_be_redefined)
140+
topic_class.undefine_attribute_methods
141+
142+
assert_not_respond_to topic, :aliased_title_to_be_redefined
143+
144+
topic_class.define_attribute_methods :title
145+
146+
assert_respond_to topic, :aliased_title_to_be_redefined
147+
assert_equal "Active Model Topic", topic.aliased_title_to_be_redefined
148+
end
149+
122150
test "#define_attribute_method does not generate attribute method if already defined in attribute module" do
123151
klass = Class.new(ModelWithAttributes)
124152
klass.send(:generated_attribute_methods).module_eval do

activerecord/lib/active_record/attribute_methods.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,10 @@ def generate_alias_attributes # :nodoc:
7171
generated_attribute_methods.synchronize do
7272
return if @alias_attributes_mass_generated
7373
ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |code_generator|
74-
local_attribute_aliases.each do |new_name, old_name|
75-
generate_alias_attribute_methods(code_generator, new_name, old_name)
74+
aliases_by_attribute_name.each do |old_name, new_names|
75+
new_names.each do |new_name|
76+
generate_alias_attribute_methods(code_generator, new_name, old_name)
77+
end
7678
end
7779
end
7880

activerecord/test/cases/attribute_methods_test.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,6 +1039,25 @@ def name
10391039
end
10401040
end
10411041

1042+
test "#define_attribute_methods brings back undefined aliases" do
1043+
topic_class = Class.new(ActiveRecord::Base) do
1044+
self.table_name = "topics"
1045+
1046+
alias_attribute :title_alias_to_be_undefined, :title
1047+
end
1048+
1049+
topic = topic_class.new(title: "New topic")
1050+
assert_equal("New topic", topic.title_alias_to_be_undefined)
1051+
topic_class.undefine_attribute_methods
1052+
1053+
assert_not_respond_to topic, :title_alias_to_be_undefined
1054+
1055+
topic_class.define_attribute_methods
1056+
1057+
assert_respond_to topic, :title_alias_to_be_undefined
1058+
assert_equal "New topic", topic.title_alias_to_be_undefined
1059+
end
1060+
10421061
test "define_attribute_method works with both symbol and string" do
10431062
klass = Class.new(ActiveRecord::Base)
10441063
klass.table_name = "foo"

activerecord/test/cases/validations/numericality_validation_test.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
class NumericalityValidationTest < ActiveRecord::TestCase
77
def setup
8-
NumericData.generate_alias_attributes
98
@model_class = NumericData.dup
109
end
1110

0 commit comments

Comments
 (0)