views:

301

answers:

6

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 or 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

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

A: 

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.

nanda
A: 

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.

rob.sterner
No, I'm trying to send HTML back to the client (without a layout -- hence `:layout => false`)
Horace Loeb
Okay, well your example wasn't really clear about your intent. Regardless I updated my answer, you need to render an RJS response using render(:update) as indicated.
rob.sterner
A: 

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 jquerry 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
clyfe
I am not using prototype (or any of the javascript helpers). I'm using jQuery and setting the content-type of my AJAX requests to `text/javascript` in order to trigger the JS part of the `respond_to` block
Horace Loeb
The initial reasoning might still hold with jQuery, make sure you are not evaluating the response text (setting the dataType param to "html"might help).
clyfe
I am not evaling the response text (I assume doing that would generate errors in all browsers (not just IE))
Horace Loeb
A: 

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
Dustin Fineout
A: 

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
so1o
+1  A: 

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

ramonrails
Agree -- here's a shorter way to write it: `render :layout => !request.xhr?`
Horace Loeb