开发者

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