Reputation: 8285
Is there a way to cache per-request data in Rails? For a given Rails/mongrel request I have the result of a semi-expensive operation that I'd like to access several times later in that request. Is there a hash where I can store and access such data?
It needs to be fairly global and accessible from views, controllers, and libs, like Rails.cache and I18n are.
I'm ok doing some monkey-patching if that's what it takes.
Upvotes: 18
Views: 5407
Reputation: 1361
One of the most popular options is to use the request_store
gem, which allows you to access a global store that you from any part of your code. It uses Thread.current
to store your data, and takes care of cleaning up the data after each request.
RequestStore[:items] = []
Be aware though, since it uses Thread.current
, it won't work properly in a multi-threaded environment where you have more than one thread per request.
To circumvent this problem, I have implemented a store that can be shared between threads for the same request. It's called request_store_rails
, it's thread-safe, and the usage is very similar:
RequestLocals[:items] = []
Upvotes: 2
Reputation: 1308
There is also the request_store gem. From the documentation:
Add this line to your application's Gemfile:
gem 'request_store'
and use this code to store and retrieve data (confined to the request):
# Set
RequestStore.store[:foo] = 0
# Get
RequestStore.store[:foo]
Upvotes: 6
Reputation: 9778
Try PerRequestCache. I stole the design from the SQL Query Cache.
Configure it up in config/environment.rb
with:
config.middleware.use PerRequestCache
then use it with:
PerRequestCache.fetch(:foo_cache){ some_expensive_foo }
Upvotes: 5
Reputation: 1603
app/models/my_cacher.rb
class MyCacher
def self.result
@@result ||= begin
# do expensive stuff
# and cache in @@result
end
end
end
The ||= syntax basically means "do the following if @@result is nil" (i.e. not set to anything yet). Just make sure the last line in the begin/end block is returning the result.
Then in your views/models/whatever you would just reference the function when you need it:
MyCacher.result
This will cache the expensive action for the duration of a request.
Upvotes: -3
Reputation: 11333
Have you considered flash? It uses Session but is automatically cleared.
Upvotes: 0
Reputation: 12407
Global variables are evil. Work out how to cleanly pass the data you want to where you want to use it.
Upvotes: -2