doorkeeper-gem / doorkeeper

Doorkeeper is an OAuth 2 provider for Ruby on Rails / Grape.
https://doorkeeper.gitbook.io/guides/
MIT License
5.32k stars 1.07k forks source link

Doorkeeper 5.5.0 breaks something related to polymorphic relationships in other models? #1489

Closed connorshea closed 1 year ago

connorshea commented 3 years ago

Steps to reproduce

I'm gonna be honest, I'm not entirely sure how to reproduce this other than by running my Rails app (vglist repo here) in production mode. Unfortunately, doing that locally is not trivial, and as far as I've been able to figure out, this issue doesn't occur in development mode (at least, I haven't been able to figure out how to get it to happen).

I also have no idea why this Doorkeeper upgrade breaks it.

What I know:

No other changes have been made to my application other than the Doorkeeper 5.5.0 upgrade.

This is the stack trace being reported to Sentry:

Stack trace ``` NoMethodError: undefined method `game' for # Did you mean? games from activemodel (6.1.3) lib/active_model/attribute_methods.rb:469:in `method_missing' from pg_search (2.3.5) lib/pg_search/model.rb:42:in `method_missing' from app/helpers/activity_helper.rb:29:in `completion_status_event_text' from sorbet-runtime (0.5.6324) lib/types/private/methods/call_validation_2_7.rb:141:in `bind_call' from sorbet-runtime (0.5.6324) lib/types/private/methods/call_validation_2_7.rb:141:in `block in create_validator_method_fast1' from app/helpers/activity_helper.rb:12:in `event_text' from sorbet-runtime (0.5.6324) lib/types/private/methods/call_validation_2_7.rb:141:in `bind_call' from sorbet-runtime (0.5.6324) lib/types/private/methods/call_validation_2_7.rb:141:in `block in create_validator_method_fast1' from app/views/shared/_event.html.erb:12 from actionview (6.1.3) lib/action_view/base.rb:247:in `public_send' from actionview (6.1.3) lib/action_view/base.rb:247:in `_run' from actionview (6.1.3) lib/action_view/template.rb:154:in `block in render' from activesupport (6.1.3) lib/active_support/notifications.rb:205:in `instrument' from actionview (6.1.3) lib/action_view/template.rb:345:in `instrument_render_template' from actionview (6.1.3) lib/action_view/template.rb:152:in `render' from actionview (6.1.3) lib/action_view/renderer/partial_renderer.rb:285:in `block in render_partial_template' from activesupport (6.1.3) lib/active_support/notifications.rb:203:in `block in instrument' from activesupport (6.1.3) lib/active_support/notifications/instrumenter.rb:24:in `instrument' from activesupport (6.1.3) lib/active_support/notifications.rb:203:in `instrument' from actionview (6.1.3) lib/action_view/renderer/partial_renderer.rb:280:in `render_partial_template' from actionview (6.1.3) lib/action_view/renderer/partial_renderer.rb:271:in `render' from actionview (6.1.3) lib/action_view/renderer/renderer.rb:81:in `render_partial_to_object' from actionview (6.1.3) lib/action_view/renderer/renderer.rb:53:in `render_partial' from actionview (6.1.3) lib/action_view/helpers/rendering_helper.rb:45:in `render' from app/views/activity/following.html.erb:13 from activerecord (6.1.3) lib/active_record/relation/delegation.rb:88:in `each' from activerecord (6.1.3) lib/active_record/relation/delegation.rb:88:in `each' from app/views/activity/following.html.erb:11 from actionview (6.1.3) lib/action_view/base.rb:247:in `public_send' from actionview (6.1.3) lib/action_view/base.rb:247:in `_run' from actionview (6.1.3) lib/action_view/template.rb:154:in `block in render' from activesupport (6.1.3) lib/active_support/notifications.rb:205:in `instrument' from actionview (6.1.3) lib/action_view/template.rb:345:in `instrument_render_template' from actionview (6.1.3) lib/action_view/template.rb:152:in `render' from actionview (6.1.3) lib/action_view/renderer/template_renderer.rb:61:in `block (2 levels) in render_template' from activesupport (6.1.3) lib/active_support/notifications.rb:203:in `block in instrument' from activesupport (6.1.3) lib/active_support/notifications/instrumenter.rb:24:in `instrument' from activesupport (6.1.3) lib/active_support/notifications.rb:203:in `instrument' from actionview (6.1.3) lib/action_view/renderer/template_renderer.rb:56:in `block in render_template' from actionview (6.1.3) lib/action_view/renderer/template_renderer.rb:71:in `block in render_with_layout' from activesupport (6.1.3) lib/active_support/notifications.rb:203:in `block in instrument' from activesupport (6.1.3) lib/active_support/notifications/instrumenter.rb:24:in `instrument' from activesupport (6.1.3) lib/active_support/notifications.rb:203:in `instrument' from actionview (6.1.3) lib/action_view/renderer/template_renderer.rb:70:in `render_with_layout' from actionview (6.1.3) lib/action_view/renderer/template_renderer.rb:55:in `render_template' from actionview (6.1.3) lib/action_view/renderer/template_renderer.rb:11:in `render' from actionview (6.1.3) lib/action_view/renderer/renderer.rb:61:in `render_template_to_object' from actionview (6.1.3) lib/action_view/renderer/renderer.rb:29:in `render_to_object' from actionview (6.1.3) lib/action_view/rendering.rb:117:in `block in _render_template' from actionview (6.1.3) lib/action_view/base.rb:273:in `in_rendering_context' from actionview (6.1.3) lib/action_view/rendering.rb:116:in `_render_template' from actionpack (6.1.3) lib/action_controller/metal/streaming.rb:218:in `_render_template' from actionview (6.1.3) lib/action_view/rendering.rb:103:in `render_to_body' from actionpack (6.1.3) lib/action_controller/metal/rendering.rb:52:in `render_to_body' from actionpack (6.1.3) lib/action_controller/metal/renderers.rb:142:in `render_to_body' from actionpack (6.1.3) lib/abstract_controller/rendering.rb:25:in `render' from actionpack (6.1.3) lib/action_controller/metal/rendering.rb:36:in `render' from actionpack (6.1.3) lib/action_controller/metal/instrumentation.rb:46:in `block (2 levels) in render' from benchmark.rb:308:in `realtime' from activesupport (6.1.3) lib/active_support/core_ext/benchmark.rb:14:in `ms' from actionpack (6.1.3) lib/action_controller/metal/instrumentation.rb:46:in `block in render' from actionpack (6.1.3) lib/action_controller/metal/instrumentation.rb:86:in `cleanup_view_runtime' from activerecord (6.1.3) lib/active_record/railties/controller_runtime.rb:34:in `cleanup_view_runtime' from actionpack (6.1.3) lib/action_controller/metal/instrumentation.rb:45:in `render' from actionpack (6.1.3) lib/action_controller/metal/implicit_render.rb:35:in `default_render' from actionpack (6.1.3) lib/action_controller/metal/basic_implicit_render.rb:6:in `block in send_action' from actionpack (6.1.3) lib/action_controller/metal/basic_implicit_render.rb:6:in `tap' from actionpack (6.1.3) lib/action_controller/metal/basic_implicit_render.rb:6:in `send_action' from actionpack (6.1.3) lib/abstract_controller/base.rb:228:in `process_action' from actionpack (6.1.3) lib/action_controller/metal/rendering.rb:30:in `process_action' from actionpack (6.1.3) lib/abstract_controller/callbacks.rb:42:in `block in process_action' from activesupport (6.1.3) lib/active_support/callbacks.rb:117:in `block in run_callbacks' from sentry-raven (3.1.1) lib/raven/integrations/rails/controller_transaction.rb:7:in `block in included' from activesupport (6.1.3) lib/active_support/callbacks.rb:126:in `instance_exec' from activesupport (6.1.3) lib/active_support/callbacks.rb:126:in `block in run_callbacks' from activesupport (6.1.3) lib/active_support/callbacks.rb:137:in `run_callbacks' from actionpack (6.1.3) lib/abstract_controller/callbacks.rb:41:in `process_action' from actionpack (6.1.3) lib/action_controller/metal/rescue.rb:22:in `process_action' from actionpack (6.1.3) lib/action_controller/metal/instrumentation.rb:34:in `block in process_action' from activesupport (6.1.3) lib/active_support/notifications.rb:203:in `block in instrument' from activesupport (6.1.3) lib/active_support/notifications/instrumenter.rb:24:in `instrument' from activesupport (6.1.3) lib/active_support/notifications.rb:203:in `instrument' from actionpack (6.1.3) lib/action_controller/metal/instrumentation.rb:33:in `process_action' from actionpack (6.1.3) lib/action_controller/metal/params_wrapper.rb:249:in `process_action' from activerecord (6.1.3) lib/active_record/railties/controller_runtime.rb:27:in `process_action' from actionpack (6.1.3) lib/abstract_controller/base.rb:165:in `process' from actionview (6.1.3) lib/action_view/rendering.rb:39:in `process' from actionpack (6.1.3) lib/action_controller/metal.rb:190:in `dispatch' from actionpack (6.1.3) lib/action_controller/metal.rb:254:in `dispatch' from actionpack (6.1.3) lib/action_dispatch/routing/route_set.rb:50:in `dispatch' from actionpack (6.1.3) lib/action_dispatch/routing/route_set.rb:33:in `serve' from actionpack (6.1.3) lib/action_dispatch/journey/router.rb:50:in `block in serve' from actionpack (6.1.3) lib/action_dispatch/journey/router.rb:32:in `each' from actionpack (6.1.3) lib/action_dispatch/journey/router.rb:32:in `serve' from actionpack (6.1.3) lib/action_dispatch/routing/route_set.rb:842:in `call' from warden (1.2.9) lib/warden/manager.rb:36:in `block in call' from warden (1.2.9) lib/warden/manager.rb:34:in `catch' from warden (1.2.9) lib/warden/manager.rb:34:in `call' from rack (2.2.3) lib/rack/tempfile_reaper.rb:15:in `call' from rack (2.2.3) lib/rack/etag.rb:27:in `call' from rack (2.2.3) lib/rack/conditional_get.rb:27:in `call' from rack (2.2.3) lib/rack/head.rb:12:in `call' from actionpack (6.1.3) lib/action_dispatch/http/permissions_policy.rb:22:in `call' from actionpack (6.1.3) lib/action_dispatch/http/content_security_policy.rb:18:in `call' from rack (2.2.3) lib/rack/session/abstract/id.rb:266:in `context' from rack (2.2.3) lib/rack/session/abstract/id.rb:260:in `call' from actionpack (6.1.3) lib/action_dispatch/middleware/cookies.rb:689:in `call' from actionpack (6.1.3) lib/action_dispatch/middleware/callbacks.rb:27:in `block in call' from activesupport (6.1.3) lib/active_support/callbacks.rb:98:in `run_callbacks' from actionpack (6.1.3) lib/action_dispatch/middleware/callbacks.rb:26:in `call' from actionpack (6.1.3) lib/action_dispatch/middleware/actionable_exceptions.rb:18:in `call' from actionpack (6.1.3) lib/action_dispatch/middleware/debug_exceptions.rb:29:in `call' from actionpack (6.1.3) lib/action_dispatch/middleware/show_exceptions.rb:33:in `call' from railties (6.1.3) lib/rails/rack/logger.rb:37:in `call_app' from railties (6.1.3) lib/rails/rack/logger.rb:26:in `block in call' from activesupport (6.1.3) lib/active_support/tagged_logging.rb:99:in `block in tagged' from activesupport (6.1.3) lib/active_support/tagged_logging.rb:37:in `tagged' from activesupport (6.1.3) lib/active_support/tagged_logging.rb:99:in `tagged' from railties (6.1.3) lib/rails/rack/logger.rb:26:in `call' from actionpack (6.1.3) lib/action_dispatch/middleware/remote_ip.rb:81:in `call' from request_store (1.5.0) lib/request_store/middleware.rb:19:in `call' from actionpack (6.1.3) lib/action_dispatch/middleware/request_id.rb:26:in `call' from rack (2.2.3) lib/rack/method_override.rb:24:in `call' from rack (2.2.3) lib/rack/runtime.rb:22:in `call' from actionpack (6.1.3) lib/action_dispatch/middleware/executor.rb:14:in `call' from rack (2.2.3) lib/rack/sendfile.rb:110:in `call' from actionpack (6.1.3) lib/action_dispatch/middleware/ssl.rb:77:in `call' from actionpack (6.1.3) lib/action_dispatch/middleware/host_authorization.rb:92:in `call' from rack-cors (1.1.1) lib/rack/cors.rb:100:in `call' from sentry-raven (3.1.1) lib/raven/integrations/rack.rb:51:in `call' from railties (6.1.3) lib/rails/engine.rb:539:in `call' from puma (5.2.2) lib/puma/configuration.rb:248:in `call' from puma (5.2.2) lib/puma/request.rb:76:in `block in handle_request' from puma (5.2.2) lib/puma/thread_pool.rb:337:in `with_force_shutdown' from puma (5.2.2) lib/puma/request.rb:75:in `handle_request' from puma (5.2.2) lib/puma/server.rb:431:in `process_client' from puma (5.2.2) lib/puma/thread_pool.rb:145:in `block in spawn_thread' ```

The stack trace mentions a bunch of other gems and I realize it's not mentioning Doorkeeper at all, but given that there were no other changes (I verified this by deploying a version with 5.5.0.rc2 (works) and then a version with 5.5.0 (errors), then back again (works), no other differences), I'm fairly certain it's something that's changed in Doorkeeper between 5.5.0.rc2 and 5.5.0.

This is the code where the error occurs, it's mentioned in the stack trace near the top (link to code in repo):

def completion_status_event_text(event)
  after_value = T.cast(event.differences, T::Hash[String, T.untyped])['completion_status'][1].to_sym # Not relevant, Sorbet stuff we can ignore
  user_link = link_to(event.user.username, user_path(event.user)) # All events have a `user` relationship, so this always works.
  # For some reason, with Doorkeeper 5.5.0 the Eventable is coming back as a
  # `User` record when it should be returning a `GamePurchase` record.
  game_link = link_to(event.eventable.game.name, game_path(event.eventable.game)) # => NoMethodError: undefined method `game' for #<User:0x0000564e7492d2b8>

  # ...
end

The specific issue seems related to polymorphic relationships in Rails models, in this case I have an Event class which has a polymorphic eventable relationship to various different things that events can be about (e.g. "John Doe created their account", "Jane Doe added Minecraft to their library", etc.).

For some reason, my Rails app is getting confused by something which causes it to think that events with an eventable of type GamePurchase (a Game in a user's library) is actually a User. This caused problems when I initially deployed the Doorkeeper update last week, because it started saving Event records with invalid eventable_types relative to their event category, and I added a database constraint to prevent the problem from occurring again in the future.

Note that the issue also happens with other eventable types as well, the specific type of the eventable doesn't matter, it always ends up being interpreted as a User regardless of what the database record's eventable_type in events says.

If I had to make an uneducated guess, I'd think it could be this commit, since it's changing how Doorkeeper's loading is happening, and no other commits since 5.5.0.rc2 seem suspect to me.

If anything here needs clarification, I can try to explain more about the problem or try to figure out a properly reproducible case for you to test with.

Expected behavior

Upgrading Doorkeeper to 5.5.0 should not cause errors in production.

Actual behavior

Upgrading Doorkeeper to 5.5.0 does cause errors in production.

System configuration

You can help us to understand your problem if you will share some very useful information about your project environment (don't forget to remove any confidential data if it exists).

Doorkeeper initializer:

Doorkeeper config ```ruby # config/initializers/doorkeeper.rb Doorkeeper.configure do # Change the ORM that doorkeeper will use (requires ORM extensions installed). # Check the list of supported ORMs here: https://github.com/doorkeeper-gem/doorkeeper#orms orm :active_record # This block will be called to check whether the resource owner is authenticated or not. resource_owner_authenticator do current_user || warden.authenticate!(scope: :user) end # If you didn't skip applications controller from Doorkeeper routes in your application routes.rb # file then you need to declare this block in order to restrict access to the web interface for # adding oauth authorized applications. In other case it will return 403 Forbidden response # every time somebody will try to access the admin web interface. admin_authenticator do if current_user head :forbidden unless current_user.admin? else redirect_to new_user_session_url end end # You can use your own model classes if you need to extend (or even override) default # Doorkeeper models such as `Application`, `AccessToken` and `AccessGrant. # # Be default Doorkeeper ActiveRecord ORM uses it's own classes: # # access_token_class "Doorkeeper::AccessToken" # access_grant_class "Doorkeeper::AccessGrant" # application_class "Doorkeeper::Application" # # Don't forget to include Doorkeeper ORM mixins into your custom models: # # * ::Doorkeeper::Orm::ActiveRecord::Mixins::AccessToken - for access token # * ::Doorkeeper::Orm::ActiveRecord::Mixins::AccessGrant - for access grant # * ::Doorkeeper::Orm::ActiveRecord::Mixins::Application - for application (OAuth2 clients) # # For example: # # access_token_class "MyAccessToken" # # class MyAccessToken < ApplicationRecord # include ::Doorkeeper::Orm::ActiveRecord::Mixins::AccessToken # # self.table_name = "hey_i_wanna_my_name" # # def destroy_me! # destroy # end # end # Enables polymorphic Resource Owner association for Access Tokens and Access Grants. # By default this option is disabled. # # Make sure you properly setup you database and have all the required columns (run # `bundle exec rails generate doorkeeper:enable_polymorphic_resource_owner` and execute Rails # migrations). # # If this option enabled, Doorkeeper will store not only Resource Owner primary key # value, but also it's type (class name). See "Polymorphic Associations" section of # Rails guides: https://guides.rubyonrails.org/association_basics.html#polymorphic-associations # # [NOTE] If you apply this option on already existing project don't forget to manually # update `resource_owner_type` column in the database and fix migration template as it will # set NOT NULL constraint for Access Grants table. # # use_polymorphic_resource_owner # If you are planning to use Doorkeeper in Rails 5 API-only application, then you might # want to use API mode that will skip all the views management and change the way how # Doorkeeper responds to a requests. # # api_only # Enforce token request content type to application/x-www-form-urlencoded. # It is not enabled by default to not break prior versions of the gem. # # enforce_content_type # Authorization Code expiration time (default: 10 minutes). # # authorization_code_expires_in 10.minutes # Access token expiration time (default: 2 hours). # If you want to disable expiration, set this to `nil`. # # access_token_expires_in 2.hours # Assign custom TTL for access tokens. Will be used instead of access_token_expires_in # option if defined. In case the block returns `nil` value Doorkeeper fallbacks to # +access_token_expires_in+ configuration option value. If you really need to issue a # non-expiring access token (which is not recommended) then you need to return # Float::INFINITY from this block. # # `context` has the following properties available: # # `client` - the OAuth client application (see Doorkeeper::OAuth::Client) # `grant_type` - the grant type of the request (see Doorkeeper::OAuth) # `scopes` - the requested scopes (see Doorkeeper::OAuth::Scopes) # # custom_access_token_expires_in do |context| # context.client.application.additional_settings.implicit_oauth_expiration # end # Use a custom class for generating the access token. # See https://doorkeeper.gitbook.io/guides/configuration/other-configurations#custom-access-token-generator # # access_token_generator '::Doorkeeper::JWT' # The controller +Doorkeeper::ApplicationController+ inherits from. # Defaults to +ActionController::Base+ unless +api_only+ is set, which changes the default to # +ActionController::API+. The return value of this option must be a stringified class name. # See https://doorkeeper.gitbook.io/guides/configuration/other-configurations#custom-base-controller # base_controller 'ApplicationController' # Reuse access token for the same resource owner within an application (disabled by default). # # This option protects your application from creating new tokens before old valid one becomes # expired so your database doesn't bloat. Keep in mind that when this option is `on` Doorkeeper # doesn't updates existing token expiration time, it will create a new token instead. # Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/383 # # You can not enable this option together with +hash_token_secrets+. # # reuse_access_token # In case you enabled `reuse_access_token` option Doorkeeper will try to find matching # token using `matching_token_for` Access Token API that searches for valid records # in batches in order not to pollute the memory with all the database records. By default # Doorkeeper uses batch size of 10 000 records. You can increase or decrease this value # depending on your needs and server capabilities. # # token_lookup_batch_size 10_000 # Set a limit for token_reuse if using reuse_access_token option # # This option limits token_reusability to some extent. # If not set then access_token will be reused unless it expires. # Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/1189 # # This option should be a percentage(i.e. (0,100]) # # token_reuse_limit 100 # Only allow one valid access token obtained via client credentials # per client. If a new access token is obtained before the old one # expired, the old one gets revoked (disabled by default) # # When enabling this option, make sure that you do not expect multiple processes # using the same credentials at the same time (e.g. web servers spanning # multiple machines and/or processes). # # revoke_previous_client_credentials_token # Hash access and refresh tokens before persisting them. # This will disable the possibility to use +reuse_access_token+ # since plain values can no longer be retrieved. # # Note: If you are already a user of doorkeeper and have existing tokens # in your installation, they will be invalid without enabling the additional # setting `fallback_to_plain_secrets` below. # # hash_token_secrets # By default, token secrets will be hashed using the # +Doorkeeper::Hashing::SHA256+ strategy. # # If you wish to use another hashing implementation, you can override # this strategy as follows: # # hash_token_secrets using: '::Doorkeeper::Hashing::MyCustomHashImpl' # # Keep in mind that changing the hashing function will invalidate all existing # secrets, if there are any. # Hash application secrets before persisting them. # # hash_application_secrets # # By default, applications will be hashed # with the +Doorkeeper::SecretStoring::SHA256+ strategy. # # If you wish to use bcrypt for application secret hashing, uncomment # this line instead: # hash_application_secrets using: '::Doorkeeper::SecretStoring::BCrypt' # When the above option is enabled, and a hashed token or secret is not found, # you can allow to fall back to another strategy. For users upgrading # doorkeeper and wishing to enable hashing, you will probably want to enable # the fallback to plain tokens. # # This will ensure that old access tokens and secrets # will remain valid even if the hashing above is enabled. # # fallback_to_plain_secrets # Issue access tokens with refresh token (disabled by default), you may also # pass a block which accepts `context` to customize when to give a refresh # token or not. Similar to +custom_access_token_expires_in+, `context` has # the following properties: # # `client` - the OAuth client application (see Doorkeeper::OAuth::Client) # `grant_type` - the grant type of the request (see Doorkeeper::OAuth) # `scopes` - the requested scopes (see Doorkeeper::OAuth::Scopes) # # use_refresh_token # Provide support for an owner to be assigned to each registered application (disabled by default) # Optional parameter confirmation: true (default: false) if you want to enforce ownership of # a registered application # NOTE: you must also run the rails g doorkeeper:application_owner generator # to provide the necessary support # enable_application_owner confirmation: true # Define access token scopes for your provider # For more information go to # https://doorkeeper.gitbook.io/guides/ruby-on-rails/scopes # default_scopes :read optional_scopes :write # Allows to restrict only certain scopes for grant_type. # By default, all the scopes will be available for all the grant types. # # Keys to this hash should be the name of grant_type and # values should be the array of scopes for that grant type. # Note: scopes should be from configured_scopes (i.e. default or optional) # # CUSTOMIZATION NOTE: Implicit grants only allow read access because # they're less secure. scopes_by_grant_type( implicit: [:read], authorization_code: [:read, :write] ) # Forbids creating/updating applications with arbitrary scopes that are # not in configuration, i.e. +default_scopes+ or +optional_scopes+. # (disabled by default) # enforce_configured_scopes # Change the way client credentials are retrieved from the request object. # By default it retrieves first from the `HTTP_AUTHORIZATION` header, then # falls back to the `:client_id` and `:client_secret` params from the `params` object. # Check out https://github.com/doorkeeper-gem/doorkeeper/wiki/Changing-how-clients-are-authenticated # for more information on customization # # client_credentials :from_basic, :from_params # Change the way access token is authenticated from the request object. # By default it retrieves first from the `HTTP_AUTHORIZATION` header, then # falls back to the `:access_token` or `:bearer_token` params from the `params` object. # Check out https://github.com/doorkeeper-gem/doorkeeper/wiki/Changing-how-clients-are-authenticated # for more information on customization # # access_token_methods :from_bearer_authorization, :from_access_token_param, :from_bearer_param # Forces the usage of the HTTPS protocol in non-native redirect uris (enabled # by default in non-development environments). OAuth2 delegates security in # communication to the HTTPS protocol so it is wise to keep this enabled. # # Callable objects such as proc, lambda, block or any object that responds to # #call can be used in order to allow conditional checks (to allow non-SSL # redirects to localhost for example). # force_ssl_in_redirect_uri { |uri| !Rails.env.development? && !Rails.env.test? && uri.host != 'localhost' } # Specify what redirect URI's you want to block during Application creation. # Any redirect URI is whitelisted by default. # # You can use this option in order to forbid URI's with 'javascript' scheme # for example. # # forbid_redirect_uri { |uri| uri.scheme.to_s.downcase == 'javascript' } # Allows to set blank redirect URIs for Applications in case Doorkeeper configured # to use URI-less OAuth grant flows like Client Credentials or Resource Owner # Password Credentials. The option is on by default and checks configured grant # types, but you **need** to manually drop `NOT NULL` constraint from `redirect_uri` # column for `oauth_applications` database table. # # You can completely disable this feature with: # # allow_blank_redirect_uri false # # Or you can define your custom check: # # allow_blank_redirect_uri do |grant_flows, client| # client.superapp? # end # Specify how authorization errors should be handled. # By default, doorkeeper renders json errors when access token # is invalid, expired, revoked or has invalid scopes. # # If you want to render error response yourself (i.e. rescue exceptions), # set +handle_auth_errors+ to `:raise` and rescue Doorkeeper::Errors::InvalidToken # or following specific errors: # # Doorkeeper::Errors::TokenForbidden, Doorkeeper::Errors::TokenExpired, # Doorkeeper::Errors::TokenRevoked, Doorkeeper::Errors::TokenUnknown # # handle_auth_errors :raise # Customize token introspection response. # Allows to add your own fields to default one that are required by the OAuth spec # for the introspection response. It could be `sub`, `aud` and so on. # This configuration option can be a proc, lambda or any Ruby object responds # to `.call` method and result of it's invocation must be a Hash. # # custom_introspection_response do |token, context| # { # "sub": "Z5O3upPC88QrAjx00dis", # "aud": "https://protected.example.net/resource", # "username": User.find(token.resource_owner_id).username # } # end # # or # # custom_introspection_response CustomIntrospectionResponder # Specify what grant flows are enabled in array of Strings. The valid # strings and the flows they enable are: # # "authorization_code" => Authorization Code Grant Flow # "implicit" => Implicit Grant Flow # "password" => Resource Owner Password Credentials Grant Flow # "client_credentials" => Client Credentials Grant Flow # # If not specified, Doorkeeper enables authorization_code and # client_credentials. # # implicit and password grant flows have risks that you should understand # before enabling: # http://tools.ietf.org/html/rfc6819#section-4.4.2 # http://tools.ietf.org/html/rfc6819#section-4.4.3 # grant_flows %w[authorization_code implicit] # Allows to customize OAuth grant flows that +each+ application support. # You can configure a custom block (or use a class respond to `#call`) that must # return `true` in case Application instance supports requested OAuth grant flow # during the authorization request to the server. This configuration +doesn't+ # set flows per application, it only allows to check if application supports # specific grant flow. # # For example you can add an additional database column to `oauth_applications` table, # say `t.array :grant_flows, default: []`, and store allowed grant flows that can # be used with this application there. Then when authorization requested Doorkeeper # will call this block to check if specific Application (passed with client_id and/or # client_secret) is allowed to perform the request for the specific grant type # (authorization, password, client_credentials, etc). # # Example of the block: # # ->(flow, client) { client.grant_flows.include?(flow) } # # In case this option invocation result is `false`, Doorkeeper server returns # :unauthorized_client error and stops the request. # # @param allow_grant_flow_for_client [Proc] Block or any object respond to #call # @return [Boolean] `true` if allow or `false` if forbid the request # # allow_grant_flow_for_client do |grant_flow, client| # # `grant_flows` is an Array column with grant # # flows that application supports # # client.grant_flows.include?(grant_flow) # end # If you need arbitrary Resource Owner-Client authorization you can enable this option # and implement the check your need. Config option must respond to #call and return # true in case resource owner authorized for the specific application or false in other # cases. # # Be default all Resource Owners are authorized to any Client (application). # # authorize_resource_owner_for_client do |client, resource_owner| # resource_owner.admin? || client.owners_whitelist.include?(resource_owner) # end # Hook into the strategies' request & response life-cycle in case your # application needs advanced customization or logging: # # before_successful_strategy_response do |request| # puts "BEFORE HOOK FIRED! #{request}" # end # # after_successful_strategy_response do |request, response| # puts "AFTER HOOK FIRED! #{request}, #{response}" # end # Hook into Authorization flow in order to implement Single Sign Out # or add any other functionality. Inside the block you have an access # to `controller` (authorizations controller instance) and `context` # (Doorkeeper::OAuth::Hooks::Context instance) which provides pre auth # or auth objects with issued token based on hook type (before or after). # # before_successful_authorization do |controller, context| # Rails.logger.info(controller.request.params.inspect) # # Rails.logger.info(context.pre_auth.inspect) # end # # after_successful_authorization do |controller, context| # controller.session[:logout_urls] << # Doorkeeper::Application # .find_by(controller.request.params.slice(:redirect_uri)) # .logout_uri # # Rails.logger.info(context.auth.inspect) # Rails.logger.info(context.issued_token) # end # Under some circumstances you might want to have applications auto-approved, # so that the user skips the authorization step. # For example if dealing with a trusted application. # # skip_authorization do |resource_owner, client| # client.superapp? or resource_owner.admin? # end # Configure custom constraints for the Token Introspection request. # By default this configuration option allows to introspect a token by another # token of the same application, OR to introspect the token that belongs to # authorized client (from authenticated client) OR when token doesn't # belong to any client (public token). Otherwise requester has no access to the # introspection and it will return response as stated in the RFC. # # Block arguments: # # @param token [Doorkeeper::AccessToken] # token to be introspected # # @param authorized_client [Doorkeeper::Application] # authorized client (if request is authorized using Basic auth with # Client Credentials for example) # # @param authorized_token [Doorkeeper::AccessToken] # Bearer token used to authorize the request # # In case the block returns `nil` or `false` introspection responses with 401 status code # when using authorized token to introspect, or you'll get 200 with { "active": false } body # when using authorized client to introspect as stated in the # RFC 7662 section 2.2. Introspection Response. # # Using with caution: # Keep in mind that these three parameters pass to block can be nil as following case: # `authorized_client` is nil if and only if `authorized_token` is present, and vice versa. # `token` will be nil if and only if `authorized_token` is present. # So remember to use `&` or check if it is present before calling method on # them to make sure you doesn't get NoMethodError exception. # # You can define your custom check: # # allow_token_introspection do |token, authorized_client, authorized_token| # if authorized_token # # customize: require `introspection` scope # authorized_token.application == token&.application || # authorized_token.scopes.include?("introspection") # elsif token.application # # `protected_resource` is a new database boolean column, for example # authorized_client == token.application || authorized_client.protected_resource? # else # # public token (when token.application is nil, token doesn't belong to any application) # true # end # end # # Or you can completely disable any token introspection: # # allow_token_introspection false # # If you need to block the request at all, then configure your routes.rb or web-server # like nginx to forbid the request. # WWW-Authenticate Realm (default: "Doorkeeper"). # # realm "Doorkeeper" end ```

Ruby version: 2.7.2

Gemfile.lock:

Gemfile.lock content ``` GIT remote: https://github.com/paper-trail-gem/paper_trail revision: c3c58b739a62100b83ff79762c91f3dbd857761d specs: paper_trail (11.1.0) activerecord (>= 5.2) request_store (~> 1.1) GEM remote: https://rubygems.org/ specs: actioncable (6.1.3) actionpack (= 6.1.3) activesupport (= 6.1.3) nio4r (~> 2.0) websocket-driver (>= 0.6.1) actionmailbox (6.1.3) actionpack (= 6.1.3) activejob (= 6.1.3) activerecord (= 6.1.3) activestorage (= 6.1.3) activesupport (= 6.1.3) mail (>= 2.7.1) actionmailer (6.1.3) actionpack (= 6.1.3) actionview (= 6.1.3) activejob (= 6.1.3) activesupport (= 6.1.3) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) actionpack (6.1.3) actionview (= 6.1.3) activesupport (= 6.1.3) rack (~> 2.0, >= 2.0.9) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) actiontext (6.1.3) actionpack (= 6.1.3) activerecord (= 6.1.3) activestorage (= 6.1.3) activesupport (= 6.1.3) nokogiri (>= 1.8.5) actionview (6.1.3) activesupport (= 6.1.3) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) active_storage_validations (0.9.2) rails (>= 5.2.0) activejob (6.1.3) activesupport (= 6.1.3) globalid (>= 0.3.6) activemodel (6.1.3) activesupport (= 6.1.3) activerecord (6.1.3) activemodel (= 6.1.3) activesupport (= 6.1.3) activestorage (6.1.3) actionpack (= 6.1.3) activejob (= 6.1.3) activerecord (= 6.1.3) activesupport (= 6.1.3) marcel (~> 0.3.1) mimemagic (~> 0.3.2) activesupport (6.1.3) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) zeitwerk (~> 2.3) addressable (2.7.0) public_suffix (>= 2.0.2, < 5.0) ast (2.4.2) aws-eventstream (1.1.1) aws-partitions (1.390.0) aws-sdk-core (3.109.2) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.239.0) aws-sigv4 (~> 1.1) jmespath (~> 1.0) aws-sdk-kms (1.39.0) aws-sdk-core (~> 3, >= 3.109.0) aws-sigv4 (~> 1.1) aws-sdk-s3 (1.83.2) aws-sdk-core (~> 3, >= 3.109.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.1) aws-sigv4 (1.2.3) aws-eventstream (~> 1, >= 1.0.2) bcrypt (3.1.16) better_errors (2.9.1) coderay (>= 1.0.0) erubi (>= 1.0.0) rack (>= 0.9.0) bindex (0.8.1) binding_of_caller (1.0.0) debug_inspector (>= 0.0.1) bootsnap (1.7.2) msgpack (~> 1.0) builder (3.2.4) byebug (11.1.3) capybara (3.35.3) addressable mini_mime (>= 0.1.3) nokogiri (~> 1.8) rack (>= 1.6.0) rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) childprocess (3.0.0) coderay (1.1.3) colorize (0.8.1) commander (4.5.2) highline (~> 2.0.0) concurrent-ruby (1.1.8) connection_pool (2.2.3) crass (1.0.6) database_cleaner (2.0.1) database_cleaner-active_record (~> 2.0.0) database_cleaner-active_record (2.0.0) activerecord (>= 5.a) database_cleaner-core (~> 2.0.0) database_cleaner-core (2.0.1) debug_inspector (1.0.0) devise (4.7.3) bcrypt (~> 3.0) orm_adapter (~> 0.1) railties (>= 4.1.0) responders warden (~> 1.2.3) diff-lcs (1.4.4) docile (1.3.5) doorkeeper (5.5.0) railties (>= 5) dotenv (2.7.6) dotenv-rails (2.7.6) dotenv (= 2.7.6) railties (>= 3.2) ebnf (2.1.2) htmlentities (~> 4.3) rdf (~> 3.1) scanf (~> 1.0) sxp (~> 1.1) erubi (1.10.0) factory_bot (6.1.0) activesupport (>= 5.0.0) factory_bot_rails (6.1.0) factory_bot (~> 6.1.0) railties (>= 5.0.0) faker (2.16.0) i18n (>= 1.6, < 2) faraday (1.3.0) faraday-net_http (~> 1.0) multipart-post (>= 1.2, < 3) ruby2_keywords faraday-net_http (1.0.1) ffi (1.14.2) friendly_id (5.4.2) activerecord (>= 4.0.0) fuubar (2.5.1) rspec-core (~> 3.0) ruby-progressbar (~> 1.4) globalid (0.4.2) activesupport (>= 4.2.0) graphql (1.12.5) graphql-rails_logger (1.2.3) actionpack (> 5.0) activesupport (> 5.0) railties (> 5.0) rouge (~> 3.0) hamster (3.0.0) concurrent-ruby (~> 1.0) highline (2.0.3) htmlentities (4.3.4) i18n (1.8.9) concurrent-ruby (~> 1.0) image_processing (1.12.1) mini_magick (>= 4.9.5, < 5) ruby-vips (>= 2.0.17, < 3) inline_svg (1.7.2) activesupport (>= 3.0) nokogiri (>= 1.6) invisible_captcha (2.0.0) rails (>= 5.0) jbuilder (2.11.2) activesupport (>= 5.0.0) jmespath (1.4.0) kaminari (1.2.1) activesupport (>= 4.1.0) kaminari-actionview (= 1.2.1) kaminari-activerecord (= 1.2.1) kaminari-core (= 1.2.1) kaminari-actionview (1.2.1) actionview kaminari-core (= 1.2.1) kaminari-activerecord (1.2.1) activerecord kaminari-core (= 1.2.1) kaminari-core (1.2.1) launchy (2.5.0) addressable (~> 2.7) link_header (0.0.8) listen (3.4.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) loofah (2.9.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) mini_mime (>= 0.1.1) marcel (0.3.3) mimemagic (~> 0.3.2) method_source (1.0.0) mimemagic (0.3.5) mini_magick (4.11.0) mini_mime (1.0.2) mini_portile2 (2.5.0) minitest (5.14.4) msgpack (1.4.2) multipart-post (2.1.1) net-http-persistent (4.0.1) connection_pool (~> 2.2) nio4r (2.5.7) nokogiri (1.11.1) mini_portile2 (~> 2.5.0) racc (~> 1.4) nokogiri (1.11.1-x86_64-darwin) racc (~> 1.4) nokogiri (1.11.1-x86_64-linux) racc (~> 1.4) orm_adapter (0.5.0) parallel (1.20.1) parlour (6.0.0) commander (~> 4.5) parser rainbow (~> 3.0) sorbet-runtime (>= 0.5) parser (3.0.0.0) ast (~> 2.4.1) pg (1.2.3) pg_search (2.3.5) activerecord (>= 5.2) activesupport (>= 5.2) polyfill (1.9.0) pry (0.14.0) coderay (~> 1.1) method_source (~> 1.0) pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (4.0.6) puma (5.2.2) nio4r (~> 2.0) pundit (2.1.0) activesupport (>= 3.0.0) pundit-matchers (1.6.0) rspec-rails (>= 3.0.0) racc (1.5.2) rack (2.2.3) rack-cors (1.1.1) rack (>= 2.0.0) rack-proxy (0.6.5) rack rack-test (1.1.0) rack (>= 1.0, < 3) rails (6.1.3) actioncable (= 6.1.3) actionmailbox (= 6.1.3) actionmailer (= 6.1.3) actionpack (= 6.1.3) actiontext (= 6.1.3) actionview (= 6.1.3) activejob (= 6.1.3) activemodel (= 6.1.3) activerecord (= 6.1.3) activestorage (= 6.1.3) activesupport (= 6.1.3) bundler (>= 1.15.0) railties (= 6.1.3) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) rails-html-sanitizer (1.3.0) loofah (~> 2.3) railties (6.1.3) actionpack (= 6.1.3) activesupport (= 6.1.3) method_source rake (>= 0.8.7) thor (~> 1.0) rainbow (3.0.0) rake (13.0.3) rb-fsevent (0.10.4) rb-inotify (0.10.1) ffi (~> 1.0) rdf (3.1.12) hamster (~> 3.0) link_header (~> 0.0, >= 0.0.8) rdf-aggregate-repo (3.1.0) rdf (~> 3.1) rdf-xsd (3.1.1) rdf (~> 3.1) rexml (~> 3.2) regexp_parser (2.1.1) request_store (1.5.0) rack (>= 1.4) responders (3.0.1) actionpack (>= 5.0) railties (>= 5.0) rexml (3.2.4) rouge (3.26.0) rspec-core (3.10.1) rspec-support (~> 3.10.0) rspec-expectations (3.10.1) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.10.0) rspec-mocks (3.10.2) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.10.0) rspec-rails (4.0.2) actionpack (>= 4.2) activesupport (>= 4.2) railties (>= 4.2) rspec-core (~> 3.10) rspec-expectations (~> 3.10) rspec-mocks (~> 3.10) rspec-support (~> 3.10) rspec-support (3.10.2) rubocop (1.11.0) parallel (~> 1.10) parser (>= 3.0.0.0) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8, < 3.0) rexml rubocop-ast (>= 1.2.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 1.4.0, < 3.0) rubocop-ast (1.4.1) parser (>= 2.7.1.5) rubocop-performance (1.10.1) rubocop (>= 0.90.0, < 2.0) rubocop-ast (>= 0.4.0) rubocop-rails (2.9.1) activesupport (>= 4.2.0) rack (>= 1.1) rubocop (>= 0.90.0, < 2.0) rubocop-rspec (2.2.0) rubocop (~> 1.0) rubocop-ast (>= 1.1.0) ruby-progressbar (1.11.0) ruby-vips (2.0.17) ffi (~> 1.9) ruby2_keywords (0.0.4) rubyzip (2.3.0) safe_type (1.1.1) scanf (1.0.0) selenium-webdriver (3.142.7) childprocess (>= 0.5, < 4.0) rubyzip (>= 1.2.2) semantic_range (3.0.0) sentry-raven (3.1.1) faraday (>= 1.0) shoulda-matchers (4.5.1) activesupport (>= 4.2.0) simplecov (0.21.2) docile (~> 1.1) simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) simplecov-html (0.12.3) simplecov_json_formatter (0.1.2) sorbet (0.5.6324) sorbet-static (= 0.5.6324) sorbet-coerce (0.3.0) polyfill (~> 1.8) safe_type (~> 1.1, >= 1.1.1) sorbet (>= 0.4.4704) sorbet-runtime (>= 0.4.4704) sorbet-rails (0.7.3) method_source (>= 0.9.2) parlour (>= 4.0.1) parser (>= 2.7) sorbet-coerce (>= 0.2.6) sorbet-runtime (>= 0.5) sorbet-runtime (0.5.6324) sorbet-static (0.5.6324-universal-darwin-14) sorbet-static (0.5.6324-universal-darwin-15) sorbet-static (0.5.6324-universal-darwin-16) sorbet-static (0.5.6324-universal-darwin-17) sorbet-static (0.5.6324-universal-darwin-18) sorbet-static (0.5.6324-universal-darwin-19) sorbet-static (0.5.6324-universal-darwin-20) sorbet-static (0.5.6324-x86_64-linux) sparql (3.1.5) builder (~> 3.2) ebnf (~> 2.1) rdf (~> 3.1, >= 3.1.8) rdf-aggregate-repo (~> 3.1) rdf-xsd (~> 3.1) sparql-client (~> 3.1, >= 3.1.2) sxp (~> 1.1) sparql-client (3.1.2) net-http-persistent (~> 4.0, >= 4.0.1) rdf (~> 3.1) spoom (1.0.9) colorize sorbet (~> 0.5.5) sorbet-runtime thor (>= 0.19.2) spring (2.1.1) spring-watcher-listen (2.0.1) listen (>= 2.7, < 4.0) spring (>= 1.2, < 3.0) sprockets (4.0.2) concurrent-ruby (~> 1.0) rack (> 1, < 3) sprockets-rails (3.2.2) actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) sxp (1.1.0) rdf (~> 3.1) tapioca (0.4.15) bundler (>= 1.17.3) parlour (>= 2.1.0) pry (>= 0.12.2) sorbet-runtime sorbet-static (>= 0.4.4471) spoom thor (>= 0.19.2) thor (1.1.0) turbolinks (5.2.1) turbolinks-source (~> 5.2) turbolinks-source (5.2.0) tzinfo (2.0.4) concurrent-ruby (~> 1.0) unicode-display_width (2.0.0) warden (1.2.9) rack (>= 2.0.9) web-console (4.1.0) actionview (>= 6.0.0) activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) webdrivers (4.6.0) nokogiri (~> 1.6) rubyzip (>= 1.3.0) selenium-webdriver (>= 3.0, < 4.0) webpacker (5.2.1) activesupport (>= 5.2) rack-proxy (>= 0.6.1) railties (>= 5.2) semantic_range (>= 2.3.0) websocket-driver (0.7.3) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) zeitwerk (2.4.2) PLATFORMS ruby x86_64-darwin-18 x86_64-darwin-19 x86_64-darwin-20 x86_64-linux DEPENDENCIES active_storage_validations (~> 0.9.2) addressable (~> 2.7.0) aws-sdk-s3 (~> 1.66) better_errors (~> 2.9) binding_of_caller (~> 1.0) bootsnap (>= 1.1.0) byebug capybara (~> 3.35) database_cleaner (~> 2.0) devise (~> 4.7) doorkeeper (~> 5.5) dotenv-rails (~> 2.7) factory_bot_rails (~> 6.1) faker (~> 2.16) friendly_id (~> 5.4.2) fuubar (~> 2.5.1) graphql (~> 1.12.5) graphql-rails_logger (~> 1.2.3) image_processing (~> 1.12) inline_svg (~> 1.7) invisible_captcha (~> 2.0.0) jbuilder (~> 2.11) kaminari (~> 1.2) launchy (~> 2.5) listen (>= 3.0.5, < 3.5) paper_trail! parallel (~> 1.20) pg (~> 1.2) pg_search (~> 2.3) pry (~> 0.14) pry-rails (~> 0.3) puma (~> 5.2) pundit (~> 2.1) pundit-matchers (~> 1.6.0) rack-cors (~> 1.1) rails (~> 6.1.3) rspec-rails (~> 4.0) rubocop (~> 1.11) rubocop-performance (~> 1.10) rubocop-rails (~> 2.9) rubocop-rspec (~> 2.2) ruby-progressbar (~> 1.11) selenium-webdriver (~> 3.142) sentry-raven (~> 3.1) shoulda-matchers (= 4.5.1) simplecov (~> 0.21) sorbet (~> 0.5) sorbet-rails (~> 0.7) sorbet-runtime (~> 0.5) sparql (~> 3.1.5) spring (~> 2.1) spring-watcher-listen (~> 2.0.0) tapioca (~> 0.4.15) turbolinks (~> 5) web-console (~> 4.1.0) webdrivers (~> 4.6) webpacker (~> 5.2.1) RUBY VERSION ruby 2.7.2p137 BUNDLED WITH 2.2.13 ```
nbulaj commented 3 years ago

Hi @connorshea . This commit uses default Rails technique to lazy load AR models. So nothing specific there. But you can try to change any gem internals locally (like mentioned) to find exact place where something was broken.

I don't know how to help with the issue because there is nothing that Doorkeeper do with AR or any other models :disappointed: Maybe some specific side-effect, but it's hard to say without debug in a buggy env

nbulaj commented 3 years ago

Hi @connorshea . Could you please check your app using gem 'doorkeeper', git: "https://github.com/doorkeeper-gem/doorkeeper.git", branch: "fix-models-autoload" and report if issue still exists?

connorshea commented 3 years ago

@nbulaj unfortunately it did not fix the problem, same error message as before in production 😞

nbulaj commented 3 years ago

Hi @connorshea

I moved some ORM loading code under engine after_initializer , could you please run bundle update for Doorkeeper from the branch I mentioned above and try again? Thanks!

connorshea commented 3 years ago

@nbulaj sadly it did not 😔

Pretty much the same error as before: https://sentry.io/share/issue/c9a168a1c3594eb582005920b4f44935/

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

connorshea commented 3 years ago

It's still a problem, unfortunately.

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

connorshea commented 3 years ago

Still a problem

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

connorshea commented 2 years ago

Still a problem 😔

joeytheman commented 2 years ago

I'm also seeing unexpected behavior when upgrading from Doorkeeper 5.4.0 to 5.5.0 that is related to the change in .lazy_load.

In my tests, I have something similar to


class Tree
# uses doorkeeper
  has_many :apples
end

class Apples
  belongs_to :tree
end

Test

it do
  apple = FactoryBot.create(:apple)
  expect(apple).to be_valid
  apple.tree_id = invalid_id

  expect(apple).to_not be_valid
end

The test above passes on 5.4.0 and fails on 5.5.0. If I change the .lazy_load code back to following in 5.5.0, then the test passes as expected. https://github.com/doorkeeper-gem/doorkeeper/commit/55488ccd9910e0c45ed4342617da8e026f4f55b5

  def self.lazy_load(&block)
        # ActiveSupport has no public interface to check if something
        # already lazy-loaded :(
        loaded = ActiveSupport.instance_variable_get(:"@loaded") || {}

        if loaded.key?(:active_record)
          block.call
        else
          ActiveSupport.on_load(:active_record, {}, &block)
        end
  end
nbulaj commented 2 years ago

@connorshea @joeytheman old lazy_load will be removed in a upcoming release and will be replaced with a Ruby autoload. You can try https://github.com/doorkeeper-gem/doorkeeper/pull/1551 this branch to check if it fixes your issue.

If not - seems like it's not related to lazy_load and requires futher investigation

connorshea commented 2 years ago

@nbulaj I tried deploying 5.6.0.rc1, sadly the problem still occurred :(

connorshea commented 2 years ago

Ok, so I've migrated the Event model for my app away from polymorphism and am using a SQL view now (see https://github.com/connorshea/vglist/pull/2734). And now I've upgraded to 5.5.4 and it works just fine in production. So something about the interaction between polymorphism and Doorkeeper is definitely the problem, but at least in my case I've mitigated the issue (by just removing polymorphism lol) 🤷‍♂️

nbulaj commented 1 year ago

Can we close this issue @connorshea ? There are couple more changes in 5.6.4 related to the Doorkeeper configuration and so on, but I'm not sure you could test it.

connorshea commented 1 year ago

I suppose we can, yeah

nbulaj commented 1 year ago

Let me know please if this issue is still persist, we'll try to figure out what causes it. Thanks