原贴 http://lanvige.github.io/2014/09/11/rails-variants-tips/
现在 Web 界流行一个新词Responsive Web Design,目的就是让一套网页在不同的设备上都能展现内容,像 BootStrap 这样的主流框架也都对其进行支持,很是方便,但有时不同设备上要求是不同的,可以说是完全不同的样式,在开发过程中仍需要使用不同的模板来渲染。
提到不同模板,在 Rails 中,普遍的方案是加入一个新的 Mime,为这种 Mime 建一个 Template Engine。 示例:RailsCasts #199 Mobile Devices。
Rails 4.1 中推出了一个新功能 Action Pack Variants,主要就是简化多设备上的模板问题。
#抄自 release notes
# You can set the variant in a before_action:
request.variant = :tablet if request.user_agent =~ /iPad/
#Respond to variants in the action just like you respond to formats:
respond_to do |format|
format.html do |html|
html.tablet # renders app/views/projects/show.html+tablet.erb
html.phone { extra_setup; render ... }
end
end
# Provide separate templates for each format and variant:
app/views/projects/show.html.erb
app/views/projects/show.html+tablet.erb
app/views/projects/show.html+phone.erb
You can also simplify the variants definition using the inline syntax:
respond_to do |format|
format.js { render "trash" }
format.html.phone { redirect_to progress_path }
format.html.none { render "trash" }
end
判断浏览器是一件很烦的事情,好在有很多地方都已经写好可以借用:如ruby-china。
不过这里要推荐的是一个 gem,叫作browser
gem 'browser'
然后就可以享受到多如牛毛的判断,更多看 github 页面。
browser.name
browser.mobile?
browser.tablet?
browser.firefox?
browser.ie?
browser.ie6?
通过手机,模拟器可以看到效果,但调试起来却不方便,在 Chrome 中安装 Agnet Simulate 是个好办法,但... RailsCast 中给出了一个通过 params 来改变状态的方法,这里依然实用。
def mobile_device?
session[:mobile_override] = params[:mobile] if params[:mobile]
if session[:mobile_override]
session[:mobile_override] == '1'
else
browser.mobile?
end
end
通过 params mobile=1
来强制设定浏览器类型,然后将其存到 session 中,即可以方便的调试。
上面示例中,把判断设备的代码放在了 application_controller.rb
中,但如果在像 devise 中如何使用 Variants 呢?
因为 devise 的自定义类中,会继承class RegistrationsController < ::Devise::RegistrationsController
,而非 application_controller.rb
,所以判断方法无法在这里使用。
第一个方案是,在自定义类中重写一变判断方法,Too Sha too kill...
第二种,可以使用Concerns
# controllers/concerns/detect_format_variant.rb
module DetectFormatVariant
extend ActiveSupport::Concern
included do
before_filter :set_device_type
end
private
## Mobile device
# detect_device
# 用Rails 4.1中的variants来进行设备匹配
def set_device_type
session[:mobile_override] = params[:mobile] if params[:mobile]
if mobile_device?
request.variant = :phone
end
end
def mobile_device?
if session[:mobile_override]
session[:mobile_override] == '1'
else
browser.mobile?
end
end
end
在需要进行判断的 controller 中加入
# Base controller
class ApplicationController < ActionController::Base
include DetectFormatVariant
end
# Devise
class RegistrationsController < ::Devise::RegistrationsController
include DetectFormatVariant
end
如果想深入了解 Variants,可以看看这篇: http://ryanbigg.com/2009/04/how-rails-works-2-mime-types-respond_to/