🐰
Rails ActiveRecord で子テーブルのフィールドを pluck する
先日、指定したカラムのみを抽出する pluck メソッドについて調べた記事を書きました
今回は、子テーブルのフィールドを pluck する方法についてまとめました。
結論
- "子テーブル.カラム名" で指定する
- シンボルではなく、文字列で指定する必要がある
やりたいこと
例えば下記のように、Review テーブルと User テーブルがあったとします。
User は Review に対して belongs_to しており、Review は User に対して has_many です。
Review
ID | title | star | detail | user_id |
---|---|---|---|---|
1 | 最高 | 5 | さいこうです!!! | 1 |
2 | いまいち | 2 | いまいちでざんねん | 2 |
3 | ふつう | 3 | 可もなく不可もなくです | 3 |
User
ID | user_id | name |
---|---|---|
1 | user_id | ndj |
2 | user_2s | teqteq |
3 | user_nd | ndj-D-:D |
これらのテーブルから、下記のマップの配列が欲しいです。
{
title: "最高",
star: 5,
user.name: "ndj"
}
子テーブルのカラムを pluck するには、工夫(といっても大層なことではない)が必要です。
"子テーブル.カラム名" で指定する
結論から先に書くと以下のように指定することで、子テーブルのカラムを pluck することが可能です。
Review.where(id: 1, user: {id: 1})
.includes([:user])
.pluck(:title, :star, "user.name")
今回の場合だと、Review の子テーブルが User テーブルになります。User の name フィールドを取得するには、"user.name"
とシンボルではなく文字列で指定することで、子テーブルの情報を pluck することができます。
こういう書き方でもいけます。
Review.where(id: 1, user: {id: 1})
.includes([:user])
.pluck("reviews.title", "reviews.star", "user.name")
全部文字列指定することで、どのカラムがどのテーブルのカラムなのか明示的に指定しています。
なお指定する際は一対多の関係に注意です。
関連テーブルを複数指定していたり、似たような属性のカラムがあるなどの場合に、カラム名の混乱を防ぐ目的では使えそうです。
ただ、基本的には親テーブルはシンボル指定ができて、子テーブルは文字列指定するという制約があるのであまり使う機会はないかもしれないですね。
joins を使用した例
上記は includes で子テーブルを JOIN していますが、joins や left_joins でももちろん可能です。
Review.joins(:user)
.where(id: 1, user: {id: 1})
.pluck(:title, :star, "user.name")
Review.left_joins(:user)
.where(id: 1, user: {id: 1})
.pluck(:title, :star, "user.name")
参考
Discussion