Rails Variants Tips

现在Web界流行一个新词Responsive Web Design,目的就是让一套网页在不同的设备上都能展现内容,像BootStrap这样的主流框架也都对其进行支持,很是方便,但有时不同设备上要求是不同的,可以说是完全不同的样式,在开发过程中仍需要使用不同的模板来渲染。

Image Source

提到不同模板,在Rails中,普遍的方案是加入一个新的Mime,为这种Mime建一个Template Engine。 示例:RailsCasts #199 Mobile Devices

Action Pack Variants

Rails 4.1 中推出了一个新功能 Action Pack Variants,主要就是简化多设备上的模板问题。

具体用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#抄自 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

Tip 1 判断浏览器类型

判断浏览器是一件很烦的事情,好在有很多地方都已经写好可以借用:如ruby-china

不过这里要推荐的是一个gem,叫作browser

1
gem 'browser'

然后就可以享受到多如牛毛的判断,更多看github页面。

1
2
3
4
5
6
browser.name
browser.mobile?
browser.tablet?
browser.firefox?
browser.ie?
browser.ie6?

Tip 2 参数指定浏览器类型

通过手机,模拟器可以看到效果,但调试起来却不方便,在Chrome中安装Agnet Simulate是个好办法,但… RailsCast中给出了一个通过params来改变状态的方法,这里依然实用。

1
2
3
4
5
6
7
8
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中,即可以方便的调试。

Tip 3 Devise等如何使用

上面示例中,把判断设备的代码放在了 application_controller.rb 中,但如果在像devise中如何使用Variants呢?

因为devise的自定义类中,会继承class RegistrationsController < ::Devise::RegistrationsController,而非 application_controller.rb,所以判断方法无法在这里使用。

第一个方案是,在自定义类中重写一变判断方法,Too Sha too kill…

第二种,可以使用Concerns

controllers/concerns/detect_format_variant.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# http://blog.brzezinka.eu/rails4/rails-4-view-variant-detection-as-a-controller-concern
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中加入

1
2
3
4
5
6
7
8
9
10
# Base controller
class ApplicationController < ActionController::Base
include DetectFormatVariant
end
# Devise
class RegistrationsController < ::Devise::RegistrationsController
include DetectFormatVariant
end

REF::

如果想深入了解Variants,可以看看这篇:
http://ryanbigg.com/2009/04/how-rails-works-2-mime-types-respond_to/

http://blog.brzezinka.eu/rails4/rails-4-view-variant-detection-as-a-controller-concern
http://tech.pro/tutorial/2049/how-to-use-rails-41-actionpack-variants
http://railscasts.com/episodes/199-mobile-devices
http://codemy.net/posts/rails-4-1-variants