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?
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
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
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With