What is Toluu?
Toluu is a free service for sharing the feeds you read and discovering new ones.
Get Invite

{ Rails + Love } - Home


iPhone Optimization: stylesheet_link_tag cachingJune 29 2007

This change to the Rails core is a couple months old, but especially relevant when developing for the iPhone. One of the ways to optimize the performance of apps delivered to iPhones is to reduce the number of requests required for each action. If you like to split up your css files in logical order like I do, then you might find the stylesheet_link_tag caching useful.

Before: stylesheet_link_tag :all # returns => # <link href="/stylesheets/style1.css" media="screen" rel="Stylesheet" type="text/css" /> # <link href="/stylesheets/styleB.css" media="screen" rel="Stylesheet" type="text/css" /> # <link href="/stylesheets/styleX2.css" media="screen" rel="Stylesheet" type="text/css" /> stylesheet_link_tag "shop", "cart", "checkout" # returns => # <link href="/stylesheets/shop.css" media="screen" rel="Stylesheet" type="text/css" /> # <link href="/stylesheets/cart.css" media="screen" rel="Stylesheet" type="text/css" /> # <link href="/stylesheets/checkout.css" media="screen" rel="Stylesheet" type="text/css" /> After: stylesheet_link_tag :all, :cache => true # returns => # <link href="/stylesheets/all.css" media="screen" rel="Stylesheet" type="text/css" /> stylesheet_link_tag "shop", "cart", "checkout", :cache => "payment" # returns => # <link href="/stylesheets/payment.css" media="screen" rel="Stylesheet" type="text/css" />

You need to have ActionController::Base.perform_caching =

respond_to :iPhone in RailsJune 29 2007

As promised in my prior article, here is my current solution to quickly and easily tack on an iPhone specific user interface to Rails applications. Our goal is to be able to deliver customized html, js and css for the iPhone. To do so, I’ve decided to hijack our best friend respond_to. respond_to delivers different content to browsers based on their HTTP request and even though its only designed to discriminate based on mime-type, its pretty easy to modify it to also discriminate based on user-agent. The other distinct advantage of using respond_to is that not only can we create different html, javascript and css views, but we can also pass blocks.

If you want to follow along in the core, open up actionpack/lib/action_controller/mime_responds.rb and scroll down to the Responder Class.

The initialize method checks the CGI request for the list of acceptable formats and puts them in an array in order of preference (@mime_type_priority). Later it iterates through this array and returns the first one that matches what’s listed in respond_to. Let’s modify it to automagically add iPhone specific MIME types to the front of that preference array.

alias original_initialize initialize def initialize(controller) original_initialize(controller) # If the user agent is Safari on iPhone, duplicate the acceptable # formats with iphone_ prepe
Development for iPhoneJune 28 2007

Normally I wouldn’t advocate developing completely different views for one particular user-agent. It violates the web standards mindset that has been burned into my brain over many years. However, I can’t ignore the fact that the iPhone throws a wrench into some of that mindset. The iPhone’s full web browser will be great for reading news sites & blogs, but for web apps, we should take a couple things into consideration:

  • Every kilobyte matters! The EDGE network will have users crawling the web, quite literally. Download speeds will float somewhere between that of a 56kbps modem and an ISDN line when users are away from WiFi. Hiding elements with media-specific stylesheets does us no good because the data is still downloaded (including all those hefty javascript libraries). Which brings me to my next point…
  • iPhone will probably use “screen” css media, not “handheld” (pretty clear from the public demonstrations and Apple’s huge emphasis on it having a “FULL web browser” and browsing the web the “way it was meant” to be browsed). After all, what’s the point of having a phone with a full web browser complete with zoom-in, zoom-out capability if the browser loads stripped down versions of web pages by default? Again, great for browsing, not for monitor-sized web apps.
  • Using web apps on the iPhone will be cumbersome enough as it is. There’s no way to directl
Life on Edge RailsJune 1 2007

assert_difference & assert_no_difference now accept an array of expressions

The assert_difference and assert_no_difference testing methods now can accept an array of expressions to evaluate. So now instead of doing:

assert_difference 'User.count', +1 do post :create, :article => { :profile => {}, ... } end assert_difference 'Profile.count', +1 do post :create, :article => { :profile => {}, ... } end

we can do:

assert_difference ['User.count', 'Profile.count'], +1 do post :create, :article => { :profile => {}, ... } end

That’s some nice DRY action!

Life on Edge RailsMay 31 2007

Date#change

Date now has #change and works just like Time#change. So now we can do: next_bill_date = Date.today.change( :month => Date.today.month + 1, :day => 15)

All controller names pluralized

map.resource will now map to a pluralized controller name by default: map.resource :account # now maps to: AccountsController < ApplicationController

Where this makes even more sense to me is in this situation which I brought up in a post on the rubyonrails-core mailing list . Let’s say I have products which each has_one manufacturer. I want to be able to control those manufacturers both within the context of their association with the products and separately on their own. The way it used to be:

map.resources :products, :has_one => :manufacturer #=> ManufacturerController map.resources :manufacturers #=> ManufacturersController

The first mapping would look for a ManufacturerController because :has_one generates a singleton resource. But the second mapping would look for a ManufacturersController. Regardless of the context, I’m probably going to control my manufacturers resource the same way. So now all controllers are by default plural, whether its coming from map:resource, map.resources, :has_one, or :has_many.

map.resources :products, :has_on