Problem

You’re enjoying the performance benefits of fragment caching, but managing the cache using sweepers is not really appropriate for some fragments. Instead, you’d rather have a “time to live” option for a cached fragment, so that the cache would be expired and the fragment regenerated only if it has passed a certain age.

Update: Code has been changed to work with Rails 2.3.5 and is now hosted at github.

Solution

Of course, there are many ways to skin this cat. In the end, I settled on somewhat of a hack. However, this solution will work no matter what storage option you are using for caching.

Basically, the plugin overrides cache and cache_erb_fragment, inserting an HTML comment into the beginning of the block of HTML being cached. This HTML comment contains a timestamp (using the to_i method on a Ruby Time object) which marks the time (in UTC) at which the fragment expires. The next time cache is called, the fragment gets read, the timestamp can be checked, and the fragment can be expired or preserved depending on the current time.

Examples

In a view:

1
2
3
4
5
6
  <% cache("some_fragment", :time_to_live => 5.minutes) do -%>
    This fragment was cached at 
      <%= Time.now.utc.strftime "%H:%M:%S on %m/%d/%Y" %> 
    and will expire at: 
      <%= 5.minutes.from_now.utc.strftime "%H:%M:%S on %m/%d/%Y" %> (UTC)
  <% end %>

In a controller:

1
2
3
4
  # instead of: read_fragment("some_fragment"), try:
  unless get_johnny_cache("some_fragment")
    # make some expensive DB queries
  end

Installation

script/plugin install git://github.com/jlapier/johnny_cache.git

(or use piston or whatever you prefer)

Notes

  • Remember: If you want to play with caching and you’re working in the development environment, you need to enable caching. Find the perform_caching line in environments/development.rb and change it to true, and restart your server. If you don’t make this change, you’re never caching any fragments, and therefore, this plugin won’t do anything for you (in development; caching is turned on by default for the production environment).
  • Updated to works in Rails 2.3.5; however, the tests no longer work.
  • I assume this only works for ERB fragment caching and not Haml (or any other HTML generator). However, the code for the plugin is pretty simple and it should be easy to adapt it to Haml if you desire. If you get it working with Haml and want to send me a patch, please feel free (jason.lapier AT gmail).

Rails Plugin: acts_as_fu

March 31st, 2008

We’ve all seen the job listings. We know what they’re looking for. Rockstars. Code Monkeys. Rails Ninjas.

And you’re left thinking, “But I’m just a programmer.” Well, not anymore. Today, you become a Rails Kung-Fu Master!

“Not me,” you say. “I’ve already tried using all the acts_as_something plugins and all the something_fu plugins; and I’m still not a Rockstar or a Ninja. I’m barely a Code Simian!”

Sounds like you’ve tried the rest – now try the best! That’s right: it’s the new and improved ActsAsFu Rails plugin!

Three Easy Steps to Becoming a Rails Kung-Fu Master:

1. Stop web server

mongrel_rails stop

2. Install Plugin

./script/plugin install http://svn.offtheline.net/plugins/acts_as_fu

3. Start web server

mongrel_rails start

(note: if you’re using mongrel_cluster, thin, piston, or anything like that, these instructions don’t apply to you – you figure it out yourself, you Rockstar Ninja!)

Now you’re on your way to programming stardom! Catch ya on fame’s backside, my friend!

Bonus Round: If you work on a team, don’t forget to check this awesome plugin into your repository (or as the ninjas say, svn ci -m ‘added l33t skillz’). Your teammates will undoubtedly be very impressed by your jujitsu karate haxxing abilities. If you push it up to your production server, your boss might even give you a raise!

I have been using Err’s acts_as_textiled plugin for making certain fields of an ActiveRecord model always display with textile formatting. It’s smart enough to know that when used in a input field, the data should be displayed unformatted. The nice thing about textiling a field is not worrying about bad HTML polluting your page or attempts at XSS.

Being that the acts_as_textiled plugin saves me from accidentally displaying a field without HTML stripping (like when I forget to use the handy <%=h erb shortcut), I started using it on fields all over the place. Sometimes, where not really appropriate.

For example, let’s say you have a User model and one of the attributes is “display_name”. Now if someone picks a name like “I*am*the*greatest*ever!”, I don’t care that they are using non-alpha-numeric characters. I just don’t want it to show up like “Iamthegreatestever!”

The problem was, I had been relying on acts_as_textiled to save me from bad HTML in that field, so now if I turn it off, someone can make their display_name “Run <script blah blah blah > or something” and I have all these places in my views where I left out the h in <%=h so I’m screwed. I needed another way to strip HTML without using textiled, but I wanted to be able to auto-strip where appropriate by setting up a model the same way acts_as_textiled does.

Enter: acts_as_stripped

From the README:

Strips HTML out of an attribute whenever it's displayed - even if it's in a form 
input box/textarea (for the purposes of this plugin, I'm considering HTML evil 
in the specified fields, no matter what). 
NOTE: no stripping happens when the attribute is written, only read.
NOTE: value is converted to string; so for example if you errantly list an integer 
attribute in the attribute list it's going to come back as a string.

Inspired by Err's acts_as_textiled, but I needed some attributes to be displayed 
without textile messing with underscores and asterisks. 

And I don't trust myself to sanitize HTML in views 100% of the time. 

Use like so: 

class SomeModel < ActiveRecord::Base
  acts_as_stripped :name, :description

    # ...
end

If you need to get the unstripped value, you can always use: 
your_model.attributes["att_name"]

Install with:

./script/plugin install http://svn.offtheline.net/plugins/acts_as_stripped/

(or just use svn or piston to import into your vendor/plugins directory)

Any feedback? Questions? Criticism? All welcome and appreciated.