New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ensure target is an attribute for alias_attribute
#48972
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! And sorry for the troubles with a misleading message
Just a few non-blocking suggestions on tests
02eaf46
to
22f8548
Compare
Thank you for the suggestions ❤️ And no worries - we were doing some wacky stuff, happy that we're able to remove these usages 🙏 |
@@ -90,7 +90,18 @@ def alias_attribute_method_definition(code_generator, pattern, new_name, old_nam | |||
manually_defined = method_defined && self.instance_method(target_name).owner != generated_attribute_methods | |||
reserved_method_name = ::ActiveRecord::AttributeMethods.dangerous_attribute_methods.include?(target_name) | |||
|
|||
if manually_defined && !reserved_method_name | |||
if !has_attribute?(old_name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In an unrelated conversation I realized that this is something that will disallow alias attribute definitions in an abstract class. For example in an inheritance chain like MyModel < AbstractClassA < AbstractClassB < ApplicationRecord < ActiveRecord::Base
alias_attribute
defined in abstract classes will most likely raise a deprecation or even fail since these abstract classes have no attributes while it used to be possible to define alias attributes on abstract classes and it was a valid use-case
So here we should most likely ignore if the definition is happening on an abstract class as we can't know if the attribute exists on a concrete class inherited from the abstract class
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, thanks for catching that. I'll add a test for that case and add that fix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I incorporated the changes from main
, which included #48991, and added the check for the abstract_class
, but it looks like this change broke some other behavior in a different test file. I'm going to investigate why this broke...
22f8548
to
078235b
Compare
The CI errors look legit:
|
Yep, sorry for the delay here. I have a couple of TODOs here:
If it's helpful, I can close this out while I make those changes and re-open when it's ready for review again? |
Nah, no worries, it can stay open it's fine. |
We ran into a few cases at GitHub where we were using alias_attribute incorrectly and the new behavior either didn't warn or raised an unclear deprecation warning. This attempts to add clarity to the deprecation reason when you try to alias something that isn't actually an attribute. Previously, trying to alias a generated attribute method, such as `attribute_in_database`, would still hit `define_proxy_call`, because we were only checking the owner of the target method. In the future, we should probably raise if you try to use alias_attribute for a non-attribute. Note that we don't raise the warning for abstract classes, because the attribute may be implemented by a child class. We could potentially figure out a way to raise in these cases as well, but this hopefully is good enough for now. Finally, I also updated the way we're setting `local_alias_attributes` when `alias_attribute` is first called. This was causing problems since we now use `alias_attribute` early in the `load_schema!` call for some models: https://buildkite.com/rails/rails/builds/98910
078235b
to
eae26ca
Compare
@@ -370,6 +370,8 @@ def local_attribute_aliases # :nodoc: | |||
end | |||
|
|||
private | |||
attr_writer :local_attribute_aliases # :nodoc: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added to resolve these failures - https://buildkite.com/rails/rails/builds/98910#018a198e-03ae-4d10-820e-67f72d4b14c0. Also matches the signature for attribute_aliases
, which might be better anyway.
@nvasilevski Apologies for the delay here, but this is ready for review now! I had to make a couple of minor tweaks to account for the changes from #48930 |
Motivation / Background
We ran into a few cases at GitHub where we were using
alias_attribute
incorrectly to target non-attribute methods. Previously, this "worked", becausealias_attribute
just forwarded the method call, but this is no longer the case.In most cases, this raised a deprecation warning, although the message was a bit unclear. The original deprecation warning was intended to look for manually defined alias methods that won't be forwarded in the future.
If the target happens to be a generated attribute method, no deprecation is raised. For example, assuming a model has a
title
attribute,alias_attribute :saved_title, :title_in_database
was using the new behavior, because we only raise the deprecation if the target method is not an attribute method.Detail
This Pull Request adds a check to
alias_attribute_method_definition
to ensure that you actually are targeting an attribute, and raises a deprecation warning if not. In the future, I think we should raise if you try to usealias_attribute
with a non-attribute method.Note that the following code will still behave correctly, because
has_attribute?
will forward the aliases to the far target automatically.This correctly issues a deprecation warning for generated attribute methods, and also makes the warning for any non-attribute methods more clear.
Additional information
We originally tried to make this warning even more specific in #48929, but the logic got kind of complicated. Issuing one warning for this case felt like a good compromise.
Checklist
Before submitting the PR make sure the following are checked:
[Fix #issue-number]