41

When I try to hit this action via Javascript, I get a 406 Not Acceptable error:

  def show
    @annotation = Annotation.find_by_id(params[:id])

    respond_to do |format|
      format.html {
         if @annotation.blank?
           redirect_to root_path
         else
           redirect_to inline_annotation_path(@annotation)
         end
       }

       format.js {
         if params[:format] == "raw"
           render :text => @annotation.body.to_s
         else
           render :text => @annotation.body.to_html
         end
       }
    end
  end

This is from jQuery, but I'm doing the right beforeSend stuff:

  $.ajaxSetup({ 
    beforeSend: function(xhr) {
      xhr.setRequestHeader("Accept", "text/javascript");
    },
    cache: false 
  });

Here are my request headers:

Host    localhost:3000
User-Agent  Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3
Accept  text/javascript
Accept-Language en-us,en;q=0.5
Accept-Encoding gzip,deflate
Accept-Charset  ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive  300
Connection  keep-alive
X-Requested-With    XMLHttpRequest
Content-Type    application/x-www-form-urlencoded
Tom Lehman
  • 85,973
  • 71
  • 200
  • 272
  • 1
    Please mark your answer as the correct one... never thought I add a comment concerning that, but it makes finding the answer so much easier. – erroric Jun 10 '13 at 17:08
  • Take a look here: http://stackoverflow.com/questions/25910031/jquery-autocomplete-throws-406-not-acceptable-error – Andrea Girardi Dec 29 '14 at 13:32

12 Answers12

30

I cracked the case!

I was sending a format parameter with my get request in order to tell the server to send me markdown instead of HTML. Here's my Javascript:

$.get("/annotations/" + annotation_id, {format: 'raw'}, function(data) {
});

and then I was looking for this parameter in the format.js block:

   format.js {
     if params[:format] == "raw"
       render :text => @annotation.body.to_s
     else
       render :text => @annotation.body.to_html
     end
   }

but apparently a format parameter confuses the respond_to block. I changed it from {format: 'raw'} to {markdown: 'true'} and it works.

I guess this is a bug in Rails?

Tom Lehman
  • 85,973
  • 71
  • 200
  • 272
  • 10
    This is not a bug but intended behaviour: Rails uses the Accept Headers and the format parameter to determine wether to respond with html, javascript, xml, json or something else. So in your case the format.js {} block was never called because Rails thought that you wanted something with the format "raw" and not something with the format "js". – severin May 25 '10 at 12:46
  • 2
    You're right — I should have registered a Markdown mimetype (http://stackoverflow.com/questions/2456219/add-a-custom-format-in-rails-that-will-work-with-respond-to) and added a `format.markdown` block – Tom Lehman May 26 '10 at 04:22
5

include "format.js" in your respond_to block

Dustin
  • 51
  • 1
  • 1
5

This happened to me when using HTTPRiot connecting to a JSON rendering web app from an iPhone app. It appears that the issue is due to Rails expecting an Accept HTTP header that it is well, comfortable with. As such, I used Firefox's LiveHTTPHeaders extension to see what headers work without a 406. In any case the Accept string that worked was:

text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Another area that I would examine is the JSON-producing controller. If the controller is missing a format directive to specify it can return JSON in response, that too may cause a 406 error.

yuvalz
  • 165
  • 2
  • 7
3

Check your application.js for require jquery_ujs

//= require jquery_ujs
Sergey
  • 738
  • 7
  • 11
2

Can you try without setting the Accept Header? It should actually work even without the Accept header.

Rishav Rastogi
  • 15,484
  • 3
  • 42
  • 47
2

Just use this code in controller action method format block:

format.js   { render :nothing => true }  
noroot
  • 142
  • 2
0

Is this served through Apache? You may want to take a look at http://forums.alwayswebhosting.com/showthread.php?p=8381, which describes scenarios where security policy interferes with requests.

EDIT: The URL referenced above advocates turning off request-sniffing security policy across an entire site, which makes the site vulnerable. Setting the SecFilterEngine option to Off in the .htaccess, which is what is prescribed in the URL, should be done only to zero in on the source of the problem. It should not be considered a long term solution.

David Andres
  • 31,351
  • 7
  • 46
  • 36
  • What does the data you intend to send back to the client as part of your response look like? It is JSON, HTML, JavaScript? – David Andres Sep 12 '09 at 08:29
  • I'm just sending back text (markdown to be precise), although this doesn't work from Javascript even if I comment out the contents of the `format.js` block (so I don't think what I'm sending is relevant). Also, this is happening on my local machine through Mongrel – Tom Lehman Sep 12 '09 at 18:42
  • If you aren't sending back javascript, then you don't need the "text/javascript" request header. Perhaps "text/plain" will be a better fit for your needs. – David Andres Sep 12 '09 at 18:49
0

If you are using jRails this was causing a lot of problems for me, here is my application.js file:

$(document).ready(function () {
    $.ajaxSetup({
        beforeSend: function (xhr) {
            xhr.setRequestHeader("Accept", "text/javascript, text/html, application/xml, text/xml, */*");
        }
    });
});
Garrett
  • 7,830
  • 2
  • 41
  • 42
0

For me it was a simple before_filter that was restricting a action that renders a js file, once I added the :except => [:action] to the before_filter block it was fine.

Darren
  • 1
0

Another insidious "Gotcha" here is if you call your controller with a form_for that accidentally has an additional not-necessary parameter. The additional parameter can be interpreted by Rails as a format request, and you'll get the 406.

Example:

= form_for parking_permit, url: permit_group_parking_permits_path(@permit_group.id, useless_id), method: :get do |f| ...

In the example above, you RAKE ROUTES and determine that permit_group_parking_permits_path does NOT need anything but the permit_group id...

If you see your method being called such as /model/action.1?blahblahblah that ".1" is your tip-off.

This will return the 406. We won't talk about how much time I spent on this once.

Dave Collins
  • 1,077
  • 1
  • 15
  • 23
0

I hit this problem when I forgot to add :remote => true to my Ajax form.

zishe
  • 10,665
  • 12
  • 64
  • 103
Guy Argo
  • 397
  • 4
  • 10
0

i was calling the url for js format but had this in the controller:

respond_to do |format|
  format.html 
end

this worked fine in Safari, but not with Firefox.

naturally i was missing something, should be:

respond_to do |format|
  format.html
  format.js
end

and now both browsers are fine.

manitu
  • 1,189
  • 10
  • 16