ActiveRecordのassociationをmodule内のモデルで使う

# 概要
先日の仕事中、module内にあるActive Recordのモデルに対してassociationを作成しようとしたときに少し苦戦したので、その経緯をまとめます。
やり方だけ知りたい方は[結論](#結論)へどうぞ。

# 経緯
## 前提
次のような３つのモデルを作成し、`Buzz`が`Fizz::Foo`、`Fizz::Foo`が`Fizz::Bar`をそれぞれ`has_many`で持つようにしたい。

`app/models/fizz.rb`

```
module Fizz
  def self.table_name_prefix
    'fizz_'
  end
end
```

`app/models/buzz.rb`

```
class Buzz < ApplicationRecord
end
```

`app/models/fizz/bar.rb`

```
class Fizz::Bar < ApplicationRecord
end

```

`app/models/fizz/foo.rb`

```
class Fizz::Foo < ApplicationRecord
end
```

## 試したこと１ - テーブル名と同じprefixをつけて`has_many`で指定する
まず最初に、テーブル名と同じprefixである`fizz_`を`has_many`で指定してみました。

`app/models/buzz.rb`

```
class Buzz < ApplicationRecord
  has_many :fizz_foos
end
```

`app/models/fizz/bar.rb`

```
class Fizz::Bar < ApplicationRecord
  belongs_to :fizz_foo
end

```

`app/models/fizz/foo.rb`

```
class Fizz::Foo < ApplicationRecord
  has_many :fizz_bars
  belongs_to :buzz
end
```

### 結果
|メソッド|結果||
|---|---|---|
|`Buzz.first.fizz_foos`|`NameError (uninitialized constant Buzz::FizzFoo)`が発生|×|
|`Fizz::Foo.first.fizz_bars`|`NameError (uninitialized constant Fizz::Foo::FizzBar)`が発生|×|
|`Fizz::Foo.first.buzz`|`#<Buzz id: 1, created_at: "2019-12-11 14:40:32", updated_at: "2019-12-11 14:40:32">`|○|
|`Fizz::Bar.first.fizz_foo`|`nil`|×|

`Fizz::Foo.first.buzz`のときしか正しく関係先が取得できなかった。

## 試したこと2 - prefixを外す
moduleに無いモデル同士のときは、並列のモデルが解決できているのに、1.では`uninitialized constant Fizz::Foo::FizzBar`と`親モデル`::`has_manyで指定した名前`となっている。
それを元に考えると、同じmodule内のモデル同士であればprefixがなくても解決できるのではと思い、試してみました。

`app/models/buzz.rb`

```
class Buzz < ApplicationRecord
  has_many :fizz_foos
end
```

`app/models/fizz/bar.rb`

```
class Fizz::Bar < ApplicationRecord
  belongs_to :foo
end

```

`app/models/fizz/foo.rb`

```
class Fizz::Foo < ApplicationRecord
  has_many :bars
  belongs_to :buzz
end
```

### 結果
|メソッド|結果||
|---|---|---|
|`Buzz.first.fizz_foos`|`NameError (uninitialized constant Buzz::FizzFoo)`が発生|×|
|`Fizz::Foo.first.bars`|`#<ActiveRecord::Associations::CollectionProxy [#<Fizz::Bar id: 1, foo_id: 1, created_at: "2019-12-11 14:43:27", updated_at: "2019-12-11 14:43:27">]>`|○|
|`Fizz::Foo.first.buzz`|`#<Buzz id: 1, created_at: "2019-12-11 14:40:32", updated_at: "2019-12-11 14:40:32">`|○|
|`Fizz::Bar.first.foo`|`#<Fizz::Foo id: 1, buzz_id: 1, created_at: "2019-12-11 14:40:51", updated_at: "2019-12-11 14:40:51">`|○|

`Fizz`モジュール内同士の関係は正しく取れるようになったが、別モジュールからの時はまだエラーが起きている。

## 試したことに3 - `class_name`を使う
下記2つを参考に別モジュールのときに`class_name`を使用するように変更。
https://stackoverflow.com/questions/25715426/rails-associations-with-modules
https://railsguides.jp/association_basics.html

`app/models/buzz.rb`

```
class Buzz < ApplicationRecord
  has_many :fizz_foos, class_name: 'Fizz::Foo'
end
```

`app/models/fizz/bar.rb`

```
class Fizz::Bar < ApplicationRecord
  belongs_to :foo
end

```

`app/models/fizz/foo.rb`

```
class Fizz::Foo < ApplicationRecord
  has_many :bars
  belongs_to :buzz
end
```
### 結果
|メソッド|結果||
|---|---|---|
|`Buzz.first.fizz_foos`|`#<ActiveRecord::Associations::CollectionProxy [#<Fizz::Foo id: 1, buzz_id: 1, created_at: "2019-12-11 14:40:51", updated_at: "2019-12-11 14:40:51">]>`|○|
|`Fizz::Foo.first.bars`|`#<ActiveRecord::Associations::CollectionProxy [#<Fizz::Bar id: 1, foo_id: 1, created_at: "2019-12-11 14:43:27", updated_at: "2019-12-11 14:43:27">]>`|○|
|`Fizz::Foo.first.buzz`|`#<Buzz id: 1, created_at: "2019-12-11 14:40:32", updated_at: "2019-12-11 14:40:32">`|○|
|`Fizz::Bar.first.foo`|`#<Fizz::Foo id: 1, buzz_id: 1, created_at: "2019-12-11 14:40:51", updated_at: "2019-12-11 14:40:51">`|○|

正しく動くようになった！

# 結論
- 同じモジュール内のassociationの時、モジュールがない場合と同様にモジュールを除いたクラス名で作成できる
- 別モジュールのモデル間のassociationの時、`class_name`でモジュールを含めたクラス名を指定する

### ちなみに
そもそも、この記事を書くために再度調べていたら、[Ruby on Rails API](https://api.rubyonrails.org/) にしっかり記載がありました。

> By default, associations will look for objects within the current module scope.

( https://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#module-ActiveRecord::Associations::ClassMethods-label-Modules より引用)