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

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

ただいまの
回答率

88.79%

【rails 】whereメソッドについて

受付中

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,869
退会済みユーザー

退会済みユーザー

whereメソッドについて、利用の仕方がいまいち理解できないので、ご教授頂ければ幸いです。

いま、questionモデル,answerモデルgroupモデルがあり、以下の様な関係になっています。

answer.rb

belongs_to :question

question.rb

has_many :answers
belongs_to :group

group.rb

has_many :questions

questionsテーブルにはgroup_idがあり、answersテーブルにはquestion_idがあります。

今、例えばgroup_idが1のanswersレコードを取得するとき、
@answers = Answer.includes(:question).where(questions:{group_id:1})
と記述できるとのことですが、ここでのwhereメソッドの使い方がよくわかりません。

どなたか教えて頂ければ幸いです。
また、参考になるサイトなどがあれば、シェアしていただきたいです。

よろしくお願い致します。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • rifuch

    2016/03/17 16:37

    Answerクラスは、belongs_to :questionではないですか?
    大事な前提なので、確認したいです。

    キャンセル

  • 退会済みユーザー

    退会済みユーザー

    2016/03/17 17:50

    ご指摘ありがとうございます!
    修正致しました。

    キャンセル

回答 3

0

うまい事Arelを使ってあげると良いかと思います。
基本的に、リレーションで取得してくるテーブルの名前はincludeでもそのまま使えるので、
その方法で指定してあげるという使い方になるかと。

q_table = Question.arel_table
@answers = Answer.includes(:question).where(q_table[:group_id].eq(1))


ただ、Arelを使ったコードがControllerに出てくると、なんだか気持ち悪いので、
コントローラでやるんなら、私だったらこういう風にするかなあ。

@group = Group.includes(questions: :answers).where(params[:gourd_id])

# viewの方で
<% @group.questions.each do |question| %>
  <% question.answers.each do |answer| %>
    <!-- 何か表示 -->
  <% end %>
<% end %>

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

group_idが1のanswersレコードを取得するなら
  @answers = Grout.find(1).answers
でも可能だとおもいます。

参考ページとして次を紹介します。

質問文のものとモデル名は異なりますが、類似も構造での検索例を示します。
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 21:24

    別の記述方法も記載して頂き、ありがとうございます!

    ちなみに、whereメソッドの引数についてなのですが、
    where(questions:{group_id:1})
    の questionsは、何のことを言っているのか、教えて頂ければ幸いです。questionsテーブルの全てのレコードでしょうか?

    キャンセル

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)で指定

SELECT "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 
  FROM "answers" 
    LEFT OUTER JOIN "questions" ON "questions"."id" = "answers"."question_id" 
  WHERE "questions"."group_id" = 1

 Answer.includes(:question).where(question:{group_id:1}).to_sql

関連名(question)で指定

SELECT "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 
  FROM "answers" 
    LEFT OUTER JOIN "questions" ON "questions"."id" = "answers"."question_id" 
  WHERE "question"."group_id" = 1

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 88.79%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る