まどぎわです(・∀・)今日は、current_user
へのN+1問題の対応についてです!
railsで開発していると、N+1問題にぶつかって対応することが多いかと思います。 普通であれば、DBアクセス時にincludes
等を使って関連モデルをキャッシュしておくことで対応することが多いかと思います。
しかし、current_user
のメソッド呼び出しでN+1問題が発生してしまった場合、だいたいDBアクセス処理はライブラリで行われているため、DBアクセス時に関連モデルをキャッシュしようとしても、「どうすれば、いいんや・・・」という気持ちになり、対応方法を調べたのでメモしておきますφ(..)
前提
今回は、下記のようなUserモデルとQuestionモデルとQuestionAnswerモデルがあり、Userモデルに#answerd?
というUserがその質問に回答済みかどうかを判定するメソッドを定義しています。
何も対応しないとQuiz一覧画面等で、このメソッドを呼び出すとN+1問題が発生してしまいます。。。
class User < ApplicationRecord has_many :question_answers def answerd?(question) question.question_answers.to_a.select{ |answer| answer.user_id == id }.present? end end class QuestionAnswer < ApplicationRecord belongs_to :user belongs_to :question end class Question < ApplicationRecord has_many :question_answers end
対応方法
current_userをもとにUserインスタンスを再生成する
controller
内でcurrent_user
をもとにUserインスタンスを再生成し、その際にincludes
で関連モデルをキャッシュするようにします!これにより、#answerd?
を呼び出してもキャッシュされた値から処理が行われるので、N+1問題を防ぐことが出来ます🙌
class QuizzesController < ApplicationController def index @user = User.includes(:question_answers).find(current_user.id) @questions = Quiz.includes(:choices) end end