trailblazer-rails: breaking bug in ApplicationController extending when alias_method is used
We decided to try out Trailblazer in earnest, and immediately hit a blocker issue.
Background
We have an alias
in ApplicationController
that is redefining current_user
to add extra functionality:
alias devise_current_user current_user
def current_user
# ...
end
Issue
When adding trailblazer-rails
to the Gemfile and trying to boot, we get this error:
project_dir/app/controllers/application_controller.rb:27:in `<class:ApplicationController>': undefined method `current_user' for class `ApplicationController' (NameError)
from project_dir/app/controllers/application_controller.rb:26:in `<class:ApplicationController>'
from project_dir/app/controllers/application_controller.rb:1:in `<top (required)>'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:477:in `load'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:477:in `block in load_file'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:662:in `new_constants_in'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:476:in `load_file'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:375:in `block in require_or_load'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:37:in `block in load_interlock'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/dependencies/interlock.rb:12:in `block in loading'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/concurrency/share_lock.rb:150:in `exclusive'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/dependencies/interlock.rb:11:in `loading'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:37:in `load_interlock'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:358:in `require_or_load'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:511:in `load_missing_constant'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:203:in `const_missing'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/inflector/methods.rb:268:in `const_get'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/inflector/methods.rb:268:in `block in constantize'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/inflector/methods.rb:266:in `each'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/inflector/methods.rb:266:in `inject'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/inflector/methods.rb:266:in `constantize'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/core_ext/string/inflections.rb:66:in `constantize'
from ~/.rvm/gems/ruby-2.2.4/gems/trailblazer-rails-1.0.4/lib/trailblazer/rails/railtie.rb:75:in `extend_application_controller!'
from ~/.rvm/gems/ruby-2.2.4/gems/trailblazer-rails-1.0.4/lib/trailblazer/rails/railtie.rb:44:in `block (2 levels) in <class:Railtie>'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/lazy_load_hooks.rb:43:in `instance_eval'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/lazy_load_hooks.rb:43:in `execute_hook'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/lazy_load_hooks.rb:33:in `block in on_load'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/lazy_load_hooks.rb:32:in `each'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/lazy_load_hooks.rb:32:in `on_load'
from ~/.rvm/gems/ruby-2.2.4/gems/trailblazer-rails-1.0.4/lib/trailblazer/rails/railtie.rb:43:in `block in <class:Railtie>'
from ~/.rvm/gems/ruby-2.2.4/gems/railties-5.0.1/lib/rails/initializable.rb:30:in `instance_exec'
from ~/.rvm/gems/ruby-2.2.4/gems/railties-5.0.1/lib/rails/initializable.rb:30:in `run'
from ~/.rvm/gems/ruby-2.2.4/gems/railties-5.0.1/lib/rails/initializable.rb:55:in `block in run_initializers'
from ~/.rvm/rubies/ruby-2.2.4/lib/ruby/2.2.0/tsort.rb:226:in `block in tsort_each'
from ~/.rvm/rubies/ruby-2.2.4/lib/ruby/2.2.0/tsort.rb:348:in `block (2 levels) in each_strongly_connected_component'
from ~/.rvm/rubies/ruby-2.2.4/lib/ruby/2.2.0/tsort.rb:429:in `each_strongly_connected_component_from'
from ~/.rvm/rubies/ruby-2.2.4/lib/ruby/2.2.0/tsort.rb:347:in `block in each_strongly_connected_component'
from ~/.rvm/rubies/ruby-2.2.4/lib/ruby/2.2.0/tsort.rb:345:in `each'
from ~/.rvm/rubies/ruby-2.2.4/lib/ruby/2.2.0/tsort.rb:345:in `call'
from ~/.rvm/rubies/ruby-2.2.4/lib/ruby/2.2.0/tsort.rb:345:in `each_strongly_connected_component'
from ~/.rvm/rubies/ruby-2.2.4/lib/ruby/2.2.0/tsort.rb:224:in `tsort_each'
from ~/.rvm/rubies/ruby-2.2.4/lib/ruby/2.2.0/tsort.rb:203:in `tsort_each'
from ~/.rvm/gems/ruby-2.2.4/gems/railties-5.0.1/lib/rails/initializable.rb:54:in `run_initializers'
from ~/.rvm/gems/ruby-2.2.4/gems/railties-5.0.1/lib/rails/application.rb:352:in `initialize!'
from project_dir/config/environment.rb:5:in `<top (required)>'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:293:in `require'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:293:in `block in require'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:259:in `load_dependency'
from ~/.rvm/gems/ruby-2.2.4/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:293:in `require'
from ~/.rvm/gems/ruby-2.2.4/gems/spring-2.0.2/lib/spring/application.rb:102:in `preload'
from ~/.rvm/gems/ruby-2.2.4/gems/spring-2.0.2/lib/spring/application.rb:153:in `serve'
from ~/.rvm/gems/ruby-2.2.4/gems/spring-2.0.2/lib/spring/application.rb:141:in `block in run'
from ~/.rvm/gems/ruby-2.2.4/gems/spring-2.0.2/lib/spring/application.rb:135:in `loop'
from ~/.rvm/gems/ruby-2.2.4/gems/spring-2.0.2/lib/spring/application.rb:135:in `run'
from ~/.rvm/gems/ruby-2.2.4/gems/spring-2.0.2/lib/spring/application/boot.rb:19:in `<top (required)>'
from ~/.rvm/rubies/ruby-2.2.4/lib/ruby/site_ruby/2.2.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from ~/.rvm/rubies/ruby-2.2.4/lib/ruby/site_ruby/2.2.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from -e:1:in `<main>'
Possible fix?
It appears that the loading system in lib/trailblazer/rails/railtie.rb
isn’t properly extending ApplicationController
. It looks like #11 may have been related, but it is quite out of date.
Attempted fix
If we comment out:
# lib/trailblazer/rails/railtie.rb:41-45
initializer 'trailblazer.application_controller' do |_app|
reloader_class.to_prepare do
# Trailblazer::Railtie.extend_application_controller!(app)
end
end
And manually load the modules:
class ApplicationController < ActionController::Base
include Trailblazer::Rails::Controller
include Trailblazer::Rails::Controller::Cell if defined?(::Cell)
It works fine.
Summary
It looks like when the ApplicationController
class is forced to constantize in extend_application_controller!
, Rails hasn’t fully loaded the class, so the devise current_user
method hasn’t been defined yet.
I would PR this, but I couldn’t find consistent answer online on how this should be properly loaded.
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Comments: 18 (9 by maintainers)
Commits related to this issue
- Hook trailblazer application_controller initializer to finisher_hook , closes #54 — committed to trailblazer/trailblazer-rails by seuros 7 years ago
- Hook trailblazer application_controller initializer to finisher_hook , closes #54 — committed to trailblazer/trailblazer-rails by seuros 7 years ago
- Hook trailblazer application_controller initializer to finisher_hook , closes #54 — committed to trailblazer/trailblazer-rails by seuros 7 years ago
- Hook trailblazer application_controller initializer to finisher_hook , closes #54 — committed to trailblazer/trailblazer-rails by seuros 7 years ago
- Hook trailblazer application_controller initializer to finisher_hook , closes #54 — committed to trailblazer/trailblazer-rails by seuros 7 years ago
@sadjow Really? That happens without spring? Then we should investigate. We don’t have this problem here, are you using anything “crazy”?
And dropped the temperature of the Earth! Move over Al Gore, we’re cloning Genghis Khan to solve climate change.
Rubocop stubbornly complains about
alias_method
, but I did managed to break the law and tryalias_method
instead. I also tried putting it into a module andinclude
-ing, which also didn’t work.I expect that a
prepend
might work, but prepend sucks when you need to call the original method outside of the prepended method (method(:current_user).super_method.call()
), and at that point we’re writing weird code to work around what seems like a library bug (sorry 🤞).Great bug report, I wish everyone could formulate that well and concise.
Maybe a fix could be to add one of the million
:after
options toinitializer 'trailblazer.application_controller'
so this gets executed at the right time? I’m not very savvy on Rails initialization and honestly have no interest in learning more about it, but maybe @seuros knows a solution?By the way, be prepared to hit more immediate blockers with TRB, spring doesn’t play with modern gems like Dry.rb and TRB, and the autoloading mixed with ours can lead to having to require things manually sometimes, etc etc.