views:

70

answers:

2

I have an expensive (time-consuming) external request to another web service I need to make, and I'd like to cache it. So I attempted to use this idiom, by putting the following in the application controller:

def get_listings
  cache(:get_listings!)
end

def get_listings!
  return Hpricot.XML(open(xml_feed))
end

When I call get_listings! in my controller everything is cool, but when I call get_listings Rails complains that no block was given. And when I look up that method I see that it does indeed expect a block, and additionally it looks like that method is only for use in views? So I'm guessing that although it wasn't stated, that the example is just pseudocode.

So my question is, how do I cache something like this? I tried various other ways but couldn't figure it out. Thanks!

+3  A: 

an in-code approach could look something like this:

def get_listings
  @listings ||= get_listings!
end

def get_listings!
  Hpricot.XML(open(xml_feed))
end

which will cache the result on a per-request basis (new controller instance per request), though you may like to look at the 'memoize' helpers as an api option.

If you want several requests to use the same cached result this probably doesn't help much though.

In that case I'm not aware of a built-in mechanism (though may have missed it) but you may be able to store the result in database and refresh it if it's older than a certain age (compare timestamps and Time.now) or perhaps have a file dump of the query which you refresh with a cron job or similar.

nruth
Yeah, I definitely want to cache it between requests. I had considered storing it in the database and doing it all manually, but I'm hoping there's an easier way of doing it.
Brandon Weiss
Maybe take a look at the docs/api for ActiveSupport::Cache::Store - might fit what you're after. I've not worked with it myself but am sure there's blog posts on it or others here who have used this e.g. with memcached.
nruth
A: 

As nruth suggests, Rails' built-in cache store is probably what you want.

Try:

def get_listings
  Rails.cache.fetch(:listings) { get_listings! }
end

def get_listings!
  return Hpricot.XML(open(xml_feed))
end

fetch() retrieves the cached value for the specified key, or writes the result of the block to the cache if it doesn't exist.

By default, the Rails cache uses file store, but in a production environment, memcached is the preferred option.

See section 2 of http://guides.rubyonrails.org/caching_with_rails.html for more details.

Sidane