RailsでPCとスマフォのViewを切り分ける

スタイルシートは分けてマニフェストを書いているのですが、Viewファイルをスマフォ用に分けるかどうかは多分誰しも一度は悩んだことがあると思います。

Viewファイルを一緒にするメリットは

  • 保守が楽になる: 機能追加などによるPC、スマフォ両方のUIの変更を一度の変更でできる
  • クラス名が散らばらず綺麗なHTMLを保持しやすい

とかかなと思います。ただ一方で、

  • PCとスマフォでの表示切り替えロジックがつらい: <% if request.mobile? %>みたいなロジックがHTMLに紛れるとうざい
  • 並行で作業を進めるのが難しい: HTMLファイルが一緒だと、クラス名を変更したり要素の並びを変更したりする場合に、PCとスマフォで作業を切り分けてスタイルシートを書いたりするのが困難

という問題があると思います。結構デメリットのひとつめは、サービスの大きさに比例してつらくなっていくタイプの負債だと思ったので、ならできるだけ早い段階で切り離そう、ということになりました。

方法の検討

候補のgemsややり方はいくつかありました。

1. ディレクトリ構成を変える

一つめは、gemを使わない方法。

Railsには読み込むViewのパスを変更する方法があるので、app/views/pcapp/views/smartphoneのように切り分ける方法を検討しました。

これだとapp/views/models以下にPC用とスマフォ用のviewファイルを詰め込むよりもキレイな構造になっていると思います。

また試してみて気づいたのが、ActionMailer用のViewファイルとの切り分けもできるのでめちゃくちゃ構成がキレイになります。Railsのデフォルトではmailer用のviewファイルやlayoutのファイルが全部一緒くたになってて分かりにくいなと感じました。

ただ、今変更しているPRの全てに対して破壊的な影響を与えてしまうということと、Railsのレールからは外れてしまうことになるためいろいろな部分で軋みが生まれるという懸念がありこの方法は断念しました。

2. テンプレートの名前で読み分ける

じゃあ、app/views/models以下にindex.html.erbと、index.smartphone.html.erbみたいなファイルをどちらも作っておいてActionView側でuser agentを読んで読み込むviewを切り替える方法にしよう、ということになりました。

これだと、今変更している作業に影響を与えることもないですし、柔軟性がありそうです。

jpmobileという有名なgemがあり、このgemが標準でこの機能も提供しているので、これを使おうという話になりました。

ですが、jpmobileのメインの機能は日本のフィーチャーフォンの判別で、このために導入するにしてはちょっとヘビーな感じがしていました。

自分たちで実装しよう、ということで方法を探りましたが、Rails標準でこのような機能は提供されておらずどのgemも、RailsのクラスであるActionView::FileSystemResolverを継承したクラスを定義してMOBILE_PATTERNという定数に、":prefix/:action.mobile{.:locale,}{.:formats,}{.:handlers,}"みたいな感じでmobileの部分を付け加える、という方法をとっていました。

なので自分たちで実装するならこんな感じで軽量なgemを作るのがいいのかな。。。とか思ってたら、見つけました。

https://github.com/tscolari/mobylette

こちらはmobile用のviewに振り分けるためのgemなので、かなり今の用途と合致していました!これだーー。(みてみると自分は昔にstarしていたみたいで記憶力の低さにつらくなった。。)

このmobyletteも他のgemと仕組みは変わらないみたいで、::ActionView::FileSystemResolverを継承して使っていました。

https://github.com/tscolari/mobylette/blob/master/lib/mobylette/resolvers/chained_fallback_resolver.rb

ということで、以下も参考にさせていただきながら設定しました。

http://morizyun.github.io/blog/mobylette-gem-ruby-rails-mobile/

mime typeがmobileになるのにはなんかすごい抵抗がありましたが大概問題なく今のところ運用できているような気がします。