Welcome to Giant Robots Smashing Into Other Giant Robots — a weblog about development, business, design and technology — written by thoughtbot.
Pitfalls in RESTful "wizards"
In an application we’re currently building, users go through a wizard to order teams. We implemented this as RESTful controllers – teams, purchases, and orders.
The relevant wizard steps are:
- teams/new
- teams/:id/purchases/new
- orders/new
When each step is submitted, the related create action is called and the user is redirected to the next new action.
Pitfall: the user hits the back button.
On step 3, the user hits the back button. If they re-submit step 2, they will get a validation error because they cannot create two purchases for a team.
There’s a temptation here to stray from RESTful design. Don’t!
When the user hits the back button from step 3, we want to send them to purchases/edit for their newly-created object instead of purchases/new.
Solution: Force the browser to not cache
To ensure that the page isn’t cached by the browser and will always be re-fetched, we add a before_filter to the purchases controller which calls a private method on ApplicationController:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
before_filter :no_cache, :only => [:new] private def no_cache response.headers["Last-Modified"] = Time.now.httpdate response.headers["Expires"] = 0 # HTTP 1.0 response.headers["Pragma"] = "no-cache" # HTTP 1.1 'pre-check=0, post-check=0' (IE specific) response.headers["Cache-Control"] = 'no-store, no-cache, must-revalidate, max-age=0, pre-check=0, post-check=0' end |
Next, if the team already has a purchase, we redirect to the edit action using another before filter on the purchases controller:
1 |
before_filter :redirect_to_edit, :only => [:new], :if => :team_has_registration_purchase? |
#team_has_registration_purchase? is a method on the purchases controller. If the :if syntax is unfamiliar to you, its provided to us by our plugin, when.
Pitfall: ‘not caching’ only works in Firefox.
To the best of our knowledge, setting the HTTP headers should have worked in all browsers, but it did not work in Safari or in IE 6 and 7. A little more research proved that any page with an iframe on it will never be cached, and will always be refetched.
Solution: iframe
So, we add this to views/purchases/new:
<iframe style="height:0px;width:0px;visibility:hidden" src="about:blank">
this frame prevents back forward cache
</iframe>
This works. We now have cross-browser no-caching in a RESTful wizard.
The iframe hack feels a little dirty, though. Does anyone know a better way? Or, do we live with it, similar to using a hidden frame for “Ajax” file uploads with responds_to_parent ?
This concept might be useful outside of these more complex, wizard type controller actions, and might come in handy if you had just a normal restful controller where you wanted the user to get the edit action instead of the new action if they use the back button. Have you done something like this before, or can you think of a different way to accomplish that?
photo courtesy of Michael Porter via Flickr
About this entry
You're reading an entry on GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS, the company weblog of thoughtbot, inc.
- Author:
- Chad Pytel
- Published:
- April 25th 05:39 PM
- Updated:
- April 30th 08:55 AM
- Sections:
- Development
thoughtbot is hiring
We are hiring web developers and web designers in both Boston and New York, NY.
What are we up to?
We built Shoulda, an eclectic set of additions to Test::Unit; Paperclip to manage uploaded files without hassle; Jester, a REST/ActiveResource client library written in Javascript, and Squirrel, an enhancement for ActiveRecord's find syntax; — amongst some other projects.

Chad (President) and Jon (CTO) co-authored a technical book titled Pro Active Record: Databases with Ruby and Rails, which explores the ins and outs of the ActiveRecord ruby library. You can buy it today at Amazon.com.
About thoughtbot, inc.
We are a small web application development consulting business, with offices in Boston, MA and New York, NY. If you're looking to find a team for your next web development project or your new web application — get in touch.
12 comments
Jump to comment form