0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Rails における UserBook.all と UserBook.joins(:user).joins(:book) の違い

Posted at

はじめに

中間テーブル user_books があったとき、Rails (Active Record) における UserBook.allUserBook.joins(:user).joins(:book) の違いについて説明します。

モデルの定義

以下のようなモデルがあったとします。ユーザは複数の本を所有しており、本は複数のユーザに所有されている、いわゆる多対多の関係になっています。

class User < ApplicationRecord
  has_many :user_books
  has_many :books, through: :user_books
end
class Book < ApplicationRecord
  has_many :user_books
  has_many :users, through: :user_books
end
class UserBook < ApplicationRecord
  belongs_to :user
  belongs_to :book
end

レコード

以下のようなレコードがデータベースに格納されていたとします。

users テーブル

id name
1 一郎
2 二郎
3 三郎

books テーブル

id name
1 こころ
2 三四郎
3 人間失格
4 雪国
5 羅生門

user_books テーブル

user_books 自体の主キーである id は省略します。

user_id book_id
1 1
1 2
1 3
2 2
2 3
2 4
3 4
3 5

上記のテーブルの内容を言語的にまとめると以下のようになります。

  • 一郎さんは「こころ」と「三四郎」と「人間失格」を所有している
  • 二郎さんは「三四郎」と「人間失格」と「雪国」を所有している
  • 三郎さんは「雪国」と「羅生門」を所有している

ユースケース

「羅生門」は書庫で管理しなくなったなどの理由でレコードを削除したとします。

Book.find_by(name: "羅生門").destroy

さて、この状態で user_books テーブルに存在する、usersbooks に紐づいた全レコードを取得したいとします。

以下の Active Record では正しく 取得できません

UserBook.all

なぜなら、books テーブルから「羅生門」は削除しましたが、user_books テーブルから「三郎さんが羅生門を所有している」という情報は削除されていないからです。

users テーブルあるいは books テーブルから削除されたレコードが紐づいているものを含まない user_books テーブルの全レコードを取得したい場合は以下の Active Record を実行する必要があります。

UserBook.joins(:user).joins(:book)

おまけ

逆に users テーブルあるいは books テーブルから削除されているレコードに紐づく user_books テーブルのレコードのみを取得したい場合は以下の Active Record を実行すれば良さそうです。

UserBook
  .left_outer_joins(:user, :book)
  .where(users: { id: nil })
  .or(UserBook.where(books: { id: nil }))

上記の例でいうとこれは「削除された本『羅生門』を所有しているユーザの情報のみを表示したい」という要件の場合に使用できます。

関連するレコードを一緒に削除したい場合

上記の例で books テーブルから「羅生門」を削除しましたが、その際に user_books テーブルから「三郎さんが羅生門を所有している」というレコードも一緒に消したい場合は該当するアソシエーションに dependent: :destroy を付与します。

class Book < ApplicationRecord
-  has_many :user_books
+  has_many :user_books, dependent: :destroy
  has_many :users, through: :user_books
end

これで、books テーブルからレコードが削除された際に、そのレコードと紐づいた user_books に含まれるレコードも一緒に削除されます。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?