概要
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
とするパターン。
def change
create_table :orders do |t|
t.belongs_to :user, index:true
...
end
end
class Order < ActiveRecord::Base
belongs_to :user
...
end
パターン C2
関連性を表すことのできる、直感的な名前を付けたいパターン。
customer_id
というカラムを持ち、
関連の名前も customer
とする。
class_name を指定する必要がある。
def change
create_table :orders do |t|
t.belongs_to :customer, index:true
...
end
end
class Order < ActiveRecord::Base
belongs_to :customer, class_name: "User"
...
end
パターン C3
関連性を表すために直感的な名前を付けたいパターンその2。
しかし、カラム名は user_id
とし、
アプリから関連を辿る際には customer
を利用する。
(あんまりないかも)
class_name および foreign_key を指定してやる必要がある。
def change
create_table :orders do |t|
t.belongs_to :user, index:true
...
end
end
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
関連の名前を素直に子のモデル名の複数形とする素直なパターン。
class User < ActiveRecord::Base
has_many :orders
...
end
パターン P2
関連の名前を子のモデル名とはベツモノにするパターン。
class_name を指定する必要がある。
class User < ActiveRecord::Base
has_many :transactions, class_name: 'Order'
...
end
ちょっとややこしいケース
パターン C2 とパターン P2 を同時にする場合。
つまり、親への外部キー名を(親のモデル名ではない)独自のものにし、
かつ、子との関連名を(子のモデル名ではない)独自のものに設定したい場合。
親に foreign_key を設定してやる必要がある。
def change
create_table :orders do |t|
t.belongs_to :customer, index:true
...
end
end
class Order < ActiveRecord::Base
belongs_to :customer, class_name: "User"
...
end
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 より)
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 となっていない場合はちゃんと指定してあげること。
class Order < ActiveRecord::Base
belongs_to :customer, class_name: "User"
...
end
class User < ActiveRecord::Base
# デフォルトでは user_id を利用しようとするので
# ちゃんと指定してやる
has_many :transactions, class_name: 'Order', foreign_key: 'customer_id'
...
end
foreign_key を適切に設定していない場合、
以下のようなケースでエラーとなりうる。
# エラーが発生する
# ActiveRecord::UnknownAttributeError:
# unknown attribute: user_id
user.transactions.build(order_param)