class Order < ActiveRecord::Base; end;が実行されると何が起こるのか？


この記事は、2017/09/30(土)に書きました。

## はじめに
**Orderは適当な名前です。なんでもいいです。**
railsを使ったことがあるひとなら、`ActiveRecord::Base` を継承したモデルをつくったことが必ずあると思いますが、モデルを作った時に何が行われているかは普段気にしないとおもいます。だが、その部分を理解することはActiveRecord::Baseを継承したモデルの理解をする上で重要だと思い今回しっかり追ってみました。

```
class Order < ActiveRecord::Base
end
```

これが実行されると何が行われるのか？

**diffを強調のニュアンスで使っています。**

## 動作環境
- rails 5.1.0
- ruby 2.4.1p11

<br>

---



## ActiveRecord::Baseクラスを継承するだけで実行されるメソッドがある？


ActiveRecord::Baseクラスの中でDelegatte::DelegateCacheがextendされている。
[activerecord-5.1.0/lib/active_record/base.rb]

```diff
 class Base
    extend ActiveModel::Naming

    extend ActiveSupport::Benchmarkable
    extend ActiveSupport::DescendantsTracker

    extend ConnectionHandling
    extend QueryCache::ClassMethods
    extend Querying
    extend Translation
    extend DynamicMatchers
    extend Explain
    extend Enum
+   extend Delegate::DelegateCache

```

つまり、`Delegate::DelegateCache`モジュールに定義されているメソッドをクラス・メソッドとして使えるようになる。

<br>


## どのようなメソッドが実行されるの？(inheritedメソッド)

**`Delegate::DelegateCache` モジュールに[rubyの`inherited`メソッド](https://ref.xaio.jp/ruby/classes/class/inherited)がオーバーライドしてある。**

[activerecord-5.1.0/lib/active_record/relation/delegation.rb]

```diff
def inherited(child_class)
+	child_class.initialize_relation_delegate_cache
    delegate = child_class.relation_delegate_class(ActiveRecord::Associations::CollectionProxy)
    delegate.include ActiveRecord::Associations::CollectionProxy::DelegateExtending
    super
end

# child_class => Order
```

child_classはOrderクラスを指している。このメソッドは`child_class.initialize_relation_delegate_cache` が肝。
これは何をするのかというと、 `child_class`が所有しているインスタンス変数`@@relation_delegate_cache`に以下のようなhashを保持する。

```ruby
@relation_delegate_cache = {
	ActiveRecord::Relation                      => Order::ActiveRecord_Relation,
	ActiveRecord::Associations::CollectionProxy => Order::ActiveRecord_Associations_CollectionProxy,
	ActiveRecord::AssociationRelation           => Order::ActiveRecordAssociation
}
```

例えば`Order::ActiveRecord_Relation`はどのようなクラスかというと、

>1. ClassSpecificRelationモジュールの持つメソッドをクラス・メソッドに持つ
>2. ActiveRecord::Relationをsuperclassに持つ

という大事な性質のあるクラスである。


<br>

## 動的に生成されるクラス(Order::ActiveRecord_Relation)がどのように生成されるか？

`child_class.initialize_relation_delegate_cache` が肝だと先程いったのでその中身を見てみると、

[activerecord-5.1.0/lib/active_record/relation/delegation.rb]

```diff
def initialize_relation_delegate_cache
	@relation_delegate_cache = cache = {}
	[
		ActiveRecord::Relation,
       ActiveRecord::Associations::CollectionProxy,
       ActiveRecord::AssociationRelation
    ].each do |klass|
+    	delegate = Class.new(klass) {
+    		include ClassSpecificRelation
+    	}
    	
+    	mangled_name = klass.name.gsub("::".freeze, "_".freeze)
    	
+    	# ここでOrder::ActiveRecord_Relationの中身がdlegateになる
+    	const_set mangled_name, delegate
    	private_constant mangled_name
    	cache[klass] = delegate
    end
end
```

説明すると、klass=ActiveRecord::Relationの時、このクラスを継承してなおかつ、ClassSpecificReflationモジュールをインクルードしたクラスdelegateを動的に生成し、selfがOrderなのでconst_setでdelegateに名前をつけると、
**delegateにOrder::ActiveRecord_Relationという名前がつくわけである。**あとは生成したクラス(Order::ActiveRecord_Relation)をキーがActiveRecord::Relationでhashとしてキャッシュしている。
ActiveRecord::Baseが継承されたときだけ1度だけ行われるメソッドなので使いまわすにはキャッシュしておく必要があるのである。

以上のような仕組みで`Order::ActiveRecord_Relation`クラスが動的に生成される。

ではこのように動的に生成された`Order::ActiveRecord_Relation`クラスはどのように使われるのか？

一例としては、 


**Order.where(id:1)のようにメソッドが呼ばれた時、内部的に`Order::ActiveRecord_Relation`のインスタンス(relation)が生成され、それに対してwhereが実行されるのである。
※Order.whereとrelation.whereのwhereは別物のメソッドである。**


この例は、
[Order.where(name: "name_1", description: "description_1")はどのような順番でメソッドが実行されるのか？]()
で説明します。たぶん。。。。

<br>

## まとめ
`class Order < ActiveRecord::Base; end;` が実行されると、`Order::ActiveRecord_Relation`・`Order::ActiveRecord_Associations_CollectionProxy`・`Order::ActiveRecordAssociation`クラスが動的に生成される。例えば、`Order::ActiveRecord_Relation`クラスのインスタンスは、`Order.where(id:1)` を語る上で重要なインスタンスである。

Orderクラスがこの３つのクラスをインスタンス変数@relation_delegate_cacheに保持している。

・Order::ActiveRecord_Relation
・Order::ActiveRecord_Associations_CollectionProxy
・Order::ActiveRecordAssociation

以上。