iPhone on Rails – Creating an iPhone optimised version of your Rails site using iUI and Rails 2

After upgrading trawlr.com to Rails 2 I thought I’d make use of some of the new features and attempt to create an iPhone version of the site.
With Rails 2 you can create a mime type specifically for the iPhone and then use that format in a respond_to block (along with views such as index.iphone.erb).

Before you start – iPhoney

iPhoney is an indispensable Mac-only tool for aiding the development of an iPhone specific site.

Looking for a way to see how your web creations will look on iPhone? Look no further. iPhoney gives you a pixel-accurate web browsing environment—powered by Safari—that you can use when developing web sites for iPhone. It’s the perfect 320 by 480-pixel canvas for your iPhone development. And it’s free. iPhoney is not an iPhone simulator but instead is designed for web developers who want to create 320 by 480 (or 480 by 320) websites for use with iPhone. It gives you a canvas on which to test the visual quality of your designs.

Ensure iPhoney’s user agent is set to iPhone User Agent in the menu.

iPhone mime type

Create an iPhone mime type alias using Rails 2 initializers.

config/initializers/mime_types

Mime::Type.register_alias "text/html", :iphone

Detecting iPhone user agents

Apple recommends that rather than redirecting iPhone users to an iPhone-optimised version of your site you should instead show the original site with a link to the alternative.

This can be achieved via user agent sniffing; looking for Mobile Safari (as Apple suggests), rather that iPhone or iPod touch, to allow for future device support.

Adding a helper method to application_helper.rb allows a notification message to be shown for only iPhone users (try accessing www.trawlr.com from an iPhone).

app/helpers/application_helper.rb

# Request from an iPhone or iPod touch? (Mobile Safari user agent)
def iphone_user_agent?
  request.env["HTTP_USER_AGENT"] && request.env["HTTP_USER_AGENT"][/(Mobile\/.+Safari)/]
end

In your view, show a message for iPhone user agents directing them to the iPhone version.

<% if iphone_user_agent? # Show message for iPhone users -%>
<div class="message">
    <p>Using an iPhone? <a href="http://iphone.trawlr.com/">Use the optimised version</a>.</p>
</div>
<% end -%>

iPhone subdomain

Instead of forcing users straight to our iPhone version, we offer them the option by using a separate subdomain (iphone.trawlr.com) with a link back to the regular site if they wish. When developing locally I modified my /etc/hosts file as follows so that I could use http://iphone.localhost.com:3000/.

/etc/hosts

127.0.0.1 iphone.localhost.com

You may need to flush the DNS cache after making the changes.

sudo dscacheutil -flushcache

Adjust format for iPhone

I chose to require login for all requests to the iPhone version of the site.

class ApplicationController < ActionController::Base
    before_filter :adjust_format_for_iphone
    before_filter :iphone_login_required
private
  # Set iPhone format if request to iphone.trawlr.com
  def adjust_format_for_iphone
    request.format = :iphone if iphone_request?
  end
  # Force all iPhone users to login
  def iphone_login_required
    if iphone_request?
      redirect_to login_path unless logged_in?
    end
  end
  # Return true for requests to iphone.trawlr.com
  def iphone_request?
    return (request.subdomains.first == "iphone" || params[:format] == "iphone")
  end
end

Note that sessions_controller.rb (handles login) requires skip_before_filter :iphone_login_required.

Using iUI and creating iPhone views

The iUI framework, based on Joe Hewitt’s iPhone navigation work, hugely simplifies iPhone web development. All you need to do is include the iUI JavaScript and CSS files along with included images and create your views in a particular structure to have native iPhone behaviour such as sliding menus and AJAX page loading.

Rails 2 makes it trivial to create different views depending upon the format, including layouts. Our iPhone layout includes a few specifics for iUI and a viewport meta tag for the device.

app/views/layouts/application.iphone.erb

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <meta id="viewport" name="viewport" content="width=320; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"/>
    <title><%= @page_title -%></title>
  <%= stylesheet_link_tag 'iui' %>
  <%= javascript_include_tag 'iui' %>
</head>
<body>
    <div class="toolbar">
        <h1 id="pageTitle"></h1>
        <a id="backButton" class="button" href="#"></a>
    </div>
    <%= yield %>
</body>
</html>

When creating your iPhone views you should follow the iUI style guide, an example page is given below. Standard hyperlinks are loaded using AJAX and slide into view, navigating back is handled by iUI. Links may be prefixed with target="_self" to replace the entire page or target="_replace" to replace the element with the response (using AJAX).

index.iphone.erb

<ul title="Home" selected="true">
    <li><%= link_to 'Example action', example_path %></li>
    <li><%= link_to 'Logout', logout_path, :method => :delete, :target => '_self' %></li>
</ul>

show.iphone.erb

<div class="panel" title="Example" selected="true">
    <h2>Example Content</h2>
    <p>Here's some content</p>
</div>

It’s important to remember that iUI will load content using AJAX, thus you only need to render a layout (such as application.iphone.erb) for the first request or page of your iPhone site. All following requests should use render :layout => false (unless loaded into a new page with target="_replace"). If you experience any wierd rendering issues it’ll most likely be due to this irregularity.

respond_to do |format|
    format.iphone do  # action.iphone.erb
      render :layout => false
    end
end

Show, don’t tell

Why not try iphone.trawlr.com for yourself? It’ll work for your iPhone or any web browser. You’ll need to register via the normal site if you don’t already have an account (quick, no email registration required)!

References

The following resources on the new Rails 2 iPhone format ability and iUI library were extremely helpful; the documentation from Apple not so much!

  • http://developer.apple.com/iphone/
  • http://www.railspikes.com/2007/11/8/iphone-subdomains-with-rails
  • http://blog.nicksieger.com/articles/2007/09/18/railsconf-europe-david-heinemeier-hansson
  • http://www.joehewitt.com/blog/introducing_iui.php
  • http://code.google.com/p/iui/

Yes, I’m still loving the iPhone!


About this entry