mcpField
A
active-interaction-coder

active-interaction-coder

github.com/majesticlabs-dev開発5062 回インストール7 週間前に更新
リポジトリ

active-interaction-coder について

Rails のビジネス操作を型付きの ActiveInteraction クラスとして構成するコーディングスキルです。入力宣言、検証、合成、`.run` または `.run!` による実行、テストを扱います。

主な機能

  1. 01型付き操作入力
  2. 02標準的な Rails バリデーション
  3. 03合成可能なインタラクション
  4. 04`.run` と `.run!` による実行
  5. 05インタラクションのテストパターン

活用シーン

  1. 01ユーザー登録操作の実装
  2. 02複数のビジネス操作の合成
  3. 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

コメント