EasyInitHelper registration helpers
EasyInitHelper is the preferred way to register reload-sensitive Easy8 plugin and engine behavior from initializers.
Use it when initialization code touches Redmine registries, Easy registries, or hook listener classes that must keep working after Rails reloads in development. The helpers keep the registration timing explicit and avoid loading constants too early under Zeitwerk.
Helper selection
| Use case | Helper |
|---|---|
| Permissions and project modules | EasyInitHelper.register_access_control_block |
| Redmine menu items | EasyInitHelper.register_menu_block |
Redmine::Hook::ViewListener subclasses |
EasyInitHelper.register_redmine_view_hooks |
Registries owned by lazily loaded constants, for example EasyQuery, Redmine::Search, or Redmine::Activity |
EasyInitHelper.on_constant_autoload |
Permissions
Register access-control entries in config/initializers/01_access_control.rb.
EasyInitHelper.register_access_control_block do
Redmine::AccessControl.map do |map|
map.project_module :my_plugin do |project_module|
project_module.permission :view_my_plugin_entities,
{ my_plugin_entities: [:index] },
read: true
end
end
end
Use this instead of Rails.application.config.after_initialize for new permissions. The block is registered as Rails.application.config.to_prepare, so it runs again after development reloads.
Menus
Register menus in config/initializers/02_menu_manager.rb.
EasyInitHelper.register_menu_block do
Redmine::MenuManager.map :project_menu do |menu|
menu.push :my_plugin_entities,
{ controller: "my_plugin_entities", action: "index" },
caption: :label_my_plugin_entities,
after: :activity,
param: :project_id
end
end
Menu conditions can be evaluated without a project or entity in global contexts. If a menu item uses :if, make the proc tolerate nil where that menu can be rendered globally.
View Hooks
Register Redmine view-hook listener classes by constant name in config/initializers/03_hooks.rb.
The hook class must live in an autoloaded app/ path and follow Zeitwerk naming.
module MyPlugin
class Hooks < Redmine::Hook::ViewListener
render_on :view_issues_show_details_bottom,
partial: "my_plugin/issues/details"
end
end
Do not constantize hook listener classes directly in an initializer. Loading is deferred because constantizing inside a Redmine::Hook::ViewListener load path can fail before the listener constant is fully defined.
Constant-Autoload Registries
Use EasyInitHelper.on_constant_autoload when the registration belongs to a constant that should remain lazy-loaded.
EasyInitHelper.on_constant_autoload("EasyQuery") do
EasyQuery.map do |query|
query.register "MyPluginEntityQuery"
end
end
The helper delegates to Zeitwerk on_load. It also validates that the target constant is autoloadable and raises if the constant is already loaded when the block is registered. That failure means the initializer order is wrong or some earlier code touched the constant too early.
The same pattern is used for other registries:
EasyInitHelper.on_constant_autoload("Redmine::Search") do
Redmine::Search.map do |search|
search.register :my_plugin_entities
end
end
EasyInitHelper.on_constant_autoload("Redmine::Activity") do
Redmine::Activity.map do |activity|
activity.register :my_plugin_entities,
class_name: %w[MyPluginEntity Journal],
default: false
end
end
Avoid For New Code
Do not use these patterns for new reload-sensitive registrations:
Rails.application.config.after_initializefor menus, permissions, hook listeners, or EasyQuery registrationActiveSupport.on_load(:easy_project_start)for new EasyQuery registration- direct constantization of view-hook listener classes in initializers
RedmineExtensions::Reloader.to_prepare, which is no longer supported
Reload Verification
The reload safety net is in spec/lib/reloader_spec.rb. It checks that hooks, menus, permissions, and menu conditions remain stable across repeated Rails.application.reloader.reload! calls.
Run it when changing registration code:
There is also a request smoke test:
Both specs are skipped unless TAGS=reloader is set and Rails reloading is enabled.