Railsでデバイスの判定をするのに便利なgemを作った

rack-user_agent を作った

rack-user_agentという、User-Agentに応じていろいろな判定ができるメソッドを生やすRack::Request拡張を作った。
tagomorisさんのWootheeを使ってRack middlewareでUser-Agentをパースしておいて、 その結果に応じてrequestから簡単にいろいろな情報を得られるようにしてある。

たとえばRailsだとGemfileにgem "rack-user_agent"と書くだけで以下のように使うことができる。

class ApplicationController < ActionController::Base
  before_action :set_request_variant

  def index
    # example
    request.user_agent       #=> "Mozilla/5.0 (Linux; Android 4.3; Nexus 7 ..."
    request.device_type      #=> :smartphone
    request.os               #=> "Android"
    request.os_version       #=> "4.3"
    request.browser          #=> "Chrome"
    request.browser_version  #=> "29.0.1547.72"
    request.from_pc?         #=> false
    request.from_smartphone? #=> true
  end

  private

  # Action Pack Variants向け
  def set_request_variant
    request.variant = request.device_type # :pc, :smartphone, etc
  end
end

なぜ便利か

例えばwootheeでスマホかどうか判定したかったら、ApplicationControllerとかに

def request_from_smartphone?
  Woothee.parse(request.user_agent)[:category] == :smartphone
end

みたいなのを書く必要がある。けど、

request.from_smartphone?

で最初から書けたら便利だと思った。

Action Pack Variantsに使う

Ruby on Rails 4.1 Release Notes

Rails 4.1から、jsonやhtmlみたいなformatだけではなく、pcとかスマホのような条件によってテンプレートをスイッチできるようになった。
例えば、

app/views/projects/show.html.erb
app/views/projects/show.html+phone.erb

みたいなビューがあったとき、request.variant:phoneが入っていればshow.html+phone.erbが使われ、そうでなければshow.html.erbが使われる。 jpmobileとかでできるやつ。

ただ、このrequest.variantに何をセットするかはユーザーに委ねられていて、UAをパースして:phoneを入れたりするのは自分でやらないといけない。 そこを信頼できるUAパーサライブラリにまかせておけば、Railに乗ったまま楽にjpmobileみたいなことができて良いと思う。

作った背景、所感

最近触っているRailsアプリは、正規表現によるデバイスの判定を自前の正規表現で行っていた。
最近アプリ対応とかでその周りをいじることが多くなってきたんだけど、どんどん新しいデバイスが出てきてこれ保守するの無理だなと思った。
そこで、多言語に対応しているからいろんな人にメンテされそうなwootheeにUAのパースを任せることにした。

UAのパーサ保守するの大変なのでなるべく多くの人が保守してるやつを使って助け合いたい。