Rails – アソシエーション – 基本

概要

Railsにおけるデータベースのテーブル間のアソシエーションについて、基本を整理する。

以下のようなテーブルを例にする。Railsが生成するcreated_atupdated_atは省略している。

  • userspostsimagesのレコードはそれぞれUserPostImageモデルのインスタンス
  • PostUserに、ImagePostに属する
  • Userは0以上複数のPostを持つ
  • Postは0以上複数のImageを持つ

アソシエーションの意義

単純にテーブル操作する場合

普通に3つのテーブルだけがある場合に、特定idのユーザーの投稿記事を作成し、その記事が2つの画像を持たせるには以下の様になるだろう。

このときに生成されるデータは以下の様になる。

ここで投稿記事Post(id=1)をそれらに付随する2つの画像データとともに削除する。それには2つのImageを削除してから元のPostを削除する。

このように個別のテーブルを操作する場合、データの生成・登録や削除の際に、

  • 関連するテーブルのデータのidを常に意識し
  • データ間の関連を念頭に置きながら個々のデータを操作する

必要がある。

アソシエーション導入後

テーブル間のアソシエーションを導入した場合、関連付けられたデータの操作が直感的に、またシンプルになる。

データの生成

データの生成は以下のとおりで、親となるデータのidを意識しなくても、具体の親オブジェクトを指定して生成すれば関連付けられたデータが生成される。

上の例では、まずpostscreateした後に、そのインスタンスに従属するようにimagescreateしている。

このようなデータベースへの書き込みを、さらにまとめることができる。

 

最後にsaveするまではデータベースには保存されずidもnilのままだが、オブジェクト間の関係は保たれている。最後に保存するときに、postと2つのImagesのインスタンスが同時に保存される。

データの取得

データの取得は、親モデル.子モデルのコレクションで取得し、親モデルは単数形、子モデルは複数形。

データの削除

そして投稿記事を画像ごと削除する場合には、以下の様にたった1行で済む

さらに、外部キー制約をかけているので、以下のように親のデータだけを削除しようとするとエラーとなる。

アソシエーション設定の流れ

仕様

冒頭の3つのテーブルのうち、PostImageの2つを取り出して考える。以下の様に若干変更。

  • Postcomment要素を持つ
  • ImagePostImageに変更
  • Userとの関係は考えない

2つのモデルの関係は以下のとおりとする。

  • PostImagePostに属する
  • Postは0以上複数のPostImageを持つ
  • Postの削除に伴って、これに属するPostImageのデータも削除される

モデルの生成~外部キー指定

以下のコマンドで2つのモデルを生成する。

PostImagePostに従属するよう、post:referencesを指定している。生成するモデルが属するモデル(親のモデル)をAとするとA:referencesと指定する。

Postモデルについては枠組みのみ生成されている。

app/models/post.rb

PostImageモデルについては、references指定に伴って、Railsによりbelongs_toの1行が追加されている。

app/models/post_image.rb

モデルのアソシエーションの定義

has_many

Postが複数のPostImageを持つことをRailsに伝えるため、Postモデルにhas_manyメソッドを追記する。

dependent

親のデータを削除するときにこのデータも一括して削除するためには、dependent: :destroyを指定。

注意点

  • belongs_to :parentはメソッドの引数が単数形
  • has_many :childrenはメソッドの引数が複数形
  • dependent: :destroyは引数のハッシュで値がシンボル

マイグレーションファイル

Postsモデル

コマンドでの指定に従って、comment要素が設定されている。

PostImageモデル

コマンドで指定したfile_nameのほか、Railsによって以下の外部キーの指定が生成されている。

t.references :user, foreign_key: true

マイグレーション実行~テーブル

マイグレーション実行の結果、postsimagesの3つのテーブルが生成される。

postsテーブル

デフォルトのidcreated_atupdated_atのほか、不通に指定したcomment要素が含まれる。

post_imagesテーブル

デフォルトの要素のほか、Railsコマンドで指定した2つの要素が含まれる。

  • post: referencesの指定に対して、postsテーブルのidを参照する外部キーpost_id
  • 普通に指定したfile_name

アソシエーション設定の確認

rails consoleによる確認

rails consoleでデータベース操作の効果を確認する。

データの生成と保存

2つのPostImageオブジェクトを持つPostオブジェクトを1つ生成し、まとめて保存する。表示は見やすくするために再構成している。

saveより前では3つのオブジェクトともidnilとなっているが、オブジェクト間の関連は保持されている。

postsテーブルとPostImagesテーブルへの登録内容を確認。

データの取得

postsに従属する複数のPostImageデータをループで取り出す例。

この操作はデータベース登録(save)の前でも可能。

deleteに対する制約エラー

PostImageデータを持っている状態でpost.deleteしようとすると外部キー制約エラー

destroyによる一括削除

post.destroyだと従属する2つのImageも削除される

1つの実行文で、当該Postデータとそれに関連付けられたPostImageデータも削除される。

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です