##概要
モデル同士の繋がりを指すアソシエーション(関連付け)
定義しておくとモデルをまたいだデータの呼び出しが可能になります。
また親と子の関係や、外部キーの設定などを理解していないと、
「親モデルのデータを先に追加しないと子のデータが追加できない。」なんて
DB設計の見直しが起きる可能性も・・
データベースを可視化できるER図はとても大切。学習メモとして残します
##参考
(1)感動の分かりやすさ。ER図の基礎の基礎知識もあり。初心者必見
【初心者向け】丁寧すぎるRails『アソシエーション』チュートリアル【幾ら何でも】【完璧にわかる】
(2) 理解に苦しんだ・・ 中間テーブルってやつです。
【初心者・独学者向け】Ruby on Railsで中間テーブルを作成し、多対多を実現する
親と子の関係
【初心者向け】丁寧すぎるRails『アソシエーション』チュートリアル【幾ら何でも】【完璧にわかる】 がとても分かりやすかったので引用します
モデル同士の親子関係とは
図で考えてみましょう。
Aさん(User)は、自分が作ったブログサイトでたくさんの記事(Article)を投稿します。
Bさんも少しは投稿します。
つまり、User一人一人は沢山のArticleを持っている(User has many articles.)、と考えることができます。(この突然出てきた英文は伏線ですよ!!!!)
逆の立場(Article)も考えてみましょう。
ある日投稿された記事(Article)は、Aさん(User)によって書かれました。
次の日投稿された記事はBさんによって書かれました。
他の日に投稿された記事も、それぞれAさん、Bさんどちらかによって書かれた記事です。Aさん、Bさんが共作で書いた記事というのはありえません。
つまり、Articleは誰か一人のUserに所属している(Article belongs to a user.)と考えることができます。
UserがいなくてはArticleは生まれないし、Articleは必ず誰か一人のUserから生まれます。そう、Userが親でArticleが子となっているわけなのです。これが親子関係です。
このような関係をUserとArticleは一対多の関係または1:Nの関係といいます。
もちろんUserが1でArticleが多です。
この親と子の関係をつくるためのデータベース上でのモデルの関連付けをアソシエーションといい
アソシエーションしないと、どのユーザーがどの記事が書いたのか分かりません。
多対多の関係と中間テーブル
####多対多の関係とは ?
どちらのモデルから見ても、自分も相手も複数×複数になる状態です。
記事から見るとカテゴリーを複数持っているので、記事に対して、カテゴリーは多になります。
カテゴリーから見ると1カテゴリーに複数の記事が関連しているので、カテゴリーから見ると記事は多になります。 この>関係が多対多になります。
【初心者・独学者向け】Ruby on Railsで中間テーブルを作成し、多対多を実現する
####中間テーブルとは?
多対多の関係は2つのモデルでは実現できないんです。
え、なぜ?
例えば、先ほどの記事とカテゴリーの例。
【記事テーブル】
id | 記事タイトル |
---|---|
❶ | |
❷ |
記事ができる度に、自動生成のidが付いていきます。
主キー(primary key)ですね。
【カテゴリーテーブル】
id | カテゴリー名 |
---|---|
① | 日常 |
② | Rails |
【中間テーブル】
id | 記事タイトル | カテゴリー名 |
---|---|---|
1 | ❶ | ① |
2 | ❶ | ② |
2 | ❷ | ② |
2 | ❷ | ① |
可能性の話ですが、上記のように 1つの記事がもしかしたら何個もカテゴリーを持つかもしれないわけです。
「記事タイトル」: ライフスタイル / アウトドア / 子育て とかそんな感じでしょうか。
今はまだ記事タイトルもカテゴリーもどちらも2つしかないので、
中間テーブルいらなくない?ってなると思います。でも記事とカテゴリーはどちらもどんどんどんどん増えていく可能性がある・・
そうするとこの組み合わせは無限大になるし、
カラム数は最初に設定したらもう増やせないので、多対多の間は中間テーブルで対応してあげます。
モデルの関連性設定に has_many, through:
が加わります!
上の例で引き続き。
中間テーブルができるとモデルの関連性設定が変わります
まずはマイグレーションを実行。
class CreateCategoriesArticles < ActiveRecord::Migration
def change
create_table :categories_articles do |t|
t.integer :category_id
t.integer :article_id
t.timestamps null: false
end
end
end
次に中間テーブルで記事モデルとカテゴリーモデルとの関連付けを行う。
class CategoriesArticle < ActiveRecord::Base
belongs_to :category
belongs_to :article
end
記事モデルの関連付け
class Article < ActiveRecord::Base
has_many :categories_articles
has_many :categories, through: :articles_categories
end
カテゴリーモデルの関連付け
class Category < ActiveRecord::Base
has_many :categories_articles
has_many :articles, through: :categories_articles
end
中間テーブルを通して繋がっているものには、
through::
というkeyをつけます。
throughオプションによりarticles経由でcategoryにアクセスできるようになります
外部キーとは? (foreign key)
リレーショナルデータベース(RDB)で、テーブルのある列に、別のテーブルの特定の列に含まれる項目しか入力できないようにする制約。
商品が消えたら、いいねも消える
例えば、あるECサイト
ユーザーのマイページには自分がいいねした 「いいね一覧」 があるとします。
個人的には商品がもう存在しない場合には、いいねも消えてしまっていいのでは?と思います。
そんな時はdependent: :destroy
を使います
dependent: :destroy の役割
商品といいねのモデルには、以下のようなリレーションの記載があります。
class Product < ApplicationRecord
has_many :favorites, dependent: :destroy
end
class Favorite < ApplicationRecord
belongs_to :user
belongs_to :product
end
dependent: :destroy
と言う箇所は、親にあたる投稿が削除されたら、
子をどう扱うのかオプションを設定できるという感じです。今回は消去するので:destroy
残しておいて良いのであれば、何も記載しなくてOkay
【Rails】ActiveRecordの:dependent使い分けまとめ【: destroy, :delete, :nullify】