ActiveRecord Association 覚え書き

概要
=====

ActiveRecord の Association 周りの理解が曖昧。
整理のためにまとめておこうと思います。
随時加筆予定。

外部キーをどう持つか（子）
=====

User -(1:N)- Order な関係を考える。
Order が User の id を外部キーとして持つ場合、
子である Order の実装方法として以下の 3 パターンが考えられる。

| Pattern | DB column name    | association name |
|-----------|------------|------------|
| パターン C1   | user_id | user    |
| パターン C2   | customer_id | customer    |
| パターン C3   | user_id | customer    |

パターン C1
-----

一番素直なパターン。楽。
`user_id` というカラムを持ち、
関連の名前も素直に `user` とするパターン。

```20140623060050_create_orders.rb
def change
  create_table :orders do |t|
    t.belongs_to :user, index:true
    ...
  end
end
```

```models/order.rb
class Order < ActiveRecord::Base
  belongs_to :user
  ...
end
```

パターン C2
-----

関連性を表すことのできる、直感的な名前を付けたいパターン。
`customer_id` というカラムを持ち、
関連の名前も `customer` とする。

class_name を指定する必要がある。

```20140623060050_create_orders.rb
def change
  create_table :orders do |t|
    t.belongs_to :customer, index:true
    ...
  end
end
```

```models/order.rb
class Order < ActiveRecord::Base
  belongs_to :customer, class_name: "User"
  ...
end
```

パターン C3
-----

関連性を表すために直感的な名前を付けたいパターンその２。
しかし、カラム名は `user_id` とし、
アプリから関連を辿る際には `customer` を利用する。
（あんまりないかも）

class_name および foreign_key を指定してやる必要がある。

```20140623060050_create_orders.rb
def change
  create_table :orders do |t|
    t.belongs_to :user, index:true
    ...
  end
end
```

```models/order.rb
class Order < ActiveRecord::Base
  belongs_to :customer, class_name: "User", foreign_key: "user_id"
  ...
end
```

子との関連をどう設定するか（親）
=====

先ほどと同様に、User -(1:N)- Order な関係を考える。
親である User の関連付けの命名方法として以下の 2 パターンが考えられる。

| Pattern | association name |
|-----------|------------|
| パターン P1   | orders |
| パターン P2   | transactions |


パターン P1
-----

関連の名前を素直に子のモデル名の複数形とする素直なパターン。

```models/user.rb
class User < ActiveRecord::Base
  has_many :orders
  ...
end
```


パターン P2
-----

関連の名前を子のモデル名とはベツモノにするパターン。

class_name を指定する必要がある。

```models/user.rb
class User < ActiveRecord::Base
  has_many :transactions, class_name: 'Order'
  ...
end
```



ちょっとややこしいケース
=====

パターン C2 とパターン P2 を同時にする場合。
つまり、親への外部キー名を（親のモデル名ではない）独自のものにし、
かつ、子との関連名を（子のモデル名ではない）独自のものに設定したい場合。

親に foreign_key を設定してやる必要がある。


```20140623060050_create_orders.rb
def change
  create_table :orders do |t|
    t.belongs_to :customer, index:true
    ...
  end
end
```

```models/order.rb
class Order < ActiveRecord::Base
  belongs_to :customer, class_name: "User"
  ...
end
```

```models/user.rb
class User < ActiveRecord::Base
  has_many :transactions, class_name: 'Order', foreign_key: 'customer_id'
  ...
end
```


inverse_of
=====

TODO

foreign_key
=====

belongs_to の場合
-----

デフォルトでは Rails は外部キーとして **関連名_id** を想定している。
DB のカラム名が **関連名_id** となっていない場合はちゃんと指定してあげること。
（あんまりないと思う）

例: （上記 パターン C3 より）

```models/order.rb
class Order < ActiveRecord::Base
  # デフォルトでは customer_id を利用しようとするので
  # user_id を使うよう foreign_key を明示する
  belongs_to :customer, class_name: "User", foreign_key: "user_id"
  ...
end
```


has_many の場合
-----

デフォルトでは Rails は外部キーとして **自モデル名_id** を想定している。
DB のカラム名が **自モデル名_id** となっていない場合はちゃんと指定してあげること。


```models/order.rb
class Order < ActiveRecord::Base
  belongs_to :customer, class_name: "User"
  ...
end
```

```models/user.rb
class User < ActiveRecord::Base
  # デフォルトでは user_id を利用しようとするので
  # ちゃんと指定してやる
  has_many :transactions, class_name: 'Order', foreign_key: 'customer_id'
  ...
end
```


foreign_key を適切に設定していない場合、
以下のようなケースでエラーとなりうる。

```rb
# エラーが発生する
#     ActiveRecord::UnknownAttributeError:
#       unknown attribute: user_id
user.transactions.build(order_param)
```