はじめに
レスポンシブデザインではなく、PC用のViewとスマートフォン用のViewを分けて実装する場合があるかと思います。
その際に、ActionPack Variantsを利用して、1つのControllerでデバイス毎にViewを切り替える方法が一般的かと思います。
しかし、PCページだけ先にVue.jsにリニューアルするなど、PCとスマートフォンでControllerを分けたい時などがあります。
本記事では、デバイスごとにControllerを切り替える方法をご紹介します。
やり方
大まかな方法としては以下のようになります。
- requestからユーザーがアクセスしているデバイスを判定する
- routingのconstraintsを使ってPC用のControllerとスマートフォン用のControllerと振り分ける
検証環境
Ruby 2.5.5
Ruby on Rails 5.2.3
準備
PCとスマートフォンそれぞれのControllerとViewを用意しておきます。
class PcPageController < ApplicationController
def index
end
end
class SmartphonePageController < ApplicationController
def index
end
end
PC用のControllerから表示されました。
Smartphone用のControllerから表示されました。
アクセスしているデバイスの判定
今回はrack-user_agent
というgemをつかってデバイスを判定します。
Gemfileにrack-user_agent
を追加しておきます。
gem 'rack-user_agent'
以下のようにrequestが拡張されて、デバイスを判定できるようなメソッドが追加されるので、簡単に判定できます。
class HomeController < ApplicationController
def index
request.from_pc? #=> true
request.from_smartphone? #=> false
end
end
その他の機能はGithubのレポジトリを参照してください。
k0kubun/rack-user_agent: Rack::Request extension for handling User-Agent
constraintsを使ってルーティングを設定
constraintsを使うとルーティングにマッチさせる条件を設定することが出来ます。
参考:Rails のルーティング - Rails ガイド
基本的な使い方
get 'photos/:id', to: 'photos#show', constraints: { id: /[A-Z]\d{5}/ }
/photos/A12345のようなパスの場合photos#show
が呼ばれますが、/photos/893はマッチしないため呼ばれません。
独自のConstraintを作成する
constraintsは独自のConstraintを作成することで、柔軟な判定をすることが出来ます。
matches?メソッドがtrueを返す場合、そのルーティングにマッチします。
class SmartphoneConstraint
def self.matches?(request)
request.from_smartphone?
end
end
get '/', to: 'smartphone_page#index', constraints: SmartphoneConstraint
get '/', to: 'pc_page#index'
このように設定すると、routes.rbの上から順に判定されるため、
スマートフォンからのアクセスだとsmartphone_page#index
が呼ばれ、それ以外はpc_page#index
が呼ばれることとなります。
確認してみる
- PCからアクセスした場合
- スマートフォンからアクセスした場合
ちゃんと切り替わっていますね
おわりに
既存のRailsアプリのフロントエンドをVue.jsにリニューアルしたくて、まずはPCページだけ導入してみようと思い今回の方法を使ってみました。
基本的にはデバイス毎にViewだけを切り替えたほうが分かりやすいとは思いますが、Controllerも切り替える必要があればこんな方法はいかがでしょうか。
Github: boronngo/rails-sp-routing