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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

1回答

2220閲覧

railsでincludesした子モデルに条件を追加したい

niki

総合スコア7

Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

0グッド

0クリップ

投稿2018/06/04 06:12

編集2018/06/04 06:36

前提・実現したいこと

railsで開発をしていますが、以下の個所で詰まりました。
【前提】
groupsモデル、group_membersモデル、usersモデルの3つが存在し、それぞれ以下の関係を持っています

Ruby

1class Group < ApplicationRecord 2 has_many :group_members, dependent: :destroy 3 has_many :users, through: :group_members 4end

Ruby

1class GroupMember < ApplicationRecord 2 belongs_to :user 3 belongs_to :group 4end

Ruby

1class User < ApplicationRecord 2 has_many :group_members, dependent: :destroy 3 has_many :groups, through: :group_members 4end

グループにはグループメンバーが所属しており、グループメンバーはユーザーマスタに紐づいています。

【やりたいこと】
「グループテーブルにあるカラムAの値が今日以降」かつ、「グループメンバーは自分が所属している」というグループの情報を取得したいです。
取得した結果はViewで、eachで回して、「グループ名」「そのグループに所属するメンバー数」を表示したいです。
n+1問題が発生しないよう、includesを使い、以下のように記述しました。

Ruby

1#groups_controllerの記述 2@group_list = Group.includes(group_members: :user).where("cola > ? AND user_id = ?", Date.today, current_user.id).all 3 4#viewの記述 5<% @group_list.each do |group| %> 6 <tr> 7 <th><%= group.group_name %></th> 8 <th><%= group.group_members.size %>人</th> 9 </tr> 10<% end %>

発生している問題・エラーメッセージ

上記で実施すると、groups,group_members,usersのそれぞれでSQLを発行してくれず、一つのSQLを発行します。
なので、group_members.sizeで値が取れず、countに修正すると値が取れますが、グループの数分、SQLを発行してしまうので、n+1問題が発生します。

試したこと

Group_membersテーブルにあるuser_idへの条件を削れば、期待値を得られました。
親モデルへの条件が子モデルにもある場合は、どうやって記述すればよいでしょうか?

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

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

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

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

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

guest

回答1

0

自己解決

すみません、自己解決しました。
条件がこんがらがっていたのを、こちらに質問して整理することで、以下のように修正しました。

Ruby

1#groupsモデルに、group_membersをjoinして、Where句となるスコープを定義する 2scope :get_group_list, ->(uid){ 3 where("cola > ?", Date.today).\ 4 joins(:group_members).\ 5 merge(GroupMember.own_group_member2(uid)) 6} 7 8#group_membersモデルにも、条件となるスコープを定義する 9scope :own_group_member2, -> (uid){ 10 where(user_id: uid) 11}

上記のScopeで取得した値に対し、group_membersモデルとusersモデルをincludesしました。

Ruby

1#group_controller 2@group_list = Group.get_group_list(current_user.id).all.includes(group_members: :user)

これにより、期待していた通り、まず最初に「カラムAが当日以降であり、group_membersに自分が所属しているグループ」を取るSQLが発行され、その結果を受けて、group_membersとusersに対し、SQLが発行してくれました!

#pumaのログ (0.4ms) SELECT COUNT(*) FROM "groups" INNER JOIN "group_members" ON "group_members"."group_id" = "groups"."id" WHERE (cola > '2018-06-04') AND "group_members"."user_id" = $1 [["user_id", 2]] Group Load (0.3ms) SELECT "groups".* FROM "groups" INNER JOIN "group_members" ON "group_members"."group_id" = "groups"."id" WHERE (cola > '2018-06-04') AND "group_members"."user_id" = $1 [["user_id", 2]] GroupMember Load (0.2ms) SELECT "group_members".* FROM "group_members" WHERE "group_members"."group_id" IN (9, 10, 5, 11, 12) User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" IN (2, 4)

これにより、View側でグループに所属しているメンバー数、メンバーの名前を取れました。

Ruby

1<% @group_list.each do |group| %> 2 <tr> 3 <th><%= group.group_name %></th> 4 <th><%= group.group_members.size %>人</span> 5 <% group.group_members.each do |m| %> 6 <%= m.user.nickname %> 7 <% end %> 8 </th> 9<% end %>

お騒がせしました。
ご覧くださった方、ありがとうございます。

投稿2018/06/04 06:58

niki

総合スコア7

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問