ActiveRecord::Base.primary_key が継承可能に
ActiveRecord の primary_key がテーブル名と同様にクラス属性として扱われ、サブクラスへ自動的に継承されるようになりました。これにより抽象クラスや STI でのプライマリキー設定が直感的になります。変更点はコード上の実装とテストの追加で確認できます。
背景
従来、モデルで self.primary_key = ... と上書きしても子クラスはデフォルトのキー(通常 id)を使用していました。抽象クラスで複合キーを定義したり、STI のサブクラスで同一キーを期待するケースでは余計なコードが必要でした。今回の変更は primary_key を class_attribute 化し、親クラスの設定を子クラスが自動的に受け継ぐ設計です。
技術的な変更
activerecord/lib/active_record/attribute_methods/primary_key.rb で primary_key 系メソッドが修正され、内部で保持する定義を @primary_key_definition から self._primary_key_definition に置き換えました。
@@
- @primary_key_definition = ActiveRecord::Key.for(value)
+ self._primary_key_definition = ActiveRecord::Key.for(value)
@@
- @primary_key_definition = nil
+ class_attribute :_primary_key_definition, instance_accessor: false
primary_key の取得は primary_key_definition.name を返すだけにシンプル化し、primary_key_definition は未初期化時に reset_primary_key を呼び出すように変更しました。
@@
- reset_primary_key unless @primary_key_definition
- @primary_key_definition
+ reset_primary_key unless _primary_key_definition
+ _primary_key_definition
inherited フックでは class_attribute :_primary_key_definition, instance_accessor: false を宣言し、サブクラスが親クラスの定義をそのまま受け継げるようにしています。この属性はインスタンスからは直接参照できず、クラスレベルでのみ利用されます。
テスト activerecord/test/cases/primary_keys_test.rb に test_primary_key_inherited が追加され、親クラスで設定した primary_key がサブクラスでも同一であることを検証しています。
class TestPrimaryKeyInheritance < ActiveSupport::TestCase
def test_primary_key_inherited
parent = Class.new(ActiveRecord::Base)
child = Class.new(parent)
parent.primary_key = "foo"
assert_equal "foo", parent.primary_key
assert_equal "foo", child.primary_key
end
end
設計判断
class_attribute を用いることで、既存のインスタンスメソッドやオブジェクト状態に影響を与えずにクラスレベルの共有状態を実現しました。これにより primary_key の設定が CompositePrimaryKey の有無に関わらず安全に継承され、抽象クラスでの複合キー定義や STI のサブクラスでの同一キー利用が自然になります。
変更は primary_key= 時のモジュールインクルードロジック(include CompositePrimaryKey if primary_key_definition.composite?)を保持しつつ、属性名を統一しただけなので後方互換性は完全に保たれます。既存コードが self.primary_key = :id のままで動作し、新たに継承を利用したコードは追加の設定なしで機能します。
まとめ
ActiveRecord::Base.primary_key がクラス属性として継承可能になり、抽象クラスや STI におけるプライマリキー設定が一貫した挙動となりました。実装は class_attribute の導入とメソッドのリファクタリングに留まり、テストで期待通りの継承が保証されています。この変更は Rails アプリケーションのモデル設計をシンプルにし、意図しないキーのずれを防止します。