Conditional templates (Request variants) #

Sometimes you will want to render completely different views on Desktop browser, Mobile browser, and Native.

Request Variants allow you to conditionally render different templates, like index.html.erb & index.html+mobile.erb.

Gem Browser helps to determine whether the browser:

bundle add browser

Set +mobile template rendering variant for both Mobile browser and Native:

# app/controllers/concerns/detect_device.rb
module DetectDevice
  extend ActiveSupport::Concern

  included do
    before_action :set_variant
  end

  private

  # inspired by
  # https://github.com/gorails-screencasts/request-variants/commit/78d72b59a0a35ce4df2de8dcb0626001bfc87a5e#diff-95144019706bb2c1ee8edff448ecc0bf5d182e3dc4faf41b2a99d753b97b2999R8
  def set_variant
    #case request.user_agent
    #when /iPhone/
    #  request.variant = :phone
    #when /iPad/
    #  request.variant = :tablet
    #end

    browser = Browser.new(request.user_agent)
    return request.variant = :mobile if turbo_native_app? || browser.device.mobile?
  end
end

Activate the DetectDevice concern:

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  include DetectDevice
end

Now you can render:

  • app/views/posts/index.html.erb by default
  • app/views/posts/index.html+mobile.erb on mobile browsers / native apps

To test this, emulate user agent from your browser.

Safari:

safari-user-agent

Chromium:

chromium-user-agent

Viewport scaling #

On touchscreens you will most likely want to disable zoom with fingers.

# app/helpers/application_helper.rb
  def viewport_meta_tag
    content = ['width=device-width,initial-scale=1']
    content << 'maximum-scale=1, user-scalable=0' if turbo_native_app? || browser.device.mobile?
    tag.meta(name: 'viewport', content: content.join(','))
  end
# app/views/layouts/application.html.erb
-  <meta name="viewport" content="width=device-width,initial-scale=1">
+  <%= viewport_meta_tag %>

That’s it!