Skip to content

Instantly share code, notes, and snippets.

@awilliams
Last active December 18, 2015 01:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save awilliams/5704586 to your computer and use it in GitHub Desktop.
Save awilliams/5704586 to your computer and use it in GitHub Desktop.
Rails controller concern to help with rendering mobile views
#
# Add this to your Gemfile
# gem 'rack-mobile-detect', :require => 'rack/mobile-detect'
#
module MobileConcern
extend ActiveSupport::Concern
included do
# Call this from a controller to enable mobile for a given action
# Example: enable_mobile :only => [:show]
def self.enable_mobile(*before_filter_args)
before_action(MobileHelper, *before_filter_args)
# set layout to 'nil', which sets the default layout
layout(Proc.new { |controller| controller.mobile_helper.enabled? ? 'mobile' : nil })
end
end
# Only method leaked into the Controller
# This instance variable is set by the filer if activated, otherwise the 'null' object is created
def mobile_helper
@mobile_helper ||= MobileHelper.new(self)
end
class MobileHelper
PARAM_KEY = :mobile
PARAM_VALUES = {
mobile: '1',
desktop: '0'
}
COOKIE_KEY = 'mobile_pref'
COOKIE_VALUES = {
mobile: 'mobile',
desktop: 'desktop'
}
# Called from the before_action callback
def self.before(controller)
self.new(controller).tap { |helper|
# Give the controller access to this helper
controller.instance_variable_set(:@mobile_helper, helper)
}.filter!
end
attr_reader :controller, :views_path
def initialize(controller, views_path = 'app/views/mobile')
@controller = controller
@views_path = views_path
@enabled = false
end
def filter!
self.set_mobile_pref_from_params
self.enable! if self.show_mobile_version?
self.controller.logger.debug("mobile = #{self.enabled? ? 'enabled' : 'disabled'}")
end
def enabled?
@enabled
end
def show_mobile_version?
self.param_mobile? || self.cookie_mobile? || (self.mobile_device? && !self.param_desktop? && !self.cookie_desktop?)
end
def enable!
@enabled = true
self.controller.prepend_view_path(File.join(Rails.root, self.views_path)) # see 'set_layout' for how layout is set
end
def set_mobile_pref_from_params
self.mobile_cookie = COOKIE_VALUES[:mobile] if self.param_mobile?
self.mobile_cookie = COOKIE_VALUES[:desktop] if self.param_desktop?
end
def mobile_device_name
@mobile_device_name ||= self.controller.request.headers.fetch(Rack::MobileDetect::X_HEADER, '').downcase
end
def mobile_param
@mobile_param ||= self.controller.params.fetch(PARAM_KEY, nil)
end
def mobile_cookie
@mobile_cookie ||= self.controller.send(:cookies).fetch(COOKIE_KEY, nil)
end
def mobile_cookie=(val)
self.controller.send(:cookies)[COOKIE_KEY] = {:value => val, :expires => 30.days.from_now} if val
end
def mobile_device?
# TODO: move the ignored devices to a config
self.mobile_device_name.present? && self.mobile_device_name.downcase != 'ipad'
end
def param_mobile?
self.mobile_param == PARAM_VALUES[:mobile]
end
def param_desktop?
self.mobile_param == PARAM_VALUES[:desktop]
end
def cookie_mobile?
self.mobile_cookie == COOKIE_VALUES[:mobile]
end
def cookie_desktop?
self.mobile_cookie == COOKIE_VALUES[:desktop]
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment