LoginSignup
1
1

More than 1 year has passed since last update.

Railsでsessionによるwhere検索を行うときの注意点

Last updated at Posted at 2021-06-07

障害内容

コントローラのある1つのアクション内でsessionを利用後にデータを削除するような処理を想定して、下記コードを書いたとする

hoge_controller.rb
def action
  # イメージ的には検索処理のような感じ
  # category_idはInteger型でDBに登録されている
  @lists = Book.where(category_id: session[:category_id])
  session[:category_id].clear
end

上記のコードではBookモデルからデータを取得することはできない
実際に発行されているSQLも
SELECT * FROM books WHERE category_id = ''
のような形で出力されることが確認できるはず

通常、Railsで定義される変数類は先行評価の形式をとっているため、
例えwhere検索等の遅延評価系メソッドの後に値をnilにしても正しくデータを取得することができる

反対に、sessionは基本的に遅延評価であるため遅延評価系メソッドで使用した後にsessionの中身をクリアするとデータの取得ができなくなってしまう

解消方法

今回の例ではwhere検索であるため、それを先行評価メソッドにしてしまえば問題ない

hoge_controller.rb(whereの先行評価ver)
def action
  # SQLを直書きする
  @lists = Book.where('category_id = :id', id: session[:category_id])
  session[:category_id].clear

  # take、firstなどで即時発行させる
  @lists = Book.where(category_id: session[:category_id]).take
  @lists = Book.where(category_id: session[:category_id]).first
  session[:category_id].clear
end

  # to_aなどで変換を行う(ActiveRecord::Relationクラスではなくなるため要注意)
  @lists = Book.where(category_id: session[:category_id]).to_a
  session[:category_id].clear
end

また、それとは逆にsessionの値をdupでコピーするなど、sessionとは別で保持させることでも解消できる
格納させるときにはid = session[:category_id]のように代入で行わないようにさえすれば大体何とかなる(代入は結局のところメモリ参照のため、参照先が変われば代入された変数の値も変化する)

参考記事

1
1
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
1