In the first part, I explained how you could
Display ads from TextLinkAds in a rails application.
This created the basis for today’s addition: caching.
You know that the ads won’t change that often, and saving your bandwith and CPU cycle (and TextLinkAds too) is not too much to ask.
One way to achieve that is to use the fragment cache provided by Ruby on Rails. It does not however provide expiration dates. To add expiration, you can use 2 related elements, one for storing the expiration, one to store the actual data.
Firt you need to generate the names of the 2 keys:
def fragment_key(name)
return “TLA/TIME/#{name}”, “TLA/DATA/#{name}”
end
and here, the logic to check whether the cache is present, and has not expired.
def content
url = “http://www.text-link-ads.com/xml.php?inventory_key=”+@sb_config[‘key’]+”&referer=”+CGI::escape(@request.env[‘REQUEST_URI’])
agent = “&user_agent=”+CGI::escape(@request.env[‘HTTP_USER_AGENT’])
url_time, url_data = fragment_key(url)
#is it time to update the cache?
time = read_fragment(url_time)
if (time == nil) || (time.to_time < Time.now)
@links = request(url+agent) rescue nil
#if we can get the latest, then update the cache
if @links != nil
expire_fragment(url_time)
expire_fragment(url_data)
write_fragment(url_time, Time.now+6.hour)
write_fragment(url_data, @links)
else
#otherwise try again in 1 hour
write_fragment(url_time, Time.now+1.hour)
@links = read_fragment(url_data)
end
else
#use the cache
@links = read_fragment(url_data)
end
end
In case the request to TextLinkAds fails (@links is nil), for whatever reason, you keep the cache for one extra hour till you make an other attempt.
And to make the code complete, here are the needed files to include and other needed helper functions:
require 'net/http'
require 'cgi'
def request(url)
XmlSimple.xml_in(http_get(url))
end
# Does an HTTP GET on a given URL and returns the response body
def http_get(url)
Net::HTTP.get_response(URI.parse(url)).body.to_s
end
So this takes care of caching the calls to TextLinkAds. You may not be done, though. Depending on the app you use, and its caching strategy, you may have another problem to solve. Your app may be caching your pages and actions, which may cause your links from TextLinkAds never to be updated. One solution is to use an approach similar to the one used by typo as described by Scott Laird and use caches_action_with_params from *scottstuff*.
This can wrap any method in your controller, and provide you the ability to control the longevity of your application’s cache simply by setting the lifetime value in the response:
response.lifetime = 6.hour
So for an application like typo, the code would be:
def content
response.lifetime = 6.hour
url = "http://www.text-link-ads.com/xml.php?inventory_key="+@sb_config['key']+"&referer="+CGI::escape(@request.env['REQUEST_URI'])
agent = "&user_agent="+CGI::escape(@request.env['HTTP_USER_AGENT'])
url_time, url_data = fragment_key(url)
#is it time to update the cache?
time = read_fragment(url_time)
if (time == nil) || (time.to_time < Time.now)
@links = request(url+agent) rescue nil
#if we can get the latest, then update the cache
if @links != nil
expire_fragment(url_time)
expire_fragment(url_data)
write_fragment(url_time, Time.now+6.hour)
write_fragment(url_data, @links)
else
#otherwise try again in 1 hour
write_fragment(url_time, Time.now+1.hour)
@links = read_fragment(url_data)
end
else
#use the cache
@links = read_fragment(url_data)
end
end
As time permits, I’ll be posting my sidebar plugin for typo to provide a nice UI to set your TextLinkAds account and referral id.
nice post, I was just looking for a way to add text-links-ads on my typo blog.
Do you still plan to make a typo plugin?
yes, definitely. In fact, I have had the plugin running for some time here and it is just a matter of packaging it with a readme. Now that I’m back home, I should be able to get to it. How does the this weekend sound?
Frederic, I released the plugin and you can download it from http://blog.nanorails.com/articles/2006/06/10/textlinkads-typo-sidebar-plugin