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.

