ActiveRecordの内部的な仕組みを調べてみた

なにこれ

Ruby on RailsにはActive RecordというアプリケーションとDBを繋げるORMが使用できます。

この記事は、Active Recordの内部的な仕組みをコードを見ながら調べていきます。

 

内容

1 Modelの作成 ~ ActiveRecord::Base

Modelクラスの作成からActive Recordを使用するまでの流れを確認します。

user.rb

class User < ApplicationRecord ・・・①
end

①Userクラスを作成するときに、ApplicationRecordを継承しています。

継承元のApplicationRecordは以下のようになっています。

application_record.rb

class ApplicationRecord < ActiveRecord::Base ・・・②
 self.abstract_class = true
end

②ApplicationRecordはActiveRecord::Baseを継承しています。

これが、ActiveRecordの基になります。

 

2 ActiveRecord::Base ~ ActiveRecord::Relation

ActiveRecord::Baseのコードはこちらになります。

https://github.com/rails/rails/blob/b6f4177a6d6361adcb802d5adfb5e1cb46c359fe/activerecord/lib/active_record/base.rb

以下は一部抜粋です。

・
・
・
class Base
  ・
  ・
  ・
    extend Delegation::DelegateCache ・・・①
  ・
  ・
  ・
  end

①extendしているDelegation::DelegateCacheがActiveRecord::Relationを呼び出している部分になります。

Delegation::DelegateCachenのコードはこちらになります。

https://github.com/rails/rails/blob/b6f4177a6d6361adcb802d5adfb5e1cb46c359fe/activerecord/lib/active_record/relation/delegation.rb

以下は一部抜粋です。

・
・
・
module DelegateCache # :nodoc:
    ・
    ・
    ・
      def initialize_relation_delegate_cache
        @relation_delegate_cache = cache = {}
        [
          ActiveRecord::Relation, ・・・②
          ActiveRecord::Associations::CollectionProxy,
          ActiveRecord::AssociationRelation,
          ActiveRecord::DisableJoinsAssociationRelation
        ].each do |klass|
          delegate = Class.new(klass) {
            include ClassSpecificRelation
          }
          include_relation_methods(delegate)
          mangled_name = klass.name.gsub("::", "_")
          const_set mangled_name, delegate ・・・③
          private_constant mangled_name

          cache[klass] = delegate
        end
      end
・
・
・

ActiveRecord::RelationのインスタンスをClassSpecificRelationをincludeした形で作成しています。

③インスタンス名をモデル名::ActiveRecord_Relationのフォーマットで保存しています。

今回の例では、User::ActiveRecord_Relationが作成されます。

つまり、モデルクラスが作成されるタイミングで、モデル名::ActiveRecord_Relationが作成されて、このインスタンスを利用してActiveRecord::Relation内の各メソッドを利用できます。

3 ActiveRecord::Relation

ActiveRecord::Relationのコードはこちらになります。

https://github.com/rails/rails/blob/b6f4177a6d6361adcb802d5adfb5e1cb46c359fe/activerecord/lib/active_record/relation.rb

以下はnewメソッドのコードになります。

    def new(attributes = nil, &block)
      if attributes.is_a?(Array)
        attributes.collect { |attr| new(attr, &block) }
      else
        block = current_scope_restoring_block(&block)
        scoping { _new(attributes, &block) }
      end
    end

findメソッドなど一部のメソッドは外部のファイルに分けられて、includeされています。

 

このように、ActiveRecordを利用してモデルクラスを作成した場合は、内部でActiveRecord::Relationを利用して各メソッドを使用していることが分かりました。

以上!!!!!!!!!!

 

参考

https://qiita.com/yukihirop/items/92802b862e483d00505e