1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

君、Railsでeager_loadした後の行でfind_by, where使ってないか?

Posted at

Railsでeager_loadした後の行でfind_by, where使ってない?

要約

eager_loadpreloadでデータを読み込んだ場合、以降の行でfind_by, whereを使うとクエリを発行してしまう(ロードしたデータを利用しない)

【背景】

別件でサーバーの不具合原因を調査していると、eager_loadした後にも関わらずクエリが発行されていることを発見

【実行環境】

技術スタック バージョン
Ruby 3.2.2
Rails 7.0.4
Postgresql 1.1

具体例 (NG)

シナリオ

  1. ログイン中のユーザーに紐づく投稿(posts)を取得し、その投稿に紐づくコメント(comments)を事前読み込み

    • has_manyとかで関連づいているとする
  2. 前ステップで取得した各投稿に対して紐づくコメントの中から、
    user_id: 5
    のレコードを検索

    # current_userは事前にUserテーブルから取得したことにする
    posts = current_user.posts.eager_load(:comments)
    
    posts.map do |post|
      # eager_loadで読み込んだcommentから、さらに絞り込みを行いたい 
      comments = post.comments.where(user_id: 5)
      puts comments
    end
    

上記の場合、ステップ2の
comments = post.comments.where(user_id: 5)
で再度Commentテーブルに対してクエリを発行してしまい、eager_loadした旨味がなくなってしまう。


解決例

detectメソッドを使う(Rubyのメソッド)

posts = current_user.posts.eager_load(:comments)

posts.map do |post|
  # 変更点
  comments = construction.post.comments.detect { |comment| comment.user_id == 5 }
  puts comments
end

eager_load / preloadについて

詳しくはちゃんと紹介している記事を見てほしいが、ざっくりと使用例をば
(それぞれの使い方を理解していれば、includeメソッドを使用する必要はなくなるので、あまり使わないようにしたい。)

eager_load

# レコードを連結しているので、 post, commentのカラムの値で検索をかけることができる
# (user) - post - commentの順で紐づいているもので、commentカラムの値で検索をかける
current_user.posts.eager_load(:comments).where(comments: {user_id: 5})

preload

# レコードを連結していないので、postテーブルのカラムの値のみで検索をかけることができる
# (user) - post - commentの順で紐づいているもので、commentテーブルを読み込んでおく(postに紐づくcommentのみ)
# 例1
current_user.posts.preload(:comments)
# 例2: ベースとなっているpostテーブルのカラムの値で検索はできる
current_user.posts.preload(:comments).where(post_title: "【悲報】xxxが--な件について") 
# 例3 (NG): 読み込み先であるcommentテーブルのカラムの値で検索はできない
current_user.posts.preload(:comments).where(comments: {user_id: 5}) 

まとめ

クエリ発行が行われる際は、どんなクエリが発行されているかを確かめるべし。

最後に

間違ってたら優しく教えてください


参考にしたサイト

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?