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 railtie.rb file:
require 'bulma_form/helpers'
module BulmaForm
class Railtie < Rails::Railtie
initializer 'bulma_form.helpers' do |_app|
ActionView::Base.send :include, Helpers
# ActiveSupport.on_load(:action_view) do |_app|
# include Helpers
# end
end
end
end
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:
require 'bulma_form/helpers'
module BulmaForm
class Railtie < Rails::Railtie
config.to_prepare do
ActionView::Helpers.send :include, Helpers
end
end
end
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.
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.
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 lib:
module BulmaForm
require 'bulma_form_rails/railtie' if defined?(Rails)
end
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?
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
Bundler.require(*Rails.groups)
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
p 1
end
end
anywhere in config/application.rb, you’ll see the initializer running.
Ah, I think I understand. No initializer will run if it’s created afterRails.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 config/initializers/application_init.rb:
require 'bulma_form_rails'
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.