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 detec开发者_运维知识库t 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
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.
I had a similar problem always we cant relay on Routes . Sinatra provides filters to handle these kind of problems
@your_layout_name = ''
before :agent => /iPhone/ do
@your_layout_name = "initialize with desired iphone template"
end
get '/' do
# use @your_layout_name variable to initialize layout
end
I posting this since I had a problem where I was not in a position to filter at route level so This may help others who are looking for similar solutions
精彩评论