简体   繁体   中英

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.

  • Memcached doesn't work because it'll be shared across requests, which I don't want.
  • A global variable similarly doesn't work because different requests would share the same data, which isn't what I want.
  • Instance variables don't work because I want to access the data from inside different classes.

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]

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 }

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] = []

Global variables are evil. Work out how to cleanly pass the data you want to where you want to use it.

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

Memoisation ?

According to this railscast it's stored per request.

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" (ie 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM