whereメソッドについて、利用の仕方がいまいち理解できないので、ご教授頂ければ幸いです。
いま、questionモデル
,answerモデル
, groupモデル
があり、以下の様な関係になっています。
answer.rb
lang
1belongs_to :question
question.rb
lang:question.rb
1has_many :answers 2belongs_to :group
group.rb
lang:group.rb
1has_many :questions
questionsテーブル
にはgroup_id
があり、answersテーブル
にはquestion_id
があります。
今、例えばgroup_idが1のanswersレコードを取得するとき、
@answers = Answer.includes(:question).where(questions:{group_id:1})
と記述できるとのことですが、ここでのwhereメソッド
の使い方がよくわかりません。
どなたか教えて頂ければ幸いです。
また、参考になるサイトなどがあれば、シェアしていただきたいです。
よろしくお願い致します。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2016/03/17 08:50
回答3件
0
今、例えばgroup_idが1のanswersレコードを取得するとき、
@answers = Answer.includes(:question).where(questions:{group_id:1})
と記述できるとのことですが、ここでのwhereメソッドの使い方がよくわかりません。
whereメソッドの使い方がよくわからないとの事ですので
Answer.includes(:question).where(questions:{group_id:1})
の部分の解説をさせていただきます。
通常 Answer.where
とすると Answer モデル内のカラムのみが where の検索対象になります。
今回は Answer モデルではなく Questionモデル のgroup_id カラムを検索対象にしたいので
includes(:question)
を付けてあげます。
すると Answer.includes(:question).where
ですね。 includes の引数である :question は
Answer モデル の belongs_to :question の :question です。
そして最後に where の引数です。 includes の引数は関連名で指定しましたが where の引数は多少やっかいで、自分(Answer)以外のモデルを検索する時はテーブル名で指定します。
今回は Questionモデル のgroup_id カラム が 1 である物を探したいので
questions テーブルのgroup_id カラム が 1
という指定の仕方をする必要があります。
よって where の引数は questions:{group_id:1}
になり
Answer.includes(:question).where(questions:{group_id:1})
が完成します。
おしりに .to_sql をつけると実際に発行されるSQL文を得る事ができます。
SQL文がわかるのであれば .to_sql で確認しながら where の引数を指定するといいかもしれません。
Answer.includes(:question).where(questions:{group_id:1}).to_sql
テーブル名(questions)で指定
SQL
1SELECT "answers"."id" AS t0_r0, "answers"."question_id" AS t0_r1, "answers"."created_at" AS t0_r2, "answers"."updated_at" AS t0_r3, "questions"."id" AS t1_r0, "questions"."group_id" AS t1_r1, "questions"."created_at" AS t1_r2, "questions"."updated_at" AS t1_r3 2 FROM "answers" 3 LEFT OUTER JOIN "questions" ON "questions"."id" = "answers"."question_id" 4 WHERE "questions"."group_id" = 1
Answer.includes(:question).where(question:{group_id:1}).to_sql
関連名(question)で指定
SQL
1SELECT "answers"."id" AS t0_r0, "answers"."question_id" AS t0_r1, "answers"."created_at" AS t0_r2, "answers"."updated_at" AS t0_r3, "questions"."id" AS t1_r0, "questions"."group_id" AS t1_r1, "questions"."created_at" AS t1_r2, "questions"."updated_at" AS t1_r3 2 FROM "answers" 3 LEFT OUTER JOIN "questions" ON "questions"."id" = "answers"."question_id" 4 WHERE "question"."group_id" = 1
投稿2016/10/17 01:07
総合スコア1728
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
group_idが1のanswersレコードを取得するなら
@answers = Grout.find(1).answers
でも可能だとおもいます。
参考ページとして次を紹介します。
- Active Record の関連付け (アソシエーション) http://railsguides.jp/association_basics.html
- Active Record クエリインターフェイス http://railsguides.jp/active_record_querying.html
質問文のものとモデル名は異なりますが、類似も構造での検索例を示します。
Client -> Order で 1対多となっている場合の検索例です。
[1] pry(main)> Order.includes(:client).where(orders:{client_id:1}) Order Load (24.5ms) SELECT "orders".* FROM "orders" WHERE "orders"."client_id" = 1 ORDER BY ordered_at DESC Client Load (0.4ms) SELECT "clients".* FROM "clients" WHERE "clients"."id" IN (1) +----+-----------+----------+-------+-------------------------+-------------------------+-------------------------+ | id | client_id | status | price | ordered_at | created_at | updated_at | +----+-----------+----------+-------+-------------------------+-------------------------+-------------------------+ | 2 | 1 | active | 200 | 2000-01-01 04:58:33 UTC | 2016-03-12 09:58:33 UTC | 2016-03-12 09:58:33 UTC | | 1 | 1 | received | 100 | 2000-01-01 09:58:33 UTC | 2016-03-12 09:58:33 UTC | 2016-03-12 09:58:33 UTC | | 3 | 1 | payed | 400 | 2000-01-01 09:58:33 UTC | 2016-03-12 09:58:33 UTC | 2016-03-12 09:58:33 UTC | +----+-----------+----------+-------+-------------------------+-------------------------+-------------------------+ 3 rows in set [2] pry(main)> Client.find(1).orders Client Load (0.2ms) SELECT "clients".* FROM "clients" WHERE "clients"."id" = ? LIMIT 1 [["id", 1]] Order Load (0.3ms) SELECT "orders".* FROM "orders" WHERE "orders"."client_id" = ? ORDER BY ordered_at DESC [["client_id", 1]] +----+-----------+----------+-------+-------------------------+-------------------------+-------------------------+ | id | client_id | status | price | ordered_at | created_at | updated_at | +----+-----------+----------+-------+-------------------------+-------------------------+-------------------------+ | 2 | 1 | active | 200 | 2000-01-01 04:58:33 UTC | 2016-03-12 09:58:33 UTC | 2016-03-12 09:58:33 UTC | | 1 | 1 | received | 100 | 2000-01-01 09:58:33 UTC | 2016-03-12 09:58:33 UTC | 2016-03-12 09:58:33 UTC | | 3 | 1 | payed | 400 | 2000-01-01 09:58:33 UTC | 2016-03-12 09:58:33 UTC | 2016-03-12 09:58:33 UTC | +----+-----------+----------+-------+-------------------------+-------------------------+-------------------------+ 3 rows in set
検索結果は同じですが、発行される SQR 文は異なっています。
投稿2016/03/17 11:55
総合スコア22324
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2016/03/17 12:24
0
うまい事Arelを使ってあげると良いかと思います。
基本的に、リレーションで取得してくるテーブルの名前はincludeでもそのまま使えるので、
その方法で指定してあげるという使い方になるかと。
Ruby
1q_table = Question.arel_table 2@answers = Answer.includes(:question).where(q_table[:group_id].eq(1))
ただ、Arelを使ったコードがControllerに出てくると、なんだか気持ち悪いので、
コントローラでやるんなら、私だったらこういう風にするかなあ。
Ruby
1 @group = Group.includes(questions: :answers).where(params[:gourd_id]) 2 3# viewの方で 4<% @group.questions.each do |question| %> 5 <% question.answers.each do |answer| %> 6 <!-- 何か表示 --> 7 <% end %> 8<% end %>
投稿2016/03/17 10:40
総合スコア1901
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。