Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Sinatra, best way to serve iPhone layout vs. normal layout?

I'm writing a Sinatra app which needs to render different layouts based on whether the user is using an iPhone or a regular browser. I can detect the browser type using Rack-Mobile-Detect but I'm not sure of the best way to tell Sinatra which layout to use.

Also, I have a feeling that how I choose to do this may also break page caching. Is that true?

Example code:

require 'sinatra/base'
require 'haml'
require 'rack/mobile-detect'

class Orca < Sinatra::Base

  use Rack::MobileDetect

  helpers do
    def choose_layout
      if request.env['X_MOBILE_DEVICE'] == :iPhone
        # use iPhone layout
      else
        # use normal layout
      end
    end
  end

  before do
    # should I use a before filter?
    choose_layout()  
  end

  get '/' do
    haml :home # with proper layout
  end

end #Class Orca
like image 385
Doug Avatar asked Jun 04 '10 22:06

Doug


3 Answers

This is what I ended up doing:

require 'sinatra/base'
require 'haml'
require 'rack/mobile-detect'

class Orca < Sinatra::Base

  use Rack::MobileDetect

  # HAML template options
  # Use HTML5 doctype
  set :haml, {:format => :html5 }

  helpers do

    def get_layout
      # For AJAX (XMLHttpRequest) requests, don't use a layout
      if request.xhr? then 
        @layout = false
        exit
      end

      # For non-AJAX (XMLHttpRequest) requests, choose correct layout
      # For each mobile device, you will need a layout_<device>.haml file
      # in the Views directory
      @layout = case request.env['X_MOBILE_DEVICE']
                when /iPhone|iPod/ then :layout_iphone

              # when "Android" then :layout_android

                else true # use default Sinatra layout
                end
    end

  end # helpers

  before do
    get_layout() 
  end # before filter

  get '/' do
    # Will use iPhone layout for iPhone|iPod, 
    # Sinatra default layout for desktop browsers
    haml :home, :layout => @layout
  end

end # Class
like image 118
Doug Avatar answered Nov 15 '22 13:11

Doug


I believe the standard way to handle specific user agents in Sinatra is directly on the route...

get '/', :agent => /iPhone/ do
    # render for iPhone
end

get '/' do
    # render standard layout
end

See The Sinatra Book.

Re: caching, I guess it would depend on what caching layers are fronting your site, but, yes, you may need to account for this.

like image 4
sevennineteen Avatar answered Nov 15 '22 12:11

sevennineteen


I wrote a blog post about this topic that might be helpful to someone using Padrino with Sinatra. If you're not using Padrino, this still might be useful if you find the right place to extend Sinatra.

http://blog.joshdzielak.com/override-padrino-locale-based-template-resolu
http://dzello.com/blog/2011/06/22/override-padrino-locale-based-template-resolu/

The summary - I use rack-mobile-detect to tell me if a request is 'mobile', and I patch out Padrino's locale-based rendering support to render based on the mobile detection instead of the locale.

In this way I'm able to have foo.mobile.haml render for mobile and foo.haml for non-mobile, without any application code. As a bonus, it works both for the template file and the layout.

like image 1
Josh Dzielak Avatar answered Nov 15 '22 13:11

Josh Dzielak