Rails 8.1 サポートとマトリクステストの導入

basecamp/activerecord-tenanted

この PR では activerecord‑tenantedRails 8.1 以降を正式にサポートし、Appraisal を用いたマトリクステストと CI の拡張を行うと同時に、Rails 8.1 で不要となるパッチを条件付きで適用するよう変更しています。

背景

Rails 8.1 の正式リリースに合わせてライブラリの最低対象バージョンを更新する必要がありました。従来は >= 8.1.beta という緩やかな制約であったため、ベータ版の挙動に依存したコードが残り、将来的な互換性リスクが残っていました。また、テストは単一の Rails バージョンで実行されていたため、他バージョンでの破壊的変更を検出しにくい状態でした。

マトリクステストを導入することで、複数バージョンでの動作保証を自動化し、CI での回帰検知を強化します。Appraisal を利用すれば Gemfile の組み合わせ管理が容易になり、バージョン追加時の手間が削減されます。

この背景から、テスト基盤と依存バージョンの見直しが本 PR の主目的となります。

技術的な変更

GitHub Actions のワークフローにマトリクスジョブを追加し、各 Rails バージョン用 Gemfile を動的に列挙してテストを実行できるようになりました。

jobs:
  rails_versions:
    runs-on: ubuntu-latest
    outputs:
      gemfiles: ${{ steps.gemfiles.outputs.gemfiles }}
    steps:
      - uses: actions/checkout@v5
      - id: gemfiles
        run: echo "gemfiles=$(ruby -rjson -e 'puts Dir[\"gemfiles/*.gemfile\"].map { |f| File.basename(f, \".gemfile\") }.sort.to_json')" >> "$GITHUB_OUTPUT"
unit:
  name: "unit (${{ matrix.gemfile }})"
  needs: rails_versions
  strategy:
    fail-fast: false
    matrix:
      gemfile: ${{ fromJSON(needs.rails_versions.outputs.gemfiles) }}
  continue-on-error: ${{ matrix.gemfile == 'rails_edge' }}
  env:
    BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile

Appraisal の設定を追加し、rails-8-1rails-edge の二つのプロファイルを定義しました。これによりローカルでも bundle exec appraisal rails-8-1 bin/test-unit のように単体または全体のテストを簡単に走らせられます。

# Appraisals
appraise "rails-8-1" do
  gem "rails", "~> 8.1.0"
end

appraise "rails-edge" do
  gem "rails", github: "rails/rails", branch: "main"
end

Gemfile と gemspec の依存バージョンを更新し、rails のエッジバージョンをオプションで取得できるようにすると同時に、activerecordrailties の最低要件を >= 8.1.0 に変更しました。Appraisal 用の appraisal gem と minitest のバージョン制約も明示しています。

# Gemfile (抜粋)
 gem "rails", github: "rails/rails", branch: "main"
 gem "appraisal", "2.5.0", require: false
 gem "minitest", "< 6"
# activerecord-tenanted.gemspec (抜粋)
 rails_requirement = ">= 8.1.0"
 spec.add_dependency "activerecord", rails_requirement
 spec.add_dependency "railties", rails_requirement

ActiveRecord::Tenanted::Patches::Attributes に条件付きパッチ適用ロジックを組み込み、Rails 8.1 以降では不要な monkey‑patch を自動的にスキップします。needs_patch? がバージョン要件を評価し、apply_patch が必要なら prepend を実行します。

module Attributes
  class << self
    def needs_patch?
      Gem::Requirement.new("~> 8.1.0").satisfied_by?(Gem::Version.new(Rails::VERSION::STRING))
    end

    def apply_patch
      ActiveRecord::Base.prepend(self) if needs_patch?
    end
  end
end

Railtie の初期化コードを変更し、apply_patch を呼び出すことで条件付きにしました。これによりRails 8.1 以降で余計なモジュールが読み込まれなくなります。

