Wayne Kao
Wayne Kao

Reputation: 8285

Rails per-request hash?

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

Answers (7)

Maximo Mussini
Maximo Mussini

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

Alex Lang
Alex Lang

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

cwninja
cwninja

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

wombleton
wombleton

Reputation: 8376

Memoisation?

According to this railscast it's stored per request.

Upvotes: 0

Josh Rickard
Josh Rickard

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

Andrew Peters
Andrew Peters

Reputation: 11333

Have you considered flash? It uses Session but is automatically cleared.

Upvotes: 0

womble
womble

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

Related Questions