- 自分用のメモを公開したものです。ドキュメント/ソースコード等をまとめただけで試していないコードも多いので、信頼性は低いです。
request_storeとは?
導入
1. インストール
gem 'request_store'
$ bundle
2. 使ってみる
before_action :set_current_user
def set_current_user
RequestStore.store[:current_user] = current_user
end
RequestStore.store[:current_user]
類似機能との比較
Thread.current
- スレッドローカル変数。つまりスレッド単位でグローバルな変数。(ドキュメントには
not thread-local but fiber-local
と書いてあったが違いがわからんかった。fiber使わんし難しい...)
- request_storeは内部でコレ使ってる
Thread.current[:foo] = 0
Thread.current[:foo]
問題点
- アプリサーバはリクエスト1回分でスレッドが終了せず、次のリクエストも同じスレッドで処理する。その際に値がリセットされていないので、前回の値を持ち越してしまう
def index
Thread.current[:counter] ||= 0
Thread.current[:counter] += 1
render :text => Thread.current[:counter]
end
Webrickでは問題ないらしい
ActiveSupport::CurrentAttributes
使い方
class Current < ActiveSupport::CurrentAttributes
attribute :user
end
class ApplicationController < ActionController::Base
before_action :set_current_user
def set_current_user
Current.user = currrent_user
end
end
Current.user
使う際の注意点
グルーバルにアクセスできちゃう
リクエスト毎にマルチスレッド使うのはNG
テスト
def app
Rack::Builder.new do
use RequestStore::Middleware
run MyApp
end
end
Rails以外で使う
use RequestStore::Middleware
ざっくりコードリーディング
request_store.gemspec
lib/request_store.rb
RequestStore
Thread.current[:request_store]
を便利に扱えるようにしたラッパーのようなクラス
module RequestStore
def self.store
Thread.current[:request_store] ||= {}
end
...
end
lib/request_store/middleware.rb
RequestStore::Middleware
- レスポンス時に
Thread.current[:request_store]
をクリアするRackミドルウェア
def call(env)
RequestStore.begin!
response = @app.call(env)
returned = response << Rack::BodyProxy.new(response.pop) do
RequestStore.end!
RequestStore.clear!
end
ensure
unless returned
RequestStore.end!
RequestStore.clear!
end
end
lib/request_store/railtie.rb
参考URL