はじめに
現在アプリ制作を行っています。作成したER図を元にメンバーの方がmodelを作成してくださったのですが、コードレビューする際に知らないオプションがありなにこれ?となったため、いい機会だと思いどんなオプションがあるのかを調べてみました。
アソシエーションとは?
アソシエーションとはモデル間の関連付けのことで、簡単に言うと2つ以上のテーブルの関係性を定義することです。
関係性を定義することで、複数のテーブルにまたがるデータを簡単に取り出せるようになります。
前提
- 今回の記事では、以下3つのテーブルがあるときの関係性を例に考えてみます。
Users | Communities | Documents |
---|---|---|
id | id | id |
name | name | title |
body | ||
owner_id | ||
writer_id |
テーブル同士の関係性
1. UsersとCommunitiesの関係 (多対多)
- 1人のユーザーは複数のコミュニティに属す。
- コミュニティには複数のユーザーが含まれる。
2. UserとDocumentsの関係 (1:多)
- 1人のユーザーは複数のドキュメントを持つ。
- ドキュメントは1人のユーザーが書いたものである。
3. CommunitiesとDocuments
- 割愛
以上のように3つのテーブル間には1対多
もしくは多対多
の関係が成り立つことが分かり、この関係を踏まえた上で作成したER図が下記になります。
- UsersテーブルとCommunitiesテーブルは多対多となるため中間テーブルを用意します。
- Documentsは書いた人(writer)と所有する人(Owner)を分けるためにidを分けてます。
以上の前提条件を踏まえた上でこれからアソシエーションを定義していきましょう。
アソシエーションの定義方法
まず、基本的なアソシエーションの定義方法は以下になります。
belongs_to
- 関連するテーブルに属することを表す
- 1つのデータを割り当てる(下記の例なら一人のユーザと一つのコミュニティを紐付ける)
class CommunityUser < ApplicationRecord
belongs_to :user
belongs_to :community
end
-
has_many
- 複数データを参照する
- 1対多の関係を表す
class User < ApplicationRecord
has_many :documents
end
ユーザーは複数ドキュメントのデータを参照できる
-
has_many :through
- 多対多の関係を表す
-
through
で定義した中間テーブルを通して直接、相手側のテーブルにアクセスできる
class User < ApplicationRecord
has_many :communities, through: :community_users
end
以上はよく使うアソシエーション定義方法だと思いますが、次からはアソシエーションに用意されているオプションを紹介していきます。
アソシエーションのオプション
class_nameオプション
一つのモデルに対して違う名前で値を取り出したい時に使う。
class User < ApplicationRecord
has_many :documents,
has_many :have_documents, class_name: "Document", as: :owner
end
以上のようにすることで、documents
ではすべてのドキュメントを取り出し、have_documents
ではDocumentsテーブルのowner_idを持ったドキュメントのみを取り出せるようになります。
dependentオプション
あるモデルを削除した際の関連するモデルに対する挙動を定義する。
-
dependent: :destroy
- 関連付けしているモデルも一緒に削除する
- ActiveRecordを介して関連付けの数だけDELETEが実行される
class User < ApplicationRecord
has_many :community_users, dependent: :destroy
end
以上のようにすることでUserが削除された際に、紐づくCummunity_userも一緒に削除される。
-
dependent: :delete_all
- 直接SQLを発行してDELETEを1回だけ実行する
-
dependent: :nullify
- 関連付けしているモデルは削除しない
class User < ApplicationRecord
has_many :documents, dependent: :nullify
end
これでユーザーが削除されてもユーザーの作成したドキュメントは一緒には削除されません。
foreign_key
- 参照先テーブルの外部キーのカラム名を明示
inverse_of
- どちらのモデルからでもインスタンスを参照できるようにする
class User < ApplicationRecord
has_many :documents, foreign_key: :writer_id, inverse_of: "writer"
end
以上のようにすることで自分の書いたドキュメントで有ることがわかりやすくなる。
参考記事
おわりに
まだ理解が怪しい所もあるため、間違いなどご指摘や、他にもこんなオプションあるよなど教えて頂けると嬉しいです。