RailsのActiveRecordにおいて保存していない親レコードに紐づく子レコードへのpluckは空配列が返る件

こんにちは!kossyです!




今回は保存していない親レコードに紐づく子レコードにpluckメソッドを使って、意図通り動作しない事象に遭遇したため、

備忘録としてブログに残してみたいと思います。



環境

Ruby 2.6.8
Rails 6.0.4
MacOS BigSur



pluckメソッド

Railsでは、ActiveRecordのpluckメソッドとActiveSupportを用いている場合にEnumerableにpluckメソッドが定義されています。

api.rubyonrails.org

edgeguides.rubyonrails.org

ActiveRecordのpluckメソッドは実行時にSQLが走り、返り値は配列が返ります。(これを理解していればハマることはなかった。)


ハマったポイント

以下のようなケースでハマりました。

$ user = User.new(name: '田中太郎', email: "tarotanaka@gmail.com")

$ Post.new(user: user, title: "田中性は日本に何人いるのか?", body: "続きはWebで")

$ user.posts.pluck(:title)
=> []

とある処理の中で親インスタンスと子インスタンスを生成し、紐づく子インスタンスの値をまとめて取得して後続の処理を行いたいケースがありました。

pluckを使えば子インスタンスの値を取得できると思っていたのですが、前述の通り、ActiveRecordのpluckメソッドの場合は実行時にSQLが走りますので、

まだDBに保存されていないレコードを対象に実行しても返り値は空の配列になります。

なので、今回のケースではEnumerable#mapメソッドを使うのが正解でした。

$ user = User.new(name: '田中太郎', email: "tarotanaka@gmail.com")

$ Post.new(user: user, title: "田中性は日本に何人いるのか?", body: "続きはWebで")

$ user.posts.map(&:title)
=> ["田中性は日本に何人いるのか?"]

まとめ

ActiveRecordのpluckメソッドの挙動を理解していればハマらなかっただろうに、使ってしまった時間が悔やまれます。

この記事がどなたかの助けになることを願っています。。。



大いに参考にさせていただいた記事

素晴らしいコンテンツの提供、誠にありがとうございます。

Railsの技: pluckはActive RecordモデルでもEnumerableでも使える(翻訳)|TechRacho by BPS株式会社