LoginSignup
3
3

More than 5 years have passed since last update.

ActiveRecord では STI をどう実装しているかを調べたメモ

Last updated at Posted at 2017-10-31

コード読むときのメモです。すみません

仕組み

モデルのインスタンスを new するところ

メソッド: ActiveRecord::Inheritance#new

ActiveRecord::Inheritance モジュールにて、レコードに対応するクラス名を取得していて subclass があれば subclass として new を、それ以外だったら普通に ActiveRecord::Base の new をしている

lib/active_record/inheritance.rb#L64-L69
        if subclass && subclass != self
          subclass.new(*args, &block)
        else
          super
        end

クラス名の決定

subclass_from_attributes メソッド内で、レコードの inheritance_column で指定される attributes の値を find_sti_class に渡している

メソッド: ActiveRecord::Inheritance#subclass_from_attributes

lib/active_record/inheritance.rb#L221-L225
            subclass_name = attrs[inheritance_column] || attrs[inheritance_column.to_sym]

            if subclass_name.present?
              find_sti_class(subclass_name)
            end

inheritance_column は ModelSchema で定義していて (ActiveRecord::Base が include している)、 デフォルトでは "type" である

find_sti_class メソッドでは、所謂 type を使って constantize までする。
メソッド: ActiveRecord::Inheritance

lib/active_record/inheritance.rb#L188-L194
        def find_sti_class(type_name)
          type_name = base_class.type_for_attribute(inheritance_column).cast(type_name)
          subclass = begin
            if store_full_sti_class
              ActiveSupport::Dependencies.constantize(type_name)
            else
              compute_type(type_name)

type_name を type_for_attribute で構築し直しているが、type_for_attribute が string じゃないことも一応あるのだろうか...

改造したいときは

カラムを変える

inheritance_column メソッドをオーバーライドすればよいはず

マッピングルールを変える

たとえば一般的なクラス名を string で入れておく使い方じゃなく、何か別の文字列を入れてクラス名にマッピングさせたいときは、 find_sti_class をオーバーライドすることで実現できるらしいです
https://qiita.com/suusan2go/items/6da23826523744a74ba3

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3