For my personal homepage I wanted to load the latest tips from Handy Rails Tips as well as my most recent Tweets on twitter. As these resources are stored on different sites from my homepage, there was a little lag when loading the landing page.
I don’t tweet or post tips every day so it seemed a little unnecessary to have these loaded fresh with every hit to my site. Instead, updating them once a day seemed fine.
Here’s a quick tip for caching ActiveResource
resources or any other data that doesn’t necessarily need to be ‘hot off the press’.
Below is the Tip model for my homepage:
class Tip < ActiveResource::Base
self.site = "http://handyrailstips.com/"
def self.cached
return @@cached if @@last_cached == Date.today
@@last_cached = Date.today
@@cached = self.all
end
end
I wont cover the ins and outs of ActiveResource
here, but let’s have a look at the cached method:
the first line will return the value of the class variable @@cached
only if the @@last_cached
date is today. If not, we update @@last_cached
to equal today’s date and then re-set @@cached
to equal all tips (only 5 are returned from Handy Rails Tips). All subsequent calls to the cached method on this date will return the contents of @@cached
.
Then, in the controller all I had to add was:
class HomepagesController < ApplicationController::Base
# GET /
def index
@tips = Tip.cached
end
end
Simple!
For the tweets I took pretty much the same approach but did not use ActiveResource
.
class Tweet
require "net/http"
# a Net::HTTP object to be used for each request
HTTP_OBJ = Net::HTTP.new("twitter.com")
def self.cached
# return the cached tweets if they were cached today
return @cached_tweets if @last_cached == Date.today
# else, find the latest tweets and changed the cached date to today
@last_cached = Date.today
@cached_tweets = find_latest
end
def self.find_latest(no = 5)
response, xml = HTTP_OBJ.request_get "/statuses/user_timeline/gavin_morrice.xml?callback=twitterCallback2&count=#{no}"
# returns an array of new Tweets with the content of each <text> tag
Nokogiri( xml ).css("status").map { |status| new status.css("text").text }
end
attr_reader :text
def initialize( text )
@text = text
end
end
The twitter API returns quite a lot of XML so I used Nokogiri to pick out what I need, the status tags. Each of these are then parsed and their content loaded into a new Tweet object. Calling @tweet.text
returns the text content from this tweet.
Remember – by default, classes are not cached from one request to another in the development or test environments so to check this is working properly you’ll have to set cache_classes
to true in development.rb.
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the webserver when you make code changes.
config.cache_classes = true