Returning HTML in the JS portion of a respond_to block throws errors in IE
Here's a common pattern in my controller actions:
respond_to do |format|
format.html {}
format.js {
render :layout => false
}
end
I.e., if the request is non-AJAX, I'll send the HTML content in a layout on a brand new page. If the request is AJAX, I'll send down the same content, but without a layout (so that it can be inserted into the existing page or put into a lightbox o开发者_如何学运维r whatever).
So I'm always returning HTML in the format.js
portion, yet Rails sets the Content-Type response header to text/javascript
. This causes IE to throw this fun little error message:
alt text http://dl.dropbox.com/u/2792776/screenshots/Screen%20shot%202010-02-25%20at%205.13.49%20PM.png
Of course I could set the content-type of the response every time I did this (or use an after_filter
or whatever), but it seems like I'm trying to do something relatively standard and I don't want to add additional boilerplate code.
How do I fix this problem? Alternatively, if the only way to fix the problem is to change the content-type of the response, what's the best way to achieve the behavior I want (i.e., sending down content with layout for non-AJAX and the same content without a layout for AJAX) without having to deal with these errors?
Edit: This blog post has some more info
Does this work for you?
respond_to do |format|
format.html { :layout => false if request.xhr? }
format.js {}
end
And then call the response as HTML, not JS (I have not tested it though.)
Basically, request.xhr? is the key for this solution
The problem is that the response is sending the Content-Type
header as text/javascript
which IE then tries to interpret as javascript, hence the missing ')' error message. You need the server to send response as type text/html
so that the browser will not attempt to parse and execute the response content as a script but will allow you to use it as a block of HTML.
You can do this in Rails by adding something like the following to one of your controllers:
@headers["Content-Type"] = "text/html"
For example, you might add this to your Application Controller as follows:
class ApplicationController < ActionController::Base
before_filter :fix_ct
def fix_ct
@headers["Content-Type"] = "text/html"
end
end
IE doesn't understand the response as HTML. So either you change the header of the response, or test change the request method to GET.
If you're trying to send back HTML, you've got to do:
render(:update) do |page|
page['someDomId'].replace/replace_html(render(:partial => '/partial/path'))
end
Let PrototypeJS do what it does on the front end and your DOM id will have its content replaced automatically. Note that replace will replace the DOM id with that content, replace_html will only replace the innerHTML.
in the past i have run into similar issues with IE. here is how I solved it
if request.xhr?
render 'report', :layout => false
else
render 'report'
end
The root of your problem relies in the prototype Automatic JavaScript response evaluation: http://api.prototypejs.org/ajax/ajax/request.html
Your link_to_remote
calls generate a js piece similar to:
<a href="#" onclick="
new Ajax.Updater('posts', '/blog/destroy/3', {
asynchronous:true,
evalScripts:true
}); return false;
">Delete this post</a>
If you don't need to eval the response nowhere in your application you may globally override the link_to_remote
helper to generete the JS without evalScripts:true
If the u still need to eval the response in some parts, make a custom link_to_remote_no_eval
helper that does not generate a JS with evalScripts:true
, ie :
<a href="#" onclick="
new Ajax.Updater('posts', '/blog/destroy/3', {
asynchronous:true
}); return false;
">Delete this post</a>
Edit
In that case why not use a custom content type?
Mime::Type.register "text/html-piece", :html_piece
# add to view in jquery call instead of "text/javascript"
# then in your controller action
def show
respond_to do |format|
format.html { }
format.html_piece { } # no longer js mime so no IE error
end
end
精彩评论