initializer "active_record_tenanted.monkey_patches" do
  ActiveSupport.on_load(:active_record) do
    ActiveRecord::Tenanted::Patches::Attributes.apply_patch
    ActiveRecord::Tasks::DatabaseTasks.prepend ActiveRecord::Tenanted::Patches::DatabaseTasks
  end
end

テストスクリプトとヘルパーに環境対応を追加し、bin/test-integrationENV["BUNDLE_GEMFILE"] を参照して正しい Gemfile を使用できるようにしました。また、テストヘルパーは実行時に Rails バージョンを出力し、マトリクス実行時の可視性を向上させています。

# bin/test-integration (抜粋)
GEMFILE = File.expand_path(ENV["BUNDLE_GEMFILE"] || File.join(GEM_PATH, "Gemfile"))
puts "Testing against Rails #{Rails.version}"

これらの変更により、マトリクステストの自動化と不要パッチの除去が同時に実現され、コードベースは将来の Rails バージョンに対しても堅牢になります。

設計判断

条件付きパッチ適用とテストマトリクスの外部化という二本柱の設計方針が採用され、既存インターフェースへの破壊的変更を避けつつ拡張性を確保しました。

Appraisal を中心に Gemfile を管理することで、バージョン追加時の設定変更は gemfiles/*.gemfileAppraisals の記述だけで完結し、CI でも自動的に検出されます。これにより手動でマトリクスを更新するリスクが減少します。

条件付きパッチロジックは Rails バージョン判定に依存し、将来的に Rails 本体が同様の変更を取り込んだ場合でもコードが自動的に無効化されるため、メンテナンスコストが低減します。

まとめ

Rails 8.1 以降の正式サポートとマトリクステストの導入により、activerecord‑tenanted は複数バージョンでの動作保証が自動化され、不要な monkey‑patch が除去されてコードベースがシンプルになりました。今後新しい Rails リリースが出ても、Appraisal と CI マトリクスを更新するだけで検証が可能になる点が大きな利点です。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
170a55cb

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文がタイトル直下にあり、背景・技術的変更・設計判断・まとめの各セクションが揃っている。まとめはリード文の単なる繰り返しではなく、変更の意義を再提示している。

カスタムMarkdown構文 ⚠ WARNING

シンタックスハイライト・GitHubリンク記法の正確性

コードブロックは言語指定のみでファイル名が付与されていないが、ファイル名指定が必須ではない。GitHubリンクは "[PR #303](URL)" と記載されており、推奨の "[#303](URL)" 形式と若干異なるため警告。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

対象は Rails/ActiveRecord の開発者向けで、専門用語や実装詳細が中心。初心者向けの過度な説明はなく、適切なレベルです。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションは『総論→各論→結論』の流れになっており、段落はトピックセンテンスで始まり1トピックに絞られている。段落長も6文以内で適切に改行が入っている。

Diff内容との照合 ⚠ WARNING

コードブロックとDiff内容の一致

主要なコード変更は Diff と一致しているが、GitHub Actions の `rails_versions` ジョブにおける `permissions:` ブロックや checkout のコミットハッシュ等が記事に省略されている。内容的に重要ではないが、完全な差分再現とは言い切れないため警告。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「マトリクステスト」「条件付きパッチ適用」などの用語は PR の記述と合致しており、誤用は見られない。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

技術的な説明は Diff と PR Description に裏付けられており、因果関係も正しく記述されている。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事内の全ての主張は PR のタイトル、説明、Diff に基づいており、根拠のない推測や外部情報は含まれていない。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR 番号 (#303) やバージョン番号 (>= 8.1.0, ~> 8.1.0) などは正確に記載されている。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事タイトルは PR の「Rails 8.1 support」を的確に日本語化し、マトリクステストの導入も内容に即している。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

LTS やリリーススケジュール等、PR に記載されていない外部知識は一切記述されていない。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

時間表現の記載はなく、PR の記述と矛盾する表現もない。