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:

http://www.ruby-forum.com/topic/1744072

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