Question

I'm following Railscast #199 to allow my web app to be viewed in a mobile browser. It works great, except when I try to access information in a tabbed interface using UJS in the mobile version. Clicking on the tabs works in the web app, but on the mobile side I get a 406 error. (I tried this after setting the User Agent as iPhone in Safari. I also tested on iOS Simulator and my iPhone. Neither time loaded anything.)

Below is some code for one of the tabs. Can anyone can help me target what is going on? Here is my code.

Here's the profile_about action in profiles_controller.rb:

def profile_about
  @profile = Profile.find(params[:id])
  respond_to do |format|
    format.js { render :layout => nil }
  end
end

In my profiles/show.mobile.erb (this is the exact same code as in profiles/show.html.erb):

<div id="tabs">
  <ul id="infoContainer">
    <li><%= link_to "Cred", profile_cred_profile_path, :class=> 'active', :remote => true %></li>
    <li><%= link_to "About", profile_about_profile_path, :class=> 'inactive', :remote => true %></li>
  </ul>
  <div id="tabs-1">
  <%= render :partial => 'profile_cred' %>
  </div>
</div><!-- end tabs -->

(NOTE: I have a file for profiles/_profile_about.html.erb and profiles/_profile_about.mobile.erb.)

Here is my profiles/profile_about.js.erb:

$("#tabs-1").html("<%= escape_javascript(render(:partial => 'profile_about'))%>");

My Heroku logs showing the 406:

2012-03-08T03:02:55+00:00 app[web.1]: Started GET "/profiles/1/profile_about" for 98.218.231.113 at 2012-03-08 03:02:55 +0000
2012-03-08T03:02:55+00:00 heroku[router]: GET myapp.com/profiles/1/profile_about dyno=web.1 queue=0 wait=0ms service=14ms status=406 bytes=1
2012-03-08T03:02:55+00:00 app[web.1]:   Processing by ProfilesController#profile_about as JS
2012-03-08T03:02:55+00:00 app[web.1]:   Parameters: {"id"=>"1"}
2012-03-08T03:02:55+00:00 app[web.1]: Completed 406 Not Acceptable in 3ms
2012-03-08T03:02:55+00:00 heroku[nginx]: 98.218.231.113 - - [08/Mar/2012:03:02:55 +0000] "GET /profiles/1/profile_about HTTP/1.1" 406 1 "http://myapp.com/profiles/1" "Mozilla/5.0 (iPhone; CPU iPhone OS 5_0_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A405 Safari/7534.48.3" myapp.com

From running tail -f logs/development.log:

Started GET "/profiles/1/profile_about" for 127.0.0.1 at Wed Mar 07 22:35:36 -0500 2012
  Processing by ProfilesController#profile_about as JS
  Parameters: {"id"=>"1"}
  PK and serial sequence (5.4ms)   SELECT attr.attname, seq.relname
 FROM pg_class seq,
 pg_attribute attr,
 pg_depend dep,
 pg_namespace name,
 pg_constraint cons
 WHERE seq.oid = dep.objid
 AND seq.relkind = 'S'
 AND attr.attrelid = dep.refobjid
 AND attr.attnum = dep.refobjsubid
 AND attr.attrelid = cons.conrelid
 AND attr.attnum = cons.conkey[1]
 AND cons.contype = 'p'
 AND dep.refobjid = '"goals_profiles"'::regclass
  PK and custom sequence (2.5ms)   SELECT attr.attname,
 CASE
 WHEN split_part(def.adsrc, '''', 2) ~ '.' THEN
 substr(split_part(def.adsrc, '''', 2),
 strpos(split_part(def.adsrc, '''', 2), '.')+1)
 ELSE split_part(def.adsrc, '''', 2)
 END
 FROM pg_class t
 JOIN pg_attribute attr ON (t.oid = attrelid)
 JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
 JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
 WHERE t.oid = '"goals_profiles"'::regclass
 AND cons.contype = 'p'
 AND def.adsrc ~* 'nextval'

  Profile Load (1.3ms)  SELECT "profiles".* FROM "profiles" WHERE "profiles"."id" = '1' LIMIT 1
Completed 406 Not Acceptable in 30ms
Was it helpful?

Solution 3

Turns out this was due to a lacking check for an xhr request in the prepare_for_mobile method. I found the answer in another question. So the below prepare_for_mobile method allows the JS to work:

def prepare_for_mobile
  session[:mobile_param] = params[:mobile] if params[:mobile]
  request.format = :mobile if mobile_device? && !request.xhr?
end

OTHER TIPS

There's a few bugs in your code, maybe it's just stackoverflow formatting here but the inner quotes should be ' instead of " , like this:

$("#tabs-1").html("<%= escape_javascript(render(:partial => 'profile_about'))%>");

And this line is casuing your error:

format.mobile.js {render :layout => nil}

This is impossible because the request can only have a single mime type. "mobile" or "js", not both. If you are requesting the "profile_about" action from javascript, then you must respond back to it with js. "format.mobile" should only be used to render a "profile_about.mobile" template.

Hopefully that's at least a step in the right direction for you.

Probably don't fully answer your question but I was having the 406 status problem, because I've been deploying my app to Phonegap! It basically happened because the request type didn't match any of the Rails responders in the action.

it was like:

respond_to do |format|
  format.json {
    render( json: (@parishes) )
  }
end

Since I only used it to responde to JSON I changed and it now works:

    render( json:(@parishes) )

A more complete way to deal with this is to figure exactly what responder is being asked for that request, or default to something you know to work

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top