I’m trying to reorganize some view helper methods and corresponding ERb templates in preparation for packaging as a gem. So I moved the helper logic into
lib/bulma_form, and created the following
class Railtie < Rails::Railtie
initializer 'bulma_form.helpers' do |_app|
ActionView::Base.send :include, Helpers
# ActiveSupport.on_load(:action_view) do |_app|
# include Helpers
I can see that on Rails startup or test execution, the initializer method is executed properly, but the specified block is never invoked. As anyone can see, I’ve been experimenting with different logic within the block, but I imagine that’s irrelevant since it’s never executed anyway. What am I doing wrong?
I just found a way that works, though I don’t know if it’s considered the right or best way:
class Railtie < Rails::Railtie
ActionView::Helpers.send :include, Helpers
I think you might have missed the
group in your first attempt:
initializer 'bulma_form.helpers', group: :all do |_app|
As for the second, another option is:
config.after_initialize do |app|
Thanks Breno! I can’t find anything about the
group option to
initializer in the API docs, but the
config.after_initialize method seems to work just fine.
Yeah, I only know about group because I checked the source code of other Rails gems to see how they handled this.
Without testing it myself, I’d say your first snippet should work as you expect. And there, the
on_load variant is more correct that the uncommented one.
When does the application load the railtie?
Yeah, I kinda wondered whether an official initializer via
on_load would be the more kosher option, if I could get it to work. I load the railtie from this file in
require 'bulma_form_rails/railtie' if defined?(Rails)
I originally loaded this via an explicit
require, but now that I’ve moved everything into a gem, the Gemfile takes care of that. And interestingly, the
on_load syntax now works just fine.
So something is different about initializing from a gem that makes the kosher way work?
The key point is when is the railtie defined during the boot process. Whether that is in a gem or not does not matter. Let me explain.
One of the first files executed when Rails boots is config/environment.rb:
As you see, that loads config/application.rb and executes
Rails.application.initialize!, which is responsible for booting the application. As part of that process, the initializers of railties and engines are executed, but as you see, they have to be known at that point! If you load them later, the time is gone.
Since config/application.rb has this line
the entrypoints of the gems declared in the
Gemfile are required (mod
require: false). Typically, those entrypoints load the corresponding railtie in most gems like yours, and when
initialize! runs, all is set to be run as expected.
If your code is in
lib, as you can see the initializers will run as long as the file is loaded in config/application.rb. For example, if you throw:
class MyRailtie < Rails::Railtie
initializer "my_railtie" do
anywhere in config/application.rb, you’ll see the initializer running.
Ah, I think I understand. No initializer will run if it’s created after
Rails.application.initialize! is executed. I must’ve done something like that in my earlier attempts.
I just looked at my repo history, and I see that I had the following line in
So that’s where I was defining the railtie. Doesn’t that mean I was trying to define an initializer from another that was already running? Is that too late in the process?
Running the application initializers that exist in config/initializers is one of the things the
initialize! method does. Indeed, that is too late to define a railtie.
Makes perfect sense. Thanks for jumping into the conversation!