iPhone Web Development with Ruby on Rails

pple’s iPhone has taken the nation by storm. An alleged half million moved from the shelves into people’s pockets in the first weekend it went on sale. Safari, the iPhone’s native browser, claims to bring full featured browsing to the mobile device. You’ll learn, over the course of this article, more than a few tricks that will help your website stand out on the iPhone. Knowledge of Ruby is not required to learn from this article as it relies heavily on Cascading Style Sheets and JavaScript to work its magic. You should be able to apply the tricks you’ll learn here anywhere you’d use JavaScript or CSS. This article will not teach you everything you need to know about web development with Ruby on Rails, it will simply point out where the iPhone’s browser differs from an ordinary one. Add up all these custom tweaks and you should have the tools you need to take your web site mobile.

For a primer on Ruby on Rails, take a look at the Related Resources connected to this article.

What You Need
An iPhone, or iPhony (iPhone browser emulator), a simple Ruby project over which you have control, and boundless imagination.

Recognizing the iPhone
There are several different ways to detect if one of your visitors is hitting your page from an iPhone. Most of them rely on temporary “hacks” for assuming that safari is the only browser that will correctly accept “max-device-width” parameters. Since Ruby is all about simplicity, you should strive for a solution that is low in maintainability. Here’s the simple Ruby way of detecting the existence of the iPhone:

	<%= if request.user_agent.include?("iPhone") then 		render :partial => 'foriphoneonly' 	end %>

Let’s go over this code step-by-step:

  1. The code looks for “iPhone” within the user agent string. The full user iPhone UAString looks something like this:
    Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543a Safari/419.3"
  2. When the iPhone is detected on the connection, the Rails application renders the partial ‘foriphoneonly’ exclusively for the iPhone. This trick allows you to have one URL for your web site; iPhone users will see one interface while Firefox, Safari, and IE browsers will see something different. There has been some debate on the merits of blocking iPhone specific content from Firefox and IE users but this decision is probably best left to your business department.

To get started right away, simply create a style sheet exclusively for the iPhone. You can specify specific media type declarations to focus our CSS to appear only on iPhones:

You have to special case the if statement so that IE will render the CSS correct and process the media type declaration.

Orientation, Orientation, Orientation
The iPhone allows users to browse the web in both portrait and landscape mode. This simple feature could have a dramatic impact on the usability of your web site. First, you might want to craft your CSS so that content, ads, and menus are displayed differently in landscape versus portrait mode. Second, you’ll want to use your Ruby code to track which orientation your users prefer.

In the future, Apple may improve the ability of Safari to recognize more widely accepted methods for detecting resized events that are traditionally used by web applications. Until then, you’ll need to resort to frequently checking the window size with JavaScript and comparing it to a previously stored value to detect rotations in the iPhone, like this:

currentWidth = 0;window.setInterval( 'checkMyOrientation()', 200 );function checkMyOrientation() { if (window.innerWidth != currentWidth) {  currentWidth = window.innerWidth;  var myOrientation = (currentWidth == 320) ? "upright" : "landscape";  document.body.setAttribute("orientation", myOrientation); 	}};

The above JavaScript snippet creates an event timer, a small piece of code that waits 200 milliseconds before calling the checkMyOrientation() function and then repeats that process every 200 milliseconds. This process is called polling and it’s a useful way to make event-based decisions in a browser. Every time you run this function, you’re going to compare the window’s innerWidth property with your own expectation of the browser width to see if the width has changed. You initialize currentWidth to 0, which sets the initial orientation of the phone. After the orientation changes and your timer fires, you’ll recognize the change and set the myOrientation variable to either upright or landscape.

In CSS, you can declare any attribute for a tag. Programmers are not limited to attributes that are recognized by any particular browser. In this example, you’ll be creating an attribute for the body tag, called orientation and specifying it to be the string upright or landscape, depending on the result of the JavaScript. You can swap out content on your page based on the contents of the orientation attribute, as follows:

body[orientation="upright"]body[orientation="landscape"] 

You can create any type of attribute structure you like?including specific menus or even entire div containers exclusively for the iPhone’s different orientations. You do this by adding the orientation attribute to any CSS tag.

iPhone Orientation in Ruby on Rails
Now that the client is aware of which way the phone is used, you’ll want to be able to send that information to your server. To do so, you’ll need to use a little JavaScript wizardry in addition to some Ruby rendering tricks. Normally, if you wanted to create an event timer like the previous example, you would use the periodically_update_remote function. In practice, you might not want to communicate your orientation to the server every 200 milliseconds. Remember, the Internet is a series of tubes, it’s not a truck?you can’t just dump stuff on it.

Since Ruby is built around the Model-View-Controller method of programming, you’ll have to update both the View code and the Controller code to properly communicate changes to your Ruby server. Start with the View code and update your JavaScript timer to resemble the following code and save it as _”foriphoneonly.rhtml”. The underscore tags the file as a partial, which means that it’s a piece of browser-readable code that isn’t a View, but can be rendered by any View which accesses it with the render :partial command.

If you use the user agent detecting code described earlier in one of your Views, this event timer will only be rendered when needed, allowing you to focus on your content without cluttering up the View.

What’s been replaced here is the reliance on the browser to parse CSS and figure out which View to render. Instead, when the JavaScript event timer detects a change in the screen width, it calls the check_position function in your Controller. Now, add a bit of logic to it to parse the string returned by the client:

def check_position  windowwidth = request.raw_post.chop.to_i  if windowwidth > 330   render_text "I seem to be landscape #{windowwidth}"    else   render_text "I seem to be portrait #{windowwidth}"  end end

In the above example, request.raw_post is the object that contains the raw data sent back from the page to the server. It has two problems: it’s sent as a string and it has an extra character on the end. You can easily append methods to the end of an object to convert and manipulate data in Ruby. Here, you use “chop” to lop off the extra character and to_i to convert the value to an integer.

Armed with a valid integer to represent the current width of the screen, it becomes trivial to perform more complicated server-side logic without filling the tubes.

Preventing the Zoom
Apple has decided not to allow applications by third parties to be installed on their device, however, with a little ingenuity, you can create a web application that looks and behaves as though it was installed on the phone. This effect is ruined when your users are zooming through your page as though your app was a Google map. You can disable this feature in a single line with the following snippet:

The viewport metatag has functionality beyond the scope of this article. Check with Google for more information on its use.

Making a Call
The iPhone will automatically find numbers and convert them where appropriate. Sometimes you want to connect a user directly to your call center without having to spell the whole number out. The “tel:” format works much like the mailto: syntax, in that it will dial a number while allowing you to replace the number with something more descriptive. For example:

Jenny.

Smooth Sailing
While Apple claims that its device carries a fully featured desktop-style web browser, it’s clear it will take some manuevering to navigate a successful iPhone web experience. Hopefully after reading this article, you’ll be armed with the tools and tricks needed to make your Ruby web-apps play nice with the Apple iPhone.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

Recent Articles: