Merge pull request #49173 from Shopify/define-alias-attribute-methods-in-define_attribute_methods

Define alias attribute methods in `define_attribute_methods`
This commit is contained in:
Jean Boussier 2023-09-06 22:53:43 +02:00 committed by GitHub
commit 304f0a3c01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 63 additions and 10 deletions

@ -202,8 +202,10 @@ def attribute_method_affix(*affixes)
# person.name_short? # => true
# person.nickname_short? # => true
def alias_attribute(new_name, old_name)
self.attribute_aliases = attribute_aliases.merge(new_name.to_s => old_name.to_s)
self.local_attribute_aliases = local_attribute_aliases.merge(new_name.to_s => old_name.to_s)
old_name = old_name.to_s
new_name = new_name.to_s
self.attribute_aliases = attribute_aliases.merge(new_name => old_name)
aliases_by_attribute_name[old_name] << new_name
eagerly_generate_alias_attribute_methods(new_name, old_name)
end
@ -282,7 +284,12 @@ def attribute_alias(name)
# end
def define_attribute_methods(*attr_names)
ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |owner|
attr_names.flatten.each { |attr_name| define_attribute_method(attr_name, _owner: owner) }
attr_names.flatten.each do |attr_name|
define_attribute_method(attr_name, _owner: owner)
aliases_by_attribute_name[attr_name.to_s].each do |aliased_name|
generate_alias_attribute_methods owner, aliased_name, attr_name
end
end
end
end
@ -365,13 +372,11 @@ def undefine_attribute_methods
attribute_method_patterns_cache.clear
end
def local_attribute_aliases # :nodoc:
@local_attribute_aliases ||= {}
def aliases_by_attribute_name # :nodoc:
@aliases_by_attribute_name ||= Hash.new { |h, k| h[k] = [] }
end
private
attr_writer :local_attribute_aliases # :nodoc:
def inherited(base) # :nodoc:
super
base.class_eval do

@ -119,6 +119,34 @@ class AttributeMethodsTest < ActiveModel::TestCase
ModelWithAttributes.undefine_attribute_methods
end
test "#define_attribute_methods defines alias attribute methods after undefining" do
topic_class = Class.new do
include ActiveModel::AttributeMethods
define_attribute_methods :title
alias_attribute :aliased_title_to_be_redefined, :title
def attributes
{ title: "Active Model Topic" }
end
private
def attribute(name)
attributes[name.to_sym]
end
end
topic = topic_class.new
assert_equal("Active Model Topic", topic.aliased_title_to_be_redefined)
topic_class.undefine_attribute_methods
assert_not_respond_to topic, :aliased_title_to_be_redefined
topic_class.define_attribute_methods :title
assert_respond_to topic, :aliased_title_to_be_redefined
assert_equal "Active Model Topic", topic.aliased_title_to_be_redefined
end
test "#define_attribute_method does not generate attribute method if already defined in attribute module" do
klass = Class.new(ModelWithAttributes)
klass.send(:generated_attribute_methods).module_eval do

@ -71,8 +71,10 @@ def generate_alias_attributes # :nodoc:
generated_attribute_methods.synchronize do
return if @alias_attributes_mass_generated
ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |code_generator|
local_attribute_aliases.each do |new_name, old_name|
generate_alias_attribute_methods(code_generator, new_name, old_name)
aliases_by_attribute_name.each do |old_name, new_names|
new_names.each do |new_name|
generate_alias_attribute_methods(code_generator, new_name, old_name)
end
end
end

@ -1039,6 +1039,25 @@ def name
end
end
test "#define_attribute_methods brings back undefined aliases" do
topic_class = Class.new(ActiveRecord::Base) do
self.table_name = "topics"
alias_attribute :title_alias_to_be_undefined, :title
end
topic = topic_class.new(title: "New topic")
assert_equal("New topic", topic.title_alias_to_be_undefined)
topic_class.undefine_attribute_methods
assert_not_respond_to topic, :title_alias_to_be_undefined
topic_class.define_attribute_methods
assert_respond_to topic, :title_alias_to_be_undefined
assert_equal "New topic", topic.title_alias_to_be_undefined
end
test "define_attribute_method works with both symbol and string" do
klass = Class.new(ActiveRecord::Base)
klass.table_name = "foo"

@ -5,7 +5,6 @@
class NumericalityValidationTest < ActiveRecord::TestCase
def setup
NumericData.generate_alias_attributes
@model_class = NumericData.dup
end