質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Active Record

Active Recordは、一つのオブジェクトに対しドメインのロジックとストレージの抽象性を結合するデザインパターンです。

Q&A

0回答

1331閲覧

ActiveRecordのincludesの仕方によって、絞り込みの違いが出る理由について

dialbird

総合スコア379

Active Record

Active Recordは、一つのオブジェクトに対しドメインのロジックとストレージの抽象性を結合するデザインパターンです。

0グッド

0クリップ

投稿2017/02/28 08:17

失礼します

ActiveRecordで、一対多の関係にあるレコード同士のincludesで悩んでいるものです。
ここでは説明として、多対多の関係にあるモデル、UserLessonクラスを作成します

class User has_many :user_lessons, dependent: :destroy has_many :lessons, through: user_lessons end class UserLesson belongs_to :user belongs_to :lesson end class Lesson has_many :user_lessons, dependent: :destroy has_many :users, through: user_lessons end

ここで各々のUserが持っているLessonレコードの一覧を表示するような以下のテーブルを作ります。

<table> <thead> <tr> <th>ユーザー名</th> <th>レッスン</th> </tr> </thead> <tbody> <% @users.each do |user| %> <tr> <td><%= user.name %></td> <td> <ul> <% user.user_lessons.each do |u| %> <li><%= u.lesson.name %></li> <% end %> </ul> </td> </tr> <% end %> </tbody> </table>

このページに渡す@userを

@user = User.includes(:user_lessons) .joins(:user_lessons) .merge(UserLesson.where(lesson_id: 1144))

このように設定すると、

SELECT COUNT(*) FROM "users" INNER JOIN "user_lessons" ON "user_lessons"."user_id" = "users"."id" WHERE "user_lessons"."lesson_id" = ? [["lesson_id", 1144]] SELECT DISTINCT "users"."id" FROM "users" INNER JOIN "user_lessons" ON "user_lessons"."user_id" = "users"."id" WHERE "user_lessons"."lesson_id" = ? LIMIT ? OFFSET ? [["lesson_id", 1144], ["LIMIT", 20], ["OFFSET", 0]] SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "users"."created_at" AS t0_r2, "users"."updated_at" AS t0_r3, "user_lessons"."id" AS t1_r0, "user_lessons"."user_id" AS t1_r1, "user_lessons"."lesson_id" AS t1_r2, "user_lessons"."created_at" AS t1_r3, "user_lessons"."updated_at" AS t1_r4 FROM "users" INNER JOIN "user_lessons" ON "user_lessons"."user_id" = "users"."id" WHERE "user_lessons"."lesson_id" = ? AND "users"."id" IN (28, 56, 34, 6, 2) [["lesson_id", 1144]] SELECT "lessons".* FROM "lessons" WHERE "lessons"."id" = ? LIMIT ? [["id", 1144], ["LIMIT", 1]] CACHE (0.0ms) SELECT "lessons".* FROM "lessons" WHERE "lessons"."id" = ? LIMIT ? [["id", 1144], ["LIMIT", 1]] CACHE (0.0ms) SELECT "lessons".* FROM "lessons" WHERE "lessons"."id" = ? LIMIT ? [["id", 1144], ["LIMIT", 1]] CACHE (0.0ms) SELECT "lessons".* FROM "lessons" WHERE "lessons"."id" = ? LIMIT ? [["id", 1144], ["LIMIT", 1]] CACHE (0.0ms) SELECT "lessons".* FROM "lessons" WHERE "lessons"."id" = ? LIMIT ? [["id", 1144], ["LIMIT", 1]]

このようなSQLが出て、それぞれのUserデータのレッスン欄に、idが1144のレッスンだけが表示されて、望み通りの表示ではなくなってしまいます。

一方でこのようにincludesの段階でlessonをuser_lessonsと関連づけておくと

@user = User.includes({ user_lessons: lesson }) .joins(:user_lessons) .merge(UserLesson.where(lesson_id: 1144))
SELECT COUNT(*) FROM "users" INNER JOIN "user_lessons" ON "user_lessons"."user_id" = "users"."id" WHERE "user_lessons"."lesson_id" = ? [["lesson_id", 1144]] SELECT "users".* FROM "users" INNER JOIN "user_lessons" ON "user_lessons"."user_id" = "users"."id" WHERE "user_lessons"."lesson_id" = ? LIMIT ? OFFSET ? [["lesson_id", 1144], ["LIMIT", 20], ["OFFSET", 0]] SELECT "user_lessons".* FROM "user_lessons" WHERE "user_lessons"."user_id" IN (28, 56, 34, 6, 2) SELECT "lessons".* FROM "lessons" WHERE "lessons"."id" IN (1034, 1061, 1062, 1144, 1029, 1142, 1148, 1145, 1139, 1111, 1040, 1088, 1112, 1056, 1078, 1113, 1075)

それぞれのUserデータが持つすべてのレッスン名がレッスン欄に表示されて、理想通りになります。

SQL的には前者は子要素で、後者は親要素で絞り込んでいるのだろうということは想像できるのですが、なぜそのようになるのかが不明です。

どなたかご教授ください。宜しくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問