active-interaction-coder について
Rails のビジネス操作を型付きの ActiveInteraction クラスとして構成するコーディングスキルです。入力宣言、検証、合成、`.run` または `.run!` による実行、テストを扱います。
主な機能
- 01型付き操作入力
- 02標準的な Rails バリデーション
- 03合成可能なインタラクション
- 04`.run` と `.run!` による実行
- 05インタラクションのテストパターン
活用シーン
- 01ユーザー登録操作の実装
- 02複数のビジネス操作の合成
- 03有効な入力を使った操作のテスト
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ majesticlabs-dev/ majestic-marketplace --skill active-interaction-coderインストール後、Claude Code で/active-interaction-coderを入力して読み込まれたか確認します。
詳細
ActiveInteraction コーダー
サービスオブジェクトに代わる、型付けされたビジネスオペレーションです。
サービスオブジェクトではなく ActiveInteraction を選ぶ理由
| サービスオブジェクト | ActiveInteraction |
|---|---|
| 標準的なインターフェースがない | 一貫した .run / .run! |
| 型チェックを手動で行う | 型宣言を標準搭載 |
| バリデーションを手動で行う | Rails の標準バリデーション |
| 合成が難しい | ネイティブな合成 |
| 冗長な定型コード | 簡潔で、自己文書化されたコード |
セットアップ
# Gemfile
gem "active_interaction", "~> 5.3"
シンプルなインタラクション
# app/interactions/users/create.rb
module Users
class Create < ActiveInteraction::Base
# Typed inputs
string :email
string :name
string :password, default: nil
# Validations
validates :email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
validates :name, presence: true
# Main logic
def execute
user = User.create!(
email: email,
name: name,
password: password || SecureRandom.alphanumeric(32)
)
UserMailer.welcome(user).deliver_later
user # Return value becomes outcome.result
end
end
end
インタラクションの実行
# In controller
def create
outcome = Users::Create.run(
email: params[:email],
name: params[:name]
)
if outcome.valid?
redirect_to outcome.result, notice: "User created"
else
@errors = outcome.errors
render :new, status: :unprocessable_entity
end
end
# With bang method (raises on error)
user = Users::Create.run!(email: "[email protected]", name: "John")
入力型
class MyInteraction < ActiveInteraction::Base
# Primitives
string :name
integer :age
float :price
boolean :active
symbol :status
# Date/Time
date :birthday
time :created_at
date_time :scheduled_at
# Complex types
array :tags
hash :metadata
# Model instances
object :user, class: User
# Typed arrays
array :emails, default: [] do
string
end
# Optional with default
string :optional_field, default: nil
integer :count, default: 0
end
インタラクションの合成
module Users
class Register < ActiveInteraction::Base
string :email, :name, :password
def execute
# Compose calls another interaction
user = compose(Users::Create,
email: email,
name: name,
password: password
)
# Errors automatically merged if nested fails
compose(Users::SendWelcomeEmail, user: user)
user
end
end
end
コントローラーパターン
class ArticlesController < ApplicationController
def create
outcome = Articles::Create.run(
title: params[:article][:title],
body: params[:article][:body],
author: current_user
)
if outcome.valid?
redirect_to article_path(outcome.result), notice: "Article created"
else
@article = Article.new(article_params)
@article.errors.merge!(outcome.errors)
render :new, status: :unprocessable_entity
end
end
end
インタラクションのテスト
RSpec.describe Users::Create do
let(:valid_params) { { email: "[email protected]", name: "John" } }
it "creates user with valid inputs" do
expect { described_class.run(valid_params) }
.to change(User, :count).by(1)
end
it "returns valid outcome" do
outcome = described_class.run(valid_params)
expect(outcome).to be_valid
expect(outcome.result).to be_a(User)
end
it "validates email format" do
outcome = described_class.run(valid_params.merge(email: "invalid"))
expect(outcome).not_to be_valid
expect(outcome.errors[:email]).to be_present
end
end
高度なパターン
合成、エラー処理、カスタム型については、次を参照してください。
references/active-interaction.md
コメント
Markdown 対応