This post originated from an RSS feed registered with Ruby Buzz
by Jonathan Weiss.
Original Post: IE doesn't let us REST
Feed Title: BlogFish
Feed URL: http://blog.innerewut.de/feed/atom.xml
Feed Description: Weblog by Jonathan Weiss about Unix, BSD, security, Programming in Ruby, Ruby on Rails and Agile Development.
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.