Asked 1 month ago by PlutonianNavigator261
Why isn’t my mixin method recognized on Doorkeeper::Application after upgrading to Rails 8?
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
Asked 1 month ago by PlutonianNavigator261
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
I recently upgraded my Rails app from version 7 to 8 while using Doorkeeper 5.8.1. In my app, I have custom mixins for Doorkeeper::Application, AccessToken, and AccessGrant defined with extend ActiveSupport::Concern
. For example:
RUBY# app/models/concerns/my_mixin.rb module MyMixin extend ActiveSupport::Concern included do has_one :other_obj, foreign_key: :id, class_name: "OtherObj" validates :api_key, uniqueness: true, allow_nil: true validates_length_of :api_key, minimum: 32, allow_blank: true end def my_method(input) # do something with input. other_obj.process(input) end end Doorkeeper::Application.include MyMixin
After the upgrade, my unit tests for Doorkeeper::Application.my_method(test_input)
are failing with:
NoMethodError:
undefined method 'my_method' for an instance of Doorkeeper::Application
It appears that calling my_method
on the Doorkeeper::Application class isn’t working as expected in Rails 8. I’m wondering if any changes between Rails 7 and 8 could be affecting the behavior of ActiveSupport::Concern or the auto-loading of my mixins?
I’ve seen suggestions that the method is being defined as an instance method, so I may need to call it on an instance of Doorkeeper::Application, or explicitly define it as a class method if that was my intent. Any guidance on how to resolve this issue would be appreciated.
Comments 0
•Answers 2
•Views 70
Answer by TychoAI Agent • 1 month ago
It turns out nothing in Rails 8 changed the way ActiveSupport::Concern works. In your mixin, you defined my_method as an instance method, so you need to call it on an instance of Doorkeeper::Application rather than on the class itself.
For example, instead of calling:
RUBYDoorkeeper::Application.my_method(test_input)
you should do something like:
RUBYapp = Doorkeeper::Application.first app.my_method(test_input)
If you intended to add a class method to Doorkeeper::Application, you can do so by adding it inside a class_methods block in your concern. For example:
RUBYmodule MyMixin extend ActiveSupport::Concern included do has_one :other_obj, foreign_key: :id, class_name: "OtherObj" validates :api_key, uniqueness: true, allow_nil: true validates_length_of :api_key, minimum: 32, allow_blank: true end def my_method(input) other_obj.process(input) end class_methods do def my_class_method(input) # Class-level logic here. end end end Doorkeeper::Application.include MyMixin
Now, if you wanted to call a class method, you could call it like this:
RUBYDoorkeeper::Application.my_class_method(test_input)
In summary, Rails 8 did not change the behavior of ActiveSupport::Concern—you just need to make sure you are calling instance methods on an instance or define class methods appropriately in your mixin.
Tycho is an AI agent, that grounds responses in various sources like documentation, code bases, live discussions, and relevant posts. Want to chat privately with Tycho?
No comments yet.
Answer by StarTracker931 • 2 months ago
A much better approach than monkeypatching is to just configure Doorkeeper to use your own classes:
RUBY# config/initializers/doorkeeper.rb Doorkeeper.configure do # ... # You can use your own model classes if you need to extend (or even override) default # Doorkeeper models such as `Application`, `AccessToken` and `AccessGrant. # # By default Doorkeeper ActiveRecord ORM uses its own classes: # # access_token_class "Doorkeeper::AccessToken" # access_grant_class "Doorkeeper::AccessGrant" application_class "MyApplication" # ... end
RUBYclass MyApplication < Doorkeeper::Application has_one :other_obj, foreign_key: :id, class_name: "OtherObj" validates :api_key, uniqueness: true, allow_nil: true validates_length_of :api_key, minimum: 32, allow_blank: true def my_method(input) do # do something with input. other_obj.process(input) end end
Using modules to monkeypatch classes that are not yours should always be a last resort.
Did something change between Rails 7 and 8 that I'm missing?
Maybe. But it could have been that the monkeypatch worked when the code was eager loaded or that another test had previously caused the module to be required.
If you're gonna monkeypatch do it explicitly (in an initializer) instead of having the autoloader do it implicitly when the file is loaded. It's also a good practice to separate the file that defines the monkeypatch from the "injection" as it lets you test it without side effects.
No comments yet.
No comments yet.