Last active
December 18, 2015 01:29
-
-
Save awilliams/5704586 to your computer and use it in GitHub Desktop.
Rails controller concern to help with rendering mobile views
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# 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