-
Notifications
You must be signed in to change notification settings - Fork 21.9k
Add Rails.application.deprecators
#46049
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
Add Rails.application.deprecators
#46049
Conversation
|
||
# | ||
def [](name) | ||
# TODO? automatically instantiate a deprecator when it does not exist? |
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.
Maybe, but I'd not do it now and only do it later if it makes sense for the framework's own usage.
|
||
# | ||
def []=(name, deprecator) | ||
# TODO? save configuration from setters (e.g. `#silenced=`) and apply |
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 think it makes sense.
01add7e
to
c4e99ae
Compare
c4e99ae
to
f3b53c7
Compare
f3b53c7
to
e9ba80e
Compare
This adds a `Rails.application.deprecators` method that returns a managed collection of deprecators. Individual deprecators can be added and retrieved from the collection: ```ruby Rails.application.deprecators[:my_gem] = ActiveSupport::Deprecation.new("2.0", "MyGem") Rails.application.deprecators[:other_gem] = ActiveSupport::Deprecation.new("3.0", "OtherGem") ``` And the collection's configuration methods affect all deprecators in the collection: ```ruby Rails.application.deprecators.debug = true Rails.application.deprecators[:my_gem].debug # => true Rails.application.deprecators[:other_gem].debug # => true ``` Additionally, all deprecators in the collection can be silenced for the duration of a given block: ```ruby Rails.application.deprecators.silence do Rails.application.deprecators[:my_gem].warn # => silenced (no warning) Rails.application.deprecators[:other_gem].warn # => silenced (no warning) end ```
e9ba80e
to
d240e8a
Compare
Hi @jonathanhefner. |
@p8 Close, but it would be Dalli registering Before this PR, if a library created its own deprecator instance, users of the library would have to seek out and configure that instance separately from the global MyGem.deprecator = ActiveSupport::Deprecation.new("2.0", "my_gem") and a user wanted to set ActiveSupport::Deprecation.behavior = :raise
MyGem.deprecator.behavior = :raise And so on for each library with its own deprecator instance. With this PR, each library can have an initializer like: module MyGem
class Railtie < ::Rails::Railtie
initializer :deprecator do |app|
app.deprecators[:my_gem] = MyGem.deprecator
end
end
end And then the user will only have to write: Rails.application.deprecators.behavior = :raise Alternatively, if the user wants to change the behavior for a single deprecator, they now have a standard location to do so: Rails.application.deprecators[:my_gem].behavior = :raise And all the above also applies to the |
Ok clear. Thanks @jonathanhefner ! |
Follow-up to rails#46049 and rails#47354. Since `Rails.deprecator` is now a new `ActiveSupport::Deprecation` instance instead of `ActiveSupport::Deprecation.instance`, it makes sense to register it as `Rails.application.deprecators[:railties]` instead of `Rails.application.deprecators[:rails]`.
Follow-up to rails#46049 and rails#47354. Since `Rails.deprecator` is now a new `ActiveSupport::Deprecation` instance instead of `ActiveSupport::Deprecation.instance`, it makes sense to register it as `Rails.application.deprecators[:railties]` instead of `Rails.application.deprecators[:rails]`.
Follow-up to rails#46049 and rails#47354. Since `Rails.deprecator` is now a new `ActiveSupport::Deprecation` instance instead of `ActiveSupport::Deprecation.instance`, it makes sense to register it as `Rails.application.deprecators[:railties]` instead of `Rails.application.deprecators[:rails]`.
Follow-up to rails#46049 and rails#47354. Since `Rails.deprecator` is now a new `ActiveSupport::Deprecation` instance instead of `ActiveSupport::Deprecation.instance`, it makes sense to register it as `Rails.application.deprecators[:railties]` instead of `Rails.application.deprecators[:rails]`.
[`Rails.application.deprecators` were introduced on Rails 7.1](rails/rails#46049); this pull request opt-outs the inclusion of the bundled deprecator in previous versions still supported by this gem (6.1, 7.0). Dependencies were updated (`bundle install && bundle exec appraisal update`) and pinned to supported Ruby versioning bracket. /task https://app.asana.com/0/1207383500465368/1209229335575544/f
I am thinking of a use case that may not fit well with the current design/APIs. I am implementing support for deprecating associations: class User < ApplicationRecord
has_many :posts, deprecated: true
end The idea is that whenever the association is used (say, OK. The deprecation is checked and issued by AR, but it is not a deprecation of the library itself, nor does it have an horizon. It is an application-level deprecation issued by AR. Does it make sense to extend deprecations to support this use case? |
I have this working as a monkey patch in a client. That implementation just publishes an AS notification, so it is the subscriber in the application who has full control about what to do. It has also the benefit of receiving the reflection in the payload, instead of a string. I like the flexibility of this approach, it has been helpful in different ways. But, while upstreaming, I am wondering if users would expect a regular deprecation instead. |
I think it makes sense. Thinking of deprecator objects as communication channels, it seems reasonable to have a deprecator for each "class" of message a user may be interested in. So we could have a
I guess it depends on how the user wants to track / handle the deprecation. In particular, do they want the DX of a regular deprecation when running their test suite? |
In my real usage, in production there is no warning issued. Metadata about the reflection and santizied backtrace are sent to Datadog as a structured event. Use case is that I want to delete the association, CI issues no warnings, but I want to watch production before deleting. Logs are capped due to their volume, so a warning could be dropped and you'd miss usage. Additionally, the event allows for fine structured queries in Datadog. |
One possibility would be a config option per environment that can be |
Though, I'd like to explore if I can make an application deprecator receive a payload with a reflection object. |
One way would be as an additional argument to the Another way would be to pass the payload as the first argument (e.g. as Perhaps we could add an attribute to |
Yes, I saw that support for multiple signatures which complicates things. I have not thought about this in detail, but an idea that I had in mind was to introduce a new type of deprecator, an application deprecator. Because here, the responsibilities are kind of reversed, it is not Active Record deprecating something, it is the application deprecating something, only the logic for triggering that is within AR. So, an application deprecator would not have a horizon, and would have some API that receives a payload. The deprecator would be responsible for warning, or sending an event, building a usage backlog in CI, or whatever logic it wants. That is a raw idea, don't know if it is any good. |
This adds a
Rails.application.deprecators
method that returns a managed collection of deprecators.Individual deprecators can be added and retrieved from the collection:
And the collection's configuration methods affect all deprecators in the collection:
Additionally, all deprecators in the collection can be silenced for the duration of a given block: