request.format = :mobile causes error "undefined method `ref' for nil:NilClass"

I have a strange problem with setting request.format = :mobile

I can reproduce this problem on a completely fresh Rails 3.0.7 app with no special gems. This seemed to work well in Rails 2 but for some reason is hiccuping here, not sure what's different in Rails 3 that makes this hiccup. If you look at the stack track, it doesn't even pass through my app stack once -- weird -- maybe this is a problem with Passenger? Anyone see anything i'm doing wrong here? Your tips are much appreciated, this is baffling me.

Step-by-step instructions to reproduce:

Totally fresh rails app (rails new test_mobile), then go delete public/ index.html

routes.rb __________________________________

TestMobile::Application.routes.draw do   root :to => "application#welcome" end

application_controller.rb __________________________

class ApplicationController < ActionController::Base   protect_from_forgery

  def welcome     render "welcome/index"   end

  before_filter :check_mobile

  def check_mobile     request.format = :mobile if request.env["HTTP_USER_AGENT"] =~ / iPhone/   end end

views/welcome/index.html.erb ______________________________________

this is my regular site

views/welcome/index.mobile.erb ____________________________________

this is my mobile site

That's it -- those are all the steps one needs to take to reproduce this, no gem configuration necessary.

Set it up with Passenger (as test-mobile.local), go to Safrai, load test-mobile.local, you get "this is my regular site". Then switch Develop > User Agent to "Safari iOS 4.1", reload the page, and bam:

NoMethodError in ApplicationsController#welcome

undefined method `ref' for nil:NilClass Rails.root: /Users/jason/Projects/DEVELOPMENT/ROR/test_mobile

Application Trace | Framework Trace | Full Trace activesupport (3.0.7) lib/active_support/whiny_nil.rb:48:in `method_missing' actionpack (3.0.7) lib/action_controller/metal/rendering.rb:10:in `process_action' actionpack (3.0.7) lib/action_controller/metal/rendering.rb:10:in `map' actionpack (3.0.7) lib/action_controller/metal/rendering.rb:10:in `process_action' actionpack (3.0.7) lib/abstract_controller/callbacks.rb:18:in `process_action' activesupport (3.0.7) lib/active_support/callbacks.rb:441:in `_run__2115867319__process_action__733682996__callbacks' activesupport (3.0.7) lib/active_support/callbacks.rb:410:in `send' activesupport (3.0.7) lib/active_support/callbacks.rb:410:in `_run_process_action_callbacks' activesupport (3.0.7) lib/active_support/callbacks.rb:94:in `send' activesupport (3.0.7) lib/active_support/callbacks.rb:94:in `run_callbacks' actionpack (3.0.7) lib/abstract_controller/callbacks.rb:17:in `process_action' actionpack (3.0.7) lib/action_controller/metal/instrumentation.rb: 30:in `process_action' activesupport (3.0.7) lib/active_support/notifications.rb:52:in `instrument' activesupport (3.0.7) lib/active_support/notifications/instrumenter.rb: 21:in `instrument' activesupport (3.0.7) lib/active_support/notifications.rb:52:in `instrument' actionpack (3.0.7) lib/action_controller/metal/instrumentation.rb: 29:in `process_action' actionpack (3.0.7) lib/action_controller/metal/rescue.rb:17:in `process_action' actionpack (3.0.7) lib/abstract_controller/base.rb:119:in `process' actionpack (3.0.7) lib/abstract_controller/rendering.rb:41:in `process' actionpack (3.0.7) lib/action_controller/metal.rb:138:in `dispatch' actionpack (3.0.7) lib/action_controller/metal/rack_delegation.rb: 14:in `dispatch' actionpack (3.0.7) lib/action_controller/metal.rb:178 actionpack (3.0.7) lib/action_dispatch/routing/route_set.rb:62:in `call' actionpack (3.0.7) lib/action_dispatch/routing/route_set.rb:62:in `dispatch' actionpack (3.0.7) lib/action_dispatch/routing/route_set.rb:27:in `call' rack-mount (0.6.14) lib/rack/mount/route_set.rb:148:in `call' rack-mount (0.6.14) lib/rack/mount/code_generation.rb:93:in `recognize' rack-mount (0.6.14) lib/rack/mount/code_generation.rb:68:in `optimized_each' rack-mount (0.6.14) lib/rack/mount/code_generation.rb:92:in `recognize' rack-mount (0.6.14) lib/rack/mount/route_set.rb:139:in `call' actionpack (3.0.7) lib/action_dispatch/routing/route_set.rb:493:in `call' actionpack (3.0.7) lib/action_dispatch/middleware/ best_standards_support.rb:17:in `call' actionpack (3.0.7) lib/action_dispatch/middleware/head.rb:14:in `call' rack (1.2.2) lib/rack/methodoverride.rb:24:in `call' actionpack (3.0.7) lib/action_dispatch/middleware/params_parser.rb: 21:in `call' actionpack (3.0.7) lib/action_dispatch/middleware/flash.rb:182:in `call' actionpack (3.0.7) lib/action_dispatch/middleware/session/ abstract_store.rb:149:in `call' actionpack (3.0.7) lib/action_dispatch/middleware/cookies.rb:302:in `call' activerecord (3.0.7) lib/active_record/query_cache.rb:32:in `call' activerecord (3.0.7) lib/active_record/connection_adapters/abstract/ query_cache.rb:28:in `cache' activerecord (3.0.7) lib/active_record/query_cache.rb:12:in `cache' activerecord (3.0.7) lib/active_record/query_cache.rb:31:in `call' activerecord (3.0.7) lib/active_record/connection_adapters/abstract/ connection_pool.rb:354:in `call' actionpack (3.0.7) lib/action_dispatch/middleware/callbacks.rb:46:in `call' activesupport (3.0.7) lib/active_support/callbacks.rb:416:in `_run_call_callbacks' actionpack (3.0.7) lib/action_dispatch/middleware/callbacks.rb:44:in `call' rack (1.2.2) lib/rack/sendfile.rb:107:in `call' actionpack (3.0.7) lib/action_dispatch/middleware/remote_ip.rb:48:in `call' actionpack (3.0.7) lib/action_dispatch/middleware/show_exceptions.rb: 47:in `call' railties (3.0.7) lib/rails/rack/logger.rb:13:in `call' rack (1.2.2) lib/rack/runtime.rb:17:in `call' activesupport (3.0.7) lib/active_support/cache/strategy/local_cache.rb: 72:in `call' rack (1.2.2) lib/rack/lock.rb:11:in `call' rack (1.2.2) lib/rack/lock.rb:11:in `synchronize' rack (1.2.2) lib/rack/lock.rb:11:in `call' actionpack (3.0.7) lib/action_dispatch/middleware/static.rb:30:in `call' railties (3.0.7) lib/rails/application.rb:168:in `call' railties (3.0.7) lib/rails/application.rb:77:in `send' railties (3.0.7) lib/rails/application.rb:77:in `method_missing' passenger (2.2.10) lib/phusion_passenger/rack/request_handler.rb:92:in `process_request' passenger (2.2.10) lib/phusion_passenger/abstract_request_handler.rb: 207:in `main_loop' passenger (2.2.10) lib/phusion_passenger/rack/application_spawner.rb: 118:in `run' passenger (2.2.10) lib/phusion_passenger/rack/application_spawner.rb: 65:in `spawn_application' passenger (2.2.10) lib/phusion_passenger/utils.rb:184:in `safe_fork' passenger (2.2.10) lib/phusion_passenger/rack/application_spawner.rb: 58:in `spawn_application' passenger (2.2.10) lib/phusion_passenger/rack/application_spawner.rb: 41:in `spawn_application' passenger (2.2.10) lib/phusion_passenger/spawn_manager.rb:159:in `spawn_application' passenger (2.2.10) lib/phusion_passenger/spawn_manager.rb:287:in `handle_spawn_application' passenger (2.2.10) lib/phusion_passenger/abstract_server.rb:352:in `__send__' passenger (2.2.10) lib/phusion_passenger/abstract_server.rb:352:in `main_loop' passenger (2.2.10) lib/phusion_passenger/abstract_server.rb:196:in `start_synchronously' passenger (2.2.10) bin/passenger-spawn-server:61 Request

Parameters:

{"format"=>"mobile"} Show session dump

Show env dump

Response

Headers:

None

I have a strange problem with setting request.format = :mobile

I can reproduce this problem on a completely fresh Rails 3.0.7 app

with no special gems. This seemed to work well in Rails 2 but for some

reason is hiccuping here, not sure what’s different in Rails 3 that

makes this hiccup. If you look at the stack track, it doesn’t even

pass through my app stack once – weird – maybe this is a problem

with Passenger? Anyone see anything i’m doing wrong here? Your tips

are much appreciated, this is baffling me.

Step-by-step instructions to reproduce:

Totally fresh rails app (rails new test_mobile), then go delete public/

index.html

routes.rb __________________________________

TestMobile::Application.routes.draw do

root :to => “application#welcome”

end

application_controller.rb __________________________

class ApplicationController < ActionController::Base

protect_from_forgery

def welcome

render "welcome/index"

end

before_filter :check_mobile

def check_mobile

request.format = :mobile if request.env["HTTP_USER_AGENT"] =~ /

iPhone/

end

end

views/welcome/index.html.erb ______________________________________

this is my regular site

views/welcome/index.mobile.erb ____________________________________

this is my mobile site

That’s it – those are all the steps one needs to take to reproduce

this, no gem configuration necessary.

Set it up with Passenger (as test-mobile.local), go to Safrai, load

test-mobile.local, you get “this is my regular site”. Then switch

Develop > User Agent to “Safari iOS 4.1”, reload the page, and bam:

NoMethodError in ApplicationsController#welcome

Hmm, are you sure that your routes.rb file contains the singular form “application#welcome” and not “applications#welcome” (note the “s” on “applications”). What does “rake routes” return?

It looks to me like your :root route is mapping to “applications#welcome” (plural) as if you’ve got: root :to => “applications#welcome”

The only way to know if it is the routing is to have a rake routes dump.

request.format = :mobile if request.user_agent =~ /Mobile|webOS|iPhone/

Thanks for the feedback. No my problem was that I didn’t (/realize I had to) set the MIME type for “mobile” in config/initializers/mime_types.rb

Mime::Type.register_alias “text/html”, :mobile

That’s what I was missing – I’m sure of it cause it worked fine after I set that correctly.

If the error message from Rails said “You didn’t set a MIME type in config/initializers/mime_types.rb for the format :mobile” that would be more helpful. It makes perfect sense-- I just didn’t realize that was a necessary step.

I misread what you posted - my mistake. You also need to set the mime type, as you stated.

You might also want to do the following, which will make it simpler for you down the road where managing your views can be a bit tedious.

In application.rb set a config for:

paths.app.views << "app/views/mobile"

Then you can just keep your mobile views separate from other views.

i.e.

\views \views\home \views\layouts \views\mobile \views\users etc.

and in \mobile you would have

\mobile \mobile\home\index.mobile \mobile\layouts\application.mobile \mobile\users\index.mobile etc.

If you want to see some testing scenarios for mobile rails look at this:

I wrote it a few days ago. Glad you got it working.