mcpField
R
rails-conventions

rails-conventions

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

rails-conventions について

Rails アプリケーションの開発・保守向けに、コードとテストの規約をまとめています。シンプルでテストしやすい構成を重視し、コントローラー、サービスオブジェクト、Turbo Streams、JavaScript の読み込み、性能を扱います。

主な機能

  1. 01コントローラーとモデルの責務指針
  2. 02サービスオブジェクトの抽出ルール
  3. 03インライン Turbo Streams のパターン
  4. 04Minitest とフィクスチャによるテスト
  5. 05importmap による JavaScript 読み込み管理
  6. 06性能と命名の指針

活用シーン

  1. 01Rails のコントローラーと業務ロジックの整理
  2. 02サービスオブジェクトを抽出する判断
  3. 03フィクスチャと外部依存のスタブによる動作テスト
  4. 04公開用と管理用の JavaScript 依存関係の分離

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/majesticlabs-dev/majestic-marketplace --skill rails-conventions

インストール後、Claude Code で/rails-conventionsを入力して読み込まれたか確認します。

詳細

Rails の規約

クリーンで保守しやすいコードを書くための、明確な方針に基づく Rails のパターンです。

基本理念

  1. 複雑さより重複を選ぶ:複雑な DRY 抽象化より、シンプルなコードの重複を選びます

    • 「複雑なコントローラーが 3 つあるより、シンプルなコントローラーが 4 つあるほうがよいです」
  2. テスト容易性 = 品質:テストが難しい場合は、構造をリファクタリングする必要があります

  3. コントローラーを追加するのは問題ありません。コントローラーを複雑にするのは問題です。

Turbo Streams

シンプルな Turbo Streams は必ずコントローラー内に直接記述します。

# FAIL: Separate .turbo_stream.erb files for simple operations
render "posts/update"

# PASS: Inline array
render turbo_stream: [
  turbo_stream.replace("post_#{@post.id}", partial: "posts/post", locals: { post: @post }),
  turbo_stream.remove("flash")
]

コントローラーと Concerns

ビジネスロジックはコントローラーではなく、モデルまたは Concern に記述します。

# Concern structure
module Dispatchable
  extend ActiveSupport::Concern

  included do
    scope :available, -> { where(status: "pending") }
  end

  class_methods do
    def claim!(batch_size)
      # class-level behavior
    end
  end
end

サービスへの切り出し

次の項目が複数当てはまる場合に切り出します:

  • 複雑なビジネスルール(単に「長い」だけではない)
  • 複数のモデルを連携させる
  • 外部 API とのやり取り
  • 複数のコントローラーで再利用するロジック

サービスの構成:

  • 公開メソッドは 1 つ
  • 責務ごとに名前空間を分ける(Extraction::RegexExtractor)
  • コンストラクターで依存関係を受け取る
  • ドメインオブジェクトではなく、データ構造を返す

モダンな Ruby のスタイル

# Hash shorthand
{ id:, slug:, doc_type: kind }

# Safe navigation
created_at&.iso8601
@setting ||= SlugSetting.active.find_by!(slug:)

# Keyword arguments
def extract(document_type:, subject:, filename:)
def process!(strategy: nil)

Enum のパターン

# Frozen arrays with validation
STATUSES = %w[processed needs_review].freeze
enum :status, STATUSES.index_by(&:itself), validate: true

スコープのパターン

# Guard with .present?, chainable design
scope :by_slug, ->(slug) { where(slug:) if slug.present? }
scope :from_date, ->(date) { where(created_at: Date.parse(date).beginning_of_day..) if date.present? }

def self.filtered(params)
  all.by_slug(params[:slug]).by_kind(params[:kind])
rescue ArgumentError
  all
end

エラーハンドリング

# Domain-specific errors
class InactiveSlug < StandardError; end

# Log with context, re-raise for upstream
def handle_exception!(error:)
  log_error("Exception #{error.class}: #{error.message}", error:)
  mark_failed!(error.message)
  raise
end

テスト(Minitest + フィクスチャ)

test "describes expected behavior" do
  email = emails(:two)
  email.process
  email.reload
  assert_equal "finished", email.processing_status
end

原則:

  • 振る舞い駆動:方法ではなく、何をするかをテストします
  • フィクスチャベース:セットアップには emails(:two) を使用します
  • 外部依存をモック化:S3、API、PDF をスタブします
  • 状態を検証:操作後に .reload を実行します
  • ヘルパーメソッド:build_valid_email、with_stubbed_download

命名(5 秒ルール)

5 秒で理解できない場合:

# FAIL
show_in_frame
process_stuff

# PASS
fact_check_modal
_fact_frame

JavaScript と Importmap

Rails 7+ では、JS の依存関係管理に Importmap を使用します。依存関係のスコープは、最も限定的なエントリーポイントにします。

複数のエントリーポイント
# config/importmap.rb
pin "application"                    # Public entrypoint
pin "@hotwired/turbo-rails", to: "turbo.min.js"
pin "@hotwired/stimulus", to: "stimulus.min.js"

# Admin-only dependencies - pinned but only imported in admin entrypoint
pin "chartkick", to: "chartkick.js"
pin "Chart.bundle", to: "Chart.bundle.js"
// app/javascript/application.js — public pages only
import "@hotwired/turbo-rails"
import "@hotwired/stimulus"
import "controllers"

// app/javascript/admin.js — imports public base + admin-only libs
import "application"
import "chartkick"
import "Chart.bundle"
<%# Admin layout %>
<%= javascript_importmap_tags("admin") %>

<%# All other layouts %>
<%= javascript_importmap_tags %>
新しい JS 依存関係の追加
  1. スコープを確認します:一般ユーザー向けか、管理者専用か?
  2. config/importmap.rb で Pin します
  3. 正しいエントリーポイントでインポートします
  4. 管理者専用ライブラリを application.js に追加してはいけません

パフォーマンス

  • 規模が与える影響を考慮します
  • 時期尚早なキャッシュは避けます
  • KISS — シンプルに保ちます
  • インデックスは書き込みを遅くするため、必要な場合にのみ追加します

コメント