Class: Acta::Railtie

Inherits:
Rails::Railtie
  • Object
show all
Defined in:
lib/acta/railtie.rb

Overview

Forces projection / handler / reactor classes to load at boot, so they can register themselves with Acta before the first event is emitted.

Without this, Zeitwerk lazy-loads them on first reference. A projection that nothing has touched yet is silently unsubscribed — emits succeed, the event row is written, but the projection never runs and the read model goes stale. No error, no warning. See github.com/whoojemaflip/acta/issues/7.

Configurable via ‘config.acta.projection,handler,reactor_paths` if your app puts subscribers somewhere other than the conventional `app/projections`, `app/handlers`, `app/reactors`. Set a path list to `[]` to opt out.

Constant Summary collapse

DEFAULT_PROJECTION_PATHS =
%w[app/projections].freeze
DEFAULT_HANDLER_PATHS =
%w[app/handlers].freeze
DEFAULT_REACTOR_PATHS =
%w[app/reactors].freeze

Class Method Summary collapse

Class Method Details

.eager_load_path(path) ⇒ Object



47
48
49
50
51
52
53
# File 'lib/acta/railtie.rb', line 47

def self.eager_load_path(path)
  if rails_zeitwerk_loader_for(path)&.respond_to?(:eager_load_dir)
    rails_zeitwerk_loader_for(path).eager_load_dir(path)
  else
    Dir.glob(File.join(path, "**/*.rb")).sort.each { |file| require file }
  end
end

.eager_load_subscribers!(app) ⇒ Object



37
38
39
# File 'lib/acta/railtie.rb', line 37

def self.eager_load_subscribers!(app)
  subscriber_paths(app).each { |path| eager_load_path(path) }
end

.subscriber_paths(app) ⇒ Object



41
42
43
44
45
# File 'lib/acta/railtie.rb', line 41

def self.subscriber_paths(app)
  cfg = app.config.acta
  relative = [ *cfg.projection_paths, *cfg.handler_paths, *cfg.reactor_paths ].compact.uniq
  relative.map { |path| app.root.join(path).to_s }.select { |path| Dir.exist?(path) }
end