Skip to content
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

Rails custom inflection support #81

Closed
nicolas-brousse opened this issue May 21, 2021 · 7 comments
Closed

Rails custom inflection support #81

nicolas-brousse opened this issue May 21, 2021 · 7 comments
Assignees

Comments

@nicolas-brousse
Copy link

What did you do?

I've a config file in Rails application that follow an inflection acronym.

# config/initializers/inflections.rb

ActiveSupport::Inflector.inflections do |inflect|
  inflect.acronym "API"
end
# config/configs/payzen_api_config.rb

class PayzenAPIConfig < ApplicationConfig
  env_prefix :payzen_api
  attr_config :username, :password, :public_key, :sha256key
end

What did you expect to happen?

Code works and load correctly.

What actually happened?

I've got the following error.

expected file /home/user/Projects/rails_app/config/configs/payzen_api_config.rb to define constant PayzenApiConfig, but didn't

Additional context

I suspect eager load not to use rails loader or not the rails inflector.
https://github.com/palkan/anyway_config/blob/master/lib/anyway/railtie.rb#L16

Environment

Ruby Version: ruby 2.7.3p183 (2021-04-05 revision 6847ee089d) [x86_64-linux]

Framework Version (Rails, whatever): Rails 6.0.3.7

Anyway Config Version: 2.1.0

@palkan
Copy link
Owner

palkan commented May 24, 2021

We do use Rails inflector:

loader.inflector = ActiveSupport::Dependencies::ZeitwerkIntegration::Inflector

Can you show me the full backtrace? I guess, that could happen when you try to load the config class before the inflector initializer is loaded.

@palkan palkan added the awaiting response Awaiting reporter's response label May 24, 2021
@nicolas-brousse
Copy link
Author

@palkan thanks for your answer. I'll have a look on it an may try to create a sample application that have the same issue.

@nicolas-brousse
Copy link
Author

nicolas-brousse commented May 24, 2021

I try to reproduce it on a rails template but I can't reproduce the issue.

In my application, I've the following full backtrace on page loading:

