BREAKING: Plugin renamed from compounding-engineering to compound-engineering. Users will need to reinstall with the new name: claude /plugin install compound-engineering Changes: - Renamed plugin directory and all references - Updated documentation counts (24 agents, 19 commands) - Added julik-frontend-races-reviewer to docs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
184 lines
3.7 KiB
Markdown
184 lines
3.7 KiB
Markdown
# Rails Integration Patterns
|
|
|
|
## The Golden Rule
|
|
|
|
**Never require Rails gems directly.** This causes loading order issues.
|
|
|
|
```ruby
|
|
# WRONG - causes premature loading
|
|
require "active_record"
|
|
ActiveRecord::Base.include(MyGem::Model)
|
|
|
|
# CORRECT - lazy loading
|
|
ActiveSupport.on_load(:active_record) do
|
|
extend MyGem::Model
|
|
end
|
|
```
|
|
|
|
## ActiveSupport.on_load Hooks
|
|
|
|
Common hooks and their uses:
|
|
|
|
```ruby
|
|
# Models
|
|
ActiveSupport.on_load(:active_record) do
|
|
extend GemName::Model # Add class methods (searchkick, has_encrypted)
|
|
include GemName::Callbacks # Add instance methods
|
|
end
|
|
|
|
# Controllers
|
|
ActiveSupport.on_load(:action_controller) do
|
|
include Ahoy::Controller
|
|
end
|
|
|
|
# Jobs
|
|
ActiveSupport.on_load(:active_job) do
|
|
include GemName::JobExtensions
|
|
end
|
|
|
|
# Mailers
|
|
ActiveSupport.on_load(:action_mailer) do
|
|
include GemName::MailerExtensions
|
|
end
|
|
```
|
|
|
|
## Prepend for Behavior Modification
|
|
|
|
When overriding existing Rails methods:
|
|
|
|
```ruby
|
|
ActiveSupport.on_load(:active_record) do
|
|
ActiveRecord::Migration.prepend(StrongMigrations::Migration)
|
|
ActiveRecord::Migrator.prepend(StrongMigrations::Migrator)
|
|
end
|
|
```
|
|
|
|
## Railtie Pattern
|
|
|
|
Minimal Railtie for non-mountable gems:
|
|
|
|
```ruby
|
|
# lib/gemname/railtie.rb
|
|
module GemName
|
|
class Railtie < Rails::Railtie
|
|
initializer "gemname.configure" do
|
|
ActiveSupport.on_load(:active_record) do
|
|
extend GemName::Model
|
|
end
|
|
end
|
|
|
|
# Optional: Add to controller runtime logging
|
|
initializer "gemname.log_runtime" do
|
|
require_relative "controller_runtime"
|
|
ActiveSupport.on_load(:action_controller) do
|
|
include GemName::ControllerRuntime
|
|
end
|
|
end
|
|
|
|
# Optional: Rake tasks
|
|
rake_tasks do
|
|
load "tasks/gemname.rake"
|
|
end
|
|
end
|
|
end
|
|
```
|
|
|
|
## Engine Pattern (Mountable Gems)
|
|
|
|
For gems with web interfaces (PgHero, Blazer, Ahoy):
|
|
|
|
```ruby
|
|
# lib/pghero/engine.rb
|
|
module PgHero
|
|
class Engine < ::Rails::Engine
|
|
isolate_namespace PgHero
|
|
|
|
initializer "pghero.assets", group: :all do |app|
|
|
if app.config.respond_to?(:assets) && defined?(Sprockets)
|
|
app.config.assets.precompile << "pghero/application.js"
|
|
app.config.assets.precompile << "pghero/application.css"
|
|
end
|
|
end
|
|
|
|
initializer "pghero.config" do
|
|
PgHero.config = Rails.application.config_for(:pghero) rescue {}
|
|
end
|
|
end
|
|
end
|
|
```
|
|
|
|
## Routes for Engines
|
|
|
|
```ruby
|
|
# config/routes.rb (in engine)
|
|
PgHero::Engine.routes.draw do
|
|
root to: "home#index"
|
|
resources :databases, only: [:show]
|
|
end
|
|
```
|
|
|
|
Mount in app:
|
|
|
|
```ruby
|
|
# config/routes.rb (in app)
|
|
mount PgHero::Engine, at: "pghero"
|
|
```
|
|
|
|
## YAML Configuration with ERB
|
|
|
|
For complex gems needing config files:
|
|
|
|
```ruby
|
|
def self.settings
|
|
@settings ||= begin
|
|
path = Rails.root.join("config", "blazer.yml")
|
|
if path.exist?
|
|
YAML.safe_load(ERB.new(File.read(path)).result, aliases: true)
|
|
else
|
|
{}
|
|
end
|
|
end
|
|
end
|
|
```
|
|
|
|
## Generator Pattern
|
|
|
|
```ruby
|
|
# lib/generators/gemname/install_generator.rb
|
|
module GemName
|
|
module Generators
|
|
class InstallGenerator < Rails::Generators::Base
|
|
source_root File.expand_path("templates", __dir__)
|
|
|
|
def copy_initializer
|
|
template "initializer.rb", "config/initializers/gemname.rb"
|
|
end
|
|
|
|
def copy_migration
|
|
migration_template "migration.rb", "db/migrate/create_gemname_tables.rb"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
```
|
|
|
|
## Conditional Feature Detection
|
|
|
|
```ruby
|
|
# Check for specific Rails versions
|
|
if ActiveRecord.version >= Gem::Version.new("7.0")
|
|
# Rails 7+ specific code
|
|
end
|
|
|
|
# Check for optional dependencies
|
|
def self.client
|
|
@client ||= if defined?(OpenSearch::Client)
|
|
OpenSearch::Client.new
|
|
elsif defined?(Elasticsearch::Client)
|
|
Elasticsearch::Client.new
|
|
else
|
|
raise Error, "Install elasticsearch or opensearch-ruby"
|
|
end
|
|
end
|
|
```
|