iPhone subdomains with Rails

Posted by Luke Francl
on Thursday, November 08

iPhone! It seems like everyone has one, and those who don’t have one are talking about it. (I fall into the latter category.)

I recently attended an Apple iPhone Tech Talk with some of my colleagues from Slantwise. It was well worth it. I highly recommend going if the talk comes to your area. If you can’t attend, you can watch the videos online. Getting into the nitty-gritty of how to develop for the iPhone and iPod Touch was very interesting, but to me the most useful aspect of the class with the information on the iPhone web application user interface guidelines.

Most examples I’ve seen for how to do a special view for the iPhone suggest something like this:

1
2
3
4
5
6
7
8
9
10
class ApplicationController < ActionController::Base  

  before_filter :adjust_format_for_iphone

  def adjust_format_for_iphone
    if request.env["HTTP_USER_AGENT"] && request.env["HTTP_USER_AGENT"][/(iPhone|iPod)/]
      request.format = :iphone
    end
  end
end

However, Apple’s user interface guidelines for the iPhone suggest against doing user agent sniffing. The reason is that iPhone users are used to being able to use the entire web. They don’t want a limited subset.

Another problem is that when Apple releases a new device, your code will need to be updated to work with it. This actually happened when the iPod Touch was released. Some iPhone sites didn’t work on the iPod Touch because (unlike the code above) they only sniffed for “iPhone”.

When I was at the Apple iPhone Tech Talk, Apple suggested the best way to develop web applications for the iPhone was to provide the full version of your site, with a link to the iPhone web app. The iPhone version should focus on discrete functionality, and look like a native iPhone application. But if an iPhone user ever needs to use the “real” site, it’s just a clicks away. Examples of sites doing this include Facebook and Amazon)

Fortunately, this is still easy to do with Rails.

1
2
3
4
5
6
7
8
9
10
class ApplicationController < ActionController::Base  

  before_filter :adjust_format_for_iphone

  def adjust_format_for_iphone
    if request.subdomains.first == "iphone"
      request.format = :iphone
    end
  end
end

You can test that your subdomain detection works with something like this:

1
2
3
4
5
def test_hitting_app_using_iphone_subdomain_should_set_iphone_virtual_mime_type
  @request.host = "iphone.test.host"
  get :index
  assert_equal :iphone, @request.format.to_sym
end

This is kind of a drag to develop with, so when not in production mode, I sniff based on the user agent like the old way.

1
2
3
4
5
6
7
8
def adjust_format_for_iphone
  if request.subdomains.first == "iphone" || 
     (RAILS_ENV != "production" && 
      request.env["HTTP_USER_AGENT"] && 
      request.env["HTTP_USER_AGENT"][/(iPhone|iPod)/])
    request.format = :iphone
  end
end

With this, I can use iPhoney to test my code on localhost, but the sniffing isn’t used when deployed.

For those times when you do need user agent detection, Apple recommends testing the “Mobile/XX” part of MobileSafari’s user agent string. This will work across iPhone, iPod Touch, and future MobileSafari devices.

Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/XX (KHTML, like Gecko) Version/ZZ Mobile/WW Safari/YY

Here’s an AbstractRequest#iphone? method. You can use in in your views to display a message to iPhone users telling them about your iPhone-optimized site or web application (like Amazon does). But I’m not sure if this is the “Rails way” to do this. Let me know in the comments.

1
2
3
4
5
6
7
module ActionController
  class AbstractRequest
    def iphone?
      self.env["HTTP_USER_AGENT"] && self.env["HTTP_USER_AGENT"][/(Mobile\/.+Safari)/]
    end
  end
end

And of course, I used the above method to refactor my adjust_format_for_iphone method.

For more on this topic, check out the iPhone Dev Center. You have to be an ADC member to look at the content, but signing up is free.

Update: Check out Ben’s Slash Dot Dash article on iPhone on Rails – Creating an iPhone optimised version of your Rails site using iUI and Rails 2 for some new tips and tricks.

Comments

Leave a response

  1. Christopher WarrenNovember 16, 2007 @ 02:24 PM

    Thanks for this Luke, it’s been really helpful. I believe adjust_format_for_iphone method should be check request.subdomains.first (plural), not subdomain (singular).

  2. Luke FranclDecember 03, 2007 @ 08:53 PM

    Christopher—thanks for noticing that. I have it that way in the second (real example), but the first one I screwed up. I will fix it.

  3. JustinDecember 05, 2007 @ 01:00 PM

    I always go back and forth on whether I think iPhone-specific versions of existing sites are a good idea, but a link to an iPhone subdomain sounds like the perfect compromise.

  4. Luke FranclDecember 07, 2007 @ 10:38 AM

    I was all set to develop an iPhone version of our site on the same URL (using browser sniffing) until I went to this Apple Tech Talk, and they suggested that it was a bad practice.

    I like the iphone subdomain approach, though.