Railsで子テーブルのレコードでwhereメソッドを使って条件検索する方法
たとえば、created_atが一週間以内のusersテーブルのレコードの中で、子テーブルであるpostsテーブルのレコードのcreated_atが三日以内のものを取得したい時、
arr = []
Post.where('created_at >= ?', Time.current - 3.day).each do |post|
if post.user.created_at >= Time.current - 1.week
arr.push(post.user)
end
end
のようにすれば取得できるけれど、冗長だしパフォーマンスも悪い。
そこでテーブル結合を使えば、可読性もパフォーマンスも高くできる。
テーブル結合のやり方
joinsメソッドを使って行う。
User.joins(:posts)
のように記述する。
これで、postsレコードのuser_idがusersレコードのidと一致する、usersレコードを取得できる。つまり、postしたuserのみを取得している。
User.all.count
106
User.joins(:posts).count
68
テーブル結合後にwhereで条件検索
joinsした後に、whereでレコードを取得したい時、以下のようにすればいい。
User.joins(:posts).where('users.created_at >= ?', Time.current - 1.week).count
20
ポイントは、テーブル結合した後で条件文を書く場合、カラム名の前にテーブル名をドットでつなげて明示すること。where('[テーブル名].[カラム名] [演算子] ?', [値])の形式を使う。
User.joins(:posts).where('users.created_at >= ?', Time.current - 1.week).where('posts.created_at >= ?', Time.current - 3.day)
これで、created_atが一週間以内のusersテーブルのレコードの中で、子テーブルであるpostsテーブルのレコードのcreated_atが三日以内のものを取得できた。
一致で検索する場合は、以下のような書き方もある。
User.joins(:posts).where(posts: {status_id: "enable"})
これでpostsテーブルのstatus_idカラムがenableのレコードを取得することができる。