Vendored Engines
Custom functionality is added to Scanner via vendored Rails Engines — standard Rails Engine gems placed in the engines/ directory. This pattern lets you extend Scanner without modifying core files, making upgrades straightforward.
Engine Structure
engines/
└── my_engine/
├── my_engine.gemspec
├── lib/
│ ├── my_engine.rb # Engine entry point
│ └── my_engine/
│ └── engine.rb # Rails::Engine subclass
├── app/
│ ├── controllers/
│ ├── models/
│ └── views/
├── config/
│ └── initializers/
└── spec/
Creating an Engine
1. Create the Engine Directory
mkdir -p engines/my_engine/lib/my_engine
mkdir -p engines/my_engine/app/{controllers,models,views}
2. Create the Gemspec
engines/my_engine/my_engine.gemspec
Gem::Specification.new do |s|
s.name = "my_engine"
s.version = "0.1.0"
s.summary = "My Scanner extension"
s.files = Dir["{app,config,lib}/**/*"]
s.add_dependency "rails"
end
3. Create the Engine Class
engines/my_engine/lib/my_engine/engine.rb
module MyEngine
class Engine < ::Rails::Engine
isolate_namespace MyEngine
initializer "my_engine.configure_scanner" do
Scanner.configure do |config|
config.probe_access_class = MyEngine::ProbeAccess
end
BrandConfig.configure do |config|
config.brand_name = "My Company Scanner"
end
ProbeSourceRegistry.register(MyEngine::ProbeSource)
Scanner.register_hook(:after_report_process) do |context|
MyEngine::ReportExporter.export(context[:report])
end
end
end
end
4. Create the Entry Point
engines/my_engine/lib/my_engine.rb
require "my_engine/engine"
5. Register in Gemfile
Gemfile
gem "my_engine", path: "engines/my_engine"
Overriding Views
Place view files in your engine's app/views/ directory with the same path as the core view to override it:
engines/my_engine/app/views/
└── layouts/
└── application.html.erb # Overrides the main layout
Rails loads engine views alongside the main app — engine views take precedence for the paths they define.
Adding Routes
engines/my_engine/config/routes.rb
MyEngine::Engine.routes.draw do
get "/custom-page", to: "custom#index"
end
Mount the engine in the main app's routes:
config/routes.rb
mount MyEngine::Engine, at: "/my-engine"
Adding Migrations
Engine migrations live in the engine's db/migrate/ directory. Install them:
rails my_engine:install:migrations
rails db:migrate
Concerns Pattern
Engines can inject behavior into core models and controllers via concerns:
engines/my_engine/app/models/concerns/my_engine/target_extension.rb
module MyEngine
module TargetExtension
extend ActiveSupport::Concern
included do
has_many :custom_records, dependent: :destroy
end
end
end
engines/my_engine/lib/my_engine/engine.rb
initializer "my_engine.extend_models" do
ActiveSupport.on_load(:active_record) do
Target.include MyEngine::TargetExtension
end
end