The reason why wrote up my rant about not getting too exited about REST is that I had some fun time paying for my blind usage of REST.
While developing Webistrano I thought that this would be a nice project for playing with all the RESTful stuff that Rails currently offers. So I started to map my resources and thereby only allowing certain HTTP verbs to certain URLs.
This all works nice until reality in the form of IE hunts you down.
Until recently all my Ajax calls used HTTP POST for getting updates from the server. I used POST for so long that I didn't remember why. In Webistrano I use Ajax to periodically get status updates on a running deployment. As getting status updates translates perfectly to HTTP GET on the resource I used this code for it:
# controller
def show
@deployment = @stage.deployments.find(params[:id])
respond_to do |format|
format.html # show.rhtml
format.xml { render :xml => @deployment.to_xml }
format.js { render :partial => 'status' }
end
end
# view _status.rhtml
<% unless @deployment.completed? %>
<script type="text/javascript">
function update_status(){
new Ajax.Updater('status_info','<%=h project_stage_deployment_path(current_project, current_stage, @deployment) %>',{
method: 'get',
evalScripts: true
});
}
setTimeout(update_status, 3000);
</script>
<% end %>
This worked nicely in Safari and Firefox but Internet Explorer would update the status-div with the whole page. So you got the page-in-a-page effect. I've spend several hours trying to debug from where IE was getting this strange output and why there were no requests to the server. And then I found the answer and remembered why in the past I always used HTTP POST for my Ajax calls.
IE was caching the GET Ajax call.
In order to prevent IE from caching Ajax calls your need to either supply different parameters on each request or switch to POST. Switching to POST is not so easy as Rails will not allow POST requests to the .../deployments/1 resource. So unique parameters on each request it is:
# view _status.rhtml
<% unless @deployment.completed? %>
<script type="text/javascript">
function update_status(){
new Ajax.Updater('status_info','<%=h project_stage_deployment_path(current_project, current_stage, @deployment) %>',{
method: 'get',
evalScripts: true,
parameters: {
random_differentiator: Math.floor(Math.random()*50000) // work around IE caching bug
}
});
}
setTimeout(update_status, 3000);
</script>
<% end %>
The alternative would be to define a custom action on the deployment resource that would answer to a HTTP POST but this destroys the whole "one resource URL, different representations" REST thing.
So long for RESTful Web Applications with IE.

What if you explicitly add the .js extension to the url in the periodical updater?
formatted_project_stage_deployment_path(current_project, current_stage, @deployment, :js)
Does that get around IE’s caching?
That’s an IE bug that I didn’t know about. I’ll keep that in mind when writing ajax against a restful controller. Would it be easier to set a parameter variable to the current time in your ajax call?
Are you sure that using POST is the only option? What about setting the Cache-Control and Expires headers for the response so that IE doesn’t store it in its cache? Searching for IE and “Cache-Control” returns several articles on how to do this. Hopefully this helps.
@Tammer:
Yes, you are right, using the current time would be a better solution.
@Dan:
I havent tried setting Cache-Control yet, but I also did not want to have extra header calls in development mode. In production I globally set the expire header through Apache. BTW Rails always sets the ‘Cache-Control: private’ header, so IE should not cache at all.
NM my previous comment, I misunderstood the issue here.
I just did a test—you can successfully tunnel a GET request via POST, using the _method parameter.
new Ajax.Updater(‘status_info’,’<%=h project_stage_deployment_path(current_project, current_stage, @deployment) %>’,{ method: ‘post’, postBody: ‘_method=get’, evalScripts: true });
I just noticed that the most recent version of jQuery has the current time hack built-in to its Ajax method—when you set the ‘cache’ option to ‘false’, it adds a parameter named ’_’ to the querystring with a value of (new Date()).getTime().
Would be a nice feature to add to Prototype—you’d just set ‘cache’ to ‘false’ and you’d be good to go.
Hi,
We’ve had the same problem. I think our fix is actually checked into Edge Rails.
Give this a go in your cache-control header:
private, max-age=0, must-revalidate
Result of many hours reading caching write-ups :)
A better way is to add a datetimestamp to the url of the request for ALL Ajax requests.
Something like this …
Ajax.Responders.register ( { onCreate: function(o_Requester) { // Timestamp each AJAX action. var o_Date = new Date(); o_Requester.url = o_Requester.url + (o_Requester.url.indexOf(’?’) == -1 ? ’?’ : ‘&’) + ‘Stamp=’ + o_Date.getTime(); } } );