Backtrace
zeitwerk (2.4.2) lib/zeitwerk/loader/callbacks.rb:18:in `on_file_autoloaded'
zeitwerk (2.4.2) lib/zeitwerk/kernel.rb:27:in `block in require'
zeitwerk (2.4.2) lib/zeitwerk/kernel.rb:26:in `tap'
zeitwerk (2.4.2) lib/zeitwerk/kernel.rb:26:in `require'
lib/pay_zen.rb:22:in `public_key'
app/helpers/payment_helper.rb:8:in `block in payzen_headers'
actionview (6.0.3.7) lib/action_view/helpers/capture_helper.rb:45:in `block in capture'
actionview (6.0.3.7) lib/action_view/helpers/capture_helper.rb:209:in `with_output_buffer'
actionview (6.0.3.7) lib/action_view/helpers/capture_helper.rb:45:in `capture'
actionview (6.0.3.7) lib/action_view/helpers/capture_helper.rb:176:in `provide'
app/helpers/payment_helper.rb:7:in `payzen_headers'
app/views/carts/payments/new.html.slim:1
actionview (6.0.3.7) lib/action_view/base.rb:274:in `_run'
actionview (6.0.3.7) lib/action_view/template.rb:185:in `block in render'
activesupport (6.0.3.7) lib/active_support/notifications.rb:180:in `block in instrument'
activesupport (6.0.3.7) lib/active_support/notifications/instrumenter.rb:24:in `instrument'
sentry-rails (4.3.4) lib/sentry/rails/tracing.rb:41:in `instrument'
activesupport (6.0.3.7) lib/active_support/notifications.rb:180:in `instrument'
actionview (6.0.3.7) lib/action_view/template.rb:385:in `instrument_render_template'
actionview (6.0.3.7) lib/action_view/template.rb:183:in `render'
actionview (6.0.3.7) lib/action_view/renderer/template_renderer.rb:58:in `block (2 levels) in render_template'
actionview (6.0.3.7) lib/action_view/renderer/abstract_renderer.rb:88:in `block in instrument'
activesupport (6.0.3.7) lib/active_support/notifications.rb:180:in `block in instrument'
activesupport (6.0.3.7) lib/active_support/notifications/instrumenter.rb:24:in `instrument'
sentry-rails (4.3.4) lib/sentry/rails/tracing.rb:41:in `instrument'
activesupport (6.0.3.7) lib/active_support/notifications.rb:180:in `instrument'
actionview (6.0.3.7) lib/action_view/renderer/abstract_renderer.rb:87:in `instrument'
actionview (6.0.3.7) lib/action_view/renderer/template_renderer.rb:57:in `block in render_template'
actionview (6.0.3.7) lib/action_view/renderer/template_renderer.rb:65:in `render_with_layout'
actionview (6.0.3.7) lib/action_view/renderer/template_renderer.rb:56:in `render_template'
actionview (6.0.3.7) lib/action_view/renderer/template_renderer.rb:13:in `render'
actionview (6.0.3.7) lib/action_view/renderer/renderer.rb:61:in `render_template_to_object'
actionview (6.0.3.7) lib/action_view/renderer/renderer.rb:29:in `render_to_object'
actionview (6.0.3.7) lib/action_view/rendering.rb:117:in `block in _render_template'
actionview (6.0.3.7) lib/action_view/base.rb:304:in `in_rendering_context'
actionview (6.0.3.7) lib/action_view/rendering.rb:116:in `_render_template'
actionpack (6.0.3.7) lib/action_controller/metal/streaming.rb:218:in `_render_template'
actionview (6.0.3.7) lib/action_view/rendering.rb:103:in `render_to_body'
actionpack (6.0.3.7) lib/action_controller/metal/rendering.rb:52:in `render_to_body'
actionpack (6.0.3.7) lib/action_controller/metal/renderers.rb:142:in `render_to_body'
actionpack (6.0.3.7) lib/abstract_controller/rendering.rb:25:in `render'
actionpack (6.0.3.7) lib/action_controller/metal/rendering.rb:36:in `render'
actionpack (6.0.3.7) lib/action_controller/metal/instrumentation.rb:44:in `block (2 levels) in render'
activesupport (6.0.3.7) lib/active_support/core_ext/benchmark.rb:14:in `block in ms'
/home/n.brousse/.rbenv/versions/2.7.3/lib/ruby/2.7.0/benchmark.rb:308:in `realtime'
activesupport (6.0.3.7) lib/active_support/core_ext/benchmark.rb:14:in `ms'
actionpack (6.0.3.7) lib/action_controller/metal/instrumentation.rb:44:in `block in render'
actionpack (6.0.3.7) lib/action_controller/metal/instrumentation.rb:84:in `cleanup_view_runtime'
activerecord (6.0.3.7) lib/active_record/railties/controller_runtime.rb:34:in `cleanup_view_runtime'
actionpack (6.0.3.7) lib/action_controller/metal/instrumentation.rb:43:in `render'
view_component (2.31.1) lib/view_component/rendering_monkey_patch.rb:9:in `render'
actionpack (6.0.3.7) lib/action_controller/metal/implicit_render.rb:35:in `default_render'
actionpack (6.0.3.7) lib/action_controller/metal/basic_implicit_render.rb:6:in `block in send_action'
actionpack (6.0.3.7) lib/action_controller/metal/basic_implicit_render.rb:6:in `tap'
actionpack (6.0.3.7) lib/action_controller/metal/basic_implicit_render.rb:6:in `send_action'
actionpack (6.0.3.7) lib/abstract_controller/base.rb:195:in `process_action'
actionpack (6.0.3.7) lib/action_controller/metal/rendering.rb:30:in `process_action'
actionpack (6.0.3.7) lib/abstract_controller/callbacks.rb:42:in `block in process_action'
activesupport (6.0.3.7) lib/active_support/callbacks.rb:112:in `block in run_callbacks'
app/controllers/concerns/localization.rb:36:in `block in set_locale'
i18n (1.8.10) lib/i18n.rb:314:in `with_locale'
app/controllers/concerns/localization.rb:33:in `set_locale'
activesupport (6.0.3.7) lib/active_support/callbacks.rb:121:in `block in run_callbacks'
activesupport (6.0.3.7) lib/active_support/callbacks.rb:139:in `run_callbacks'
actionpack (6.0.3.7) lib/abstract_controller/callbacks.rb:41:in `process_action'
actionpack (6.0.3.7) lib/action_controller/metal/rescue.rb:22:in `process_action'
actionpack (6.0.3.7) lib/action_controller/metal/instrumentation.rb:33:in `block in process_action'
activesupport (6.0.3.7) lib/active_support/notifications.rb:180:in `block in instrument'
activesupport (6.0.3.7) lib/active_support/notifications/instrumenter.rb:24:in `instrument'
sentry-rails (4.3.4) lib/sentry/rails/tracing.rb:41:in `instrument'
activesupport (6.0.3.7) lib/active_support/notifications.rb:180:in `instrument'
actionpack (6.0.3.7) lib/action_controller/metal/instrumentation.rb:32:in `process_action'
actionpack (6.0.3.7) lib/action_controller/metal/params_wrapper.rb:245:in `process_action'
activerecord (6.0.3.7) lib/active_record/railties/controller_runtime.rb:27:in `process_action'
actionpack (6.0.3.7) lib/abstract_controller/base.rb:136:in `process'
actionview (6.0.3.7) lib/action_view/rendering.rb:39:in `process'
actionpack (6.0.3.7) lib/action_controller/metal.rb:190:in `dispatch'
actionpack (6.0.3.7) lib/action_controller/metal.rb:254:in `dispatch'
actionpack (6.0.3.7) lib/action_dispatch/routing/route_set.rb:50:in `dispatch'
actionpack (6.0.3.7) lib/action_dispatch/routing/route_set.rb:33:in `serve'
actionpack (6.0.3.7) lib/action_dispatch/journey/router.rb:49:in `block in serve'
actionpack (6.0.3.7) lib/action_dispatch/journey/router.rb:32:in `each'
actionpack (6.0.3.7) lib/action_dispatch/journey/router.rb:32:in `serve'
actionpack (6.0.3.7) lib/action_dispatch/routing/route_set.rb:834:in `call'
sentry-rails (4.3.4) lib/sentry/rails/rescued_exception_interceptor.rb:12:in `call'
http_accept_language (2.1.1) lib/http_accept_language/middleware.rb:14:in `call'
bullet (6.1.0) lib/bullet/rack.rb:15:in `call'
rack (2.2.3) lib/rack/tempfile_reaper.rb:15:in `call'
rack (2.2.3) lib/rack/etag.rb:27:in `call'
rack (2.2.3) lib/rack/conditional_get.rb:27:in `call'
rack (2.2.3) lib/rack/head.rb:12:in `call'
actionpack (6.0.3.7) lib/action_dispatch/http/content_security_policy.rb:18:in `call'
rack (2.2.3) lib/rack/session/abstract/id.rb:266:in `context'
rack (2.2.3) lib/rack/session/abstract/id.rb:260:in `call'
actionpack (6.0.3.7) lib/action_dispatch/middleware/cookies.rb:648:in `call'
activerecord (6.0.3.7) lib/active_record/migration.rb:567:in `call'
actionpack (6.0.3.7) lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
activesupport (6.0.3.7) lib/active_support/callbacks.rb:101:in `run_callbacks'
actionpack (6.0.3.7) lib/action_dispatch/middleware/callbacks.rb:26:in `call'
actionpack (6.0.3.7) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (6.0.3.7) lib/action_dispatch/middleware/actionable_exceptions.rb:18:in `call'
actionpack (6.0.3.7) lib/action_dispatch/middleware/debug_exceptions.rb:32:in `call'
web-console (4.1.0) lib/web_console/middleware.rb:132:in `call_app'
web-console (4.1.0) lib/web_console/middleware.rb:28:in `block in call'
web-console (4.1.0) lib/web_console/middleware.rb:17:in `catch'
web-console (4.1.0) lib/web_console/middleware.rb:17:in `call'
actionpack (6.0.3.7) lib/action_dispatch/middleware/show_exceptions.rb:33:in `call'
railties (6.0.3.7) lib/rails/rack/logger.rb:37:in `call_app'
railties (6.0.3.7) lib/rails/rack/logger.rb:26:in `block in call'
activesupport (6.0.3.7) lib/active_support/tagged_logging.rb:80:in `block in tagged'
activesupport (6.0.3.7) lib/active_support/tagged_logging.rb:28:in `tagged'
activesupport (6.0.3.7) lib/active_support/tagged_logging.rb:80:in `tagged'
railties (6.0.3.7) lib/rails/rack/logger.rb:26:in `call'
sprockets-rails (3.2.2) lib/sprockets/rails/quiet_assets.rb:13:in `call'
actionpack (6.0.3.7) lib/action_dispatch/middleware/remote_ip.rb:81:in `call'
request_store (1.5.0) lib/request_store/middleware.rb:19:in `call'
actionpack (6.0.3.7) lib/action_dispatch/middleware/request_id.rb:27:in `call'
rack (2.2.3) lib/rack/method_override.rb:24:in `call'
rack (2.2.3) lib/rack/runtime.rb:22:in `call'
activesupport (6.0.3.7) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call'
actionpack (6.0.3.7) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (6.0.3.7) lib/action_dispatch/middleware/static.rb:126:in `call'
rack (2.2.3) lib/rack/sendfile.rb:110:in `call'
actionpack (6.0.3.7) lib/action_dispatch/middleware/host_authorization.rb:82:in `call'
sentry-ruby-core (4.3.2) lib/sentry/rack/capture_exceptions.rb:23:in `block in call'
sentry-ruby-core (4.3.2) lib/sentry/hub.rb:52:in `with_scope'
sentry-ruby-core (4.3.2) lib/sentry-ruby.rb:147:in `with_scope'
sentry-ruby-core (4.3.2) lib/sentry/rack/capture_exceptions.rb:14:in `call'
rack-mini-profiler (2.3.2) lib/mini_profiler/profiler.rb:384:in `call'
webpacker (5.4.0) lib/webpacker/dev_server_proxy.rb:25:in `perform_request'
rack-proxy (0.6.5) lib/rack/proxy.rb:57:in `call'
railties (6.0.3.7) lib/rails/engine.rb:527:in `call'
puma (5.3.1) lib/puma/configuration.rb:249:in `call'
puma (5.3.1) lib/puma/request.rb:76:in `block in handle_request'
puma (5.3.1) lib/puma/thread_pool.rb:338:in `with_force_shutdown'
puma (5.3.1) lib/puma/request.rb:75:in `handle_request'
puma (5.3.1) lib/puma/server.rb:437:in `process_client'
puma (5.3.1) lib/puma/thread_pool.rb:145:in `block in spawn_thread' 

I've the issue on both webpage and console. On webpage it's on a specific page that call Payzen API, and so call config file to get credentials.

@nicolas-brousse
Copy link
Author

I've inspect the code a bit more.

config.before_configuration do
next if ::Rails.application.initialized?
config.anyway_config.autoload_static_config_path = DEFAULT_CONFIGS_PATH
end

If I'm not wrong, before_configuration execute code before initializers are loaded. I guess this is done to have access to config file in initializers.
But because of this, config/initializers/inflections.rb is not loaded yet.

What I've done to try to understand what the code doing is to put a binding.pry at the end of the following method:

def autoload_static_config_path=(val)
raise "Cannot setup autoloader after application has been initialized" if ::Rails.application.initialized?
return unless ::Rails.root.join(val).exist?
autoloader&.unload
@autoload_static_config_path = val
# See https://github.com/rails/rails/blob/8ab4fd12f18203b83d0f252db96d10731485ff6a/railties/lib/rails/autoloaders.rb#L10
@autoloader = Zeitwerk::Loader.new.tap do |loader|
loader.tag = "anyway.config"
loader.inflector = ActiveSupport::Dependencies::ZeitwerkIntegration::Inflector
loader.push_dir(::Rails.root.join(val))
loader.setup
end
end

And I notice the following:

[4] pry(Anyway::Settings)> @autoloader.autoloads
=> {"/home/user/Projects/rails/config/configs/application_config.rb"=>[Object, :ApplicationConfig],
 "/home/user/Projects/rails/config/configs/payzen_api_config.rb"=>[Object, :PayzenApiConfig]

Seems the class name already defined, before inflection initializers loaded.

@palkan
Copy link
Owner

palkan commented Jun 7, 2021

Thanks for the investigation!

Seems the class name already defined, before inflection initializers loaded.

Yeah, we call loader.setup before initialization. Since the point of this loader is to configure autoload before initialization, we cannot have an access to initializers here.

I suggest configuring inflections in the very beginning of the application boot process, e.g., in your config/application.rb:

require_relative "initializers/inflections"

module MyApp
  class Application < Rails::Application 
    # ...
  end
end

@palkan
Copy link
Owner

palkan commented Jun 7, 2021

Added a note to readme: 883c781

@palkan palkan closed this as completed Jun 7, 2021
@palkan palkan removed awaiting response Awaiting reporter's response investigation required Maybe bug labels Jun 7, 2021
@nicolas-brousse
Copy link
Author

@palkan thank you for the support!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants