Note

active_record 関連テーブルを条件にして検索をする

やっぱりよくわかっていなかったので、メモ。
要は joinsしたテーブルを検索状態にしたいのだけど…というやつです。

目的

Record は Category に紐付いていて、recordの検索の条件に categoryの中にあるカラムを使いたくなりました。
activerecordだけで調べてピンとこなかったので、ここぞとばかりにsqlから学び直すことに。

目的を達成しそうなsql

SELECT "records".*, "categories"."is_payment" FROM "records" INNER JOIN "categories" ON "records"."category_id" = "categories"."id" WHERE "categories"."is_payment" = false;

するとこんな感じの返しがきた。

id | money | date | card | memo | created_at | updated_at | category_id | user_id | is_payment ----+--------+------------+------+------+----------------------------+----------------------------+-------------+---------+------------ 41 | 290000 | 2016-04-10 | f | | 2016-04-27 09:52:07.124605 | 2016-04-27 09:52:07.124605 | 21 | 1 | f (1 row)

これをactive recordに変換する

まずjoinsから確認してみた。.to_sqlメソッドを使うと発行されるsqlを見ることができるので便利だった。

$ puts Record.all.joins(:category).to_sql SELECT "records".* FROM "records" INNER JOIN "categories" ON "categories"."id" = "records"."category_id" => nil

意外と発行してもらいたいことと近そうだ。これにwhereをつけていい感じにはきだしてくれたぽい。

$ puts Record.all.joins(:category).where("categories.is_payment = ?", false).to_sql SELECT "records".* FROM "records" INNER JOIN "categories" ON "categories"."id" = "records"."category_id" WHERE (categories.is_payment = 'f')

結果は

Record.all.joins(:category).where("categories.is_payment = ?", false) Record Load (0.5ms) SELECT "records".* FROM "records" INNER JOIN "categories" ON "categories"."id" = "records"."category_id" WHERE (categories.is_payment = 'f') => [#<Record:0x007fdbbf55a2b0 id: 41, money: 290000, date: Thu, 28 Apr 2016, card: false, memo: "", created_at: Thu, 28 Apr 2016 07:02:28 UTC +00:00, updated_at: Thu, 28 Apr 2016 07:02:28 UTC +00:00, category_id: 21, user_id: 1>]

で無事に取れた様子。
where(“categories.is_payment = ?”, false) この部分を文字列じゃない形で渡してあげたい。


追記: 2016/04/28 16:29

と思って調べてみたら、やっぱりあった。
Record.all.joins(:category).where(categories: { is_payment: false} ) という書き方で同等になる模様。


sql書かないと覚えなさそうなので、こんな感じでいろいろ遊んで覚えていきたい。