rigor-activerecord
ActiveRecordのファインダー呼び出しとリレーション呼び出しを、プロジェクトのdb/schema.rbおよび発見したモデルクラスに対して型付けします。これによりUser.find(1)はUserに、User.where(emial: …)は未知のカラムとしてフラグが立ち、user.postsはチェーンを通じてその要素型を保持します。このプラグインはソースのみを読みます。active_recordを決してロードしないため、RigorはRailsから切り離されたままです。
このプラグインはrigortypeにバンドルされて提供され、別途のインストールは不要です。設定ファイルのplugins:の下で有効化します:
plugins: - rigor-activerecord何をチェックするか
Section titled “何をチェックするか”demo.rb:20:1: info: `User.find` returns User (table: `users`) [plugin.activerecord.model-call]demo.rb:23:1: info: `User.where` (:admin) on table `users` [plugin.activerecord.model-call]
errors_demo.rb:13:1: error: `User.where(emial: ...)` references unknown column `emial` on table `users` (did you mean `:email`?) [plugin.activerecord.unknown-column]errors_demo.rb:25:1: error: `User.find` expects at least 1 argument, got 0 [plugin.activerecord.wrong-arity]| 診断 | 重大度 | ルール |
|---|---|---|
認識されたModel.find/Model.find_by/Model.whereの呼び出し | :info | plugin.activerecord.model-call |
Model.find_by(unknown: ...)/Model.where(unknown: ...) | :error | plugin.activerecord.unknown-column |
引数0個のModel.find | :error | plugin.activerecord.wrong-arity |
db/schema.rbが読み取れない | :warning | plugin.activerecord.load-error |
「もしかして」候補は、解決されたテーブルのカラム名に対するレーベンシュタイン距離≤3を用います。
plugins: - gem: rigor-activerecord config: schema_file: "db/schema.rb" # default model_search_paths: ["app/models"] # default model_base_classes: ["ApplicationRecord", "ActiveRecord::Base"] # default3つのキーはすべて任意です。次のような場合に調整します:
- スキーマが別の場所にある(
schema_file: "shared/db/schema.rb")。 - モデルが標準外のディレクトリにある(
model_search_paths: ["domain/models", "engines/billing/app/models"])。 - ベースクラスがカスタムである(
model_base_classes: ["DbRecord", "ApplicationRecord"])。
何を推論するか
Section titled “何を推論するか”このプラグインは診断に加えて、呼び出し箇所の型も提供します。クラス側: User.find(1) → User、User.find_by(...) → User | nil、User.find_by!(...) → 非nullableのUser。インスタンス側: カラムの読み取り(user.name)はそのカラムの値型にナローイングされ、user.admin?はboolに、単数の関連(post.user)はターゲットモデルにナローイングされます。
リレーションを返す呼び出し箇所 ── User.where(...)、User.all、User.order(...)、has_many/has_and_belongs_to_manyのアクセサ(user.posts)、ユーザー宣言のscope(Post.published)── はActiveRecord::Relation[Model]にナローイングされます。チェーンされたクエリメソッドは要素型を保持し、イテレーション(user.posts.each { |p| ... })はモデルを生み出します。型付きリレーションに対して呼び出されたユーザー定義のスコープ(User.where(...).published)が、誤ったcall.undefined-methodを表面化させることはありません。
- 直接のスーパークラスのみマッチ。
User < ApplicationRecordである状況下でのclass Admin < Userは発見されません。Userをmodel_base_classesに追加するか、すべての具体的なモデルを明示的に列挙してください。 db/schema.rbのみ。db/structure.sql(生のSQLダンプ)はこのイテレーションではサポートされていません。- カラムの読み取りであり、セッターではない。このプラグインはインスタンス側のカラムの読み取り(
user.name、user.admin?)と単数の関連を型付けしますが、name=セッターやダーティトラッキング系(name_changed?、name_was、…)は型付けしません。 - プロジェクト独自のインフレクションはまだ読み取られない。モデル↔テーブルの複数形化は本物のActiveSupportインフレクターを通ります(そのため
Person → people、Mouse → miceは解決されます)が、config/initializers/inflections.rbで宣言したルールはまだ取り込まれません ── それに依存するモデルにはself.table_nameが必要です(ADR-39スライス3)。
プラグインの内部
Section titled “プラグインの内部”アーキテクチャ(キャッシュされたスキーマパーサ → モデルインデックス → アナライザーのチェーン)、ソースのレイアウト、デモの実行方法、そしてこのプラグインが行使するプラグインの契約(contract)サーフェスは、プラグインのREADMEに記載されています。自分自身のプラグインを書くには、examples/のウォークスルーとrigor-plugin-authorスキルを参照してください。
© 2026 TypedDuck. Licensed under CC BY-SA 4.0.