Skip to content

Commit

Permalink
initial version
Browse files Browse the repository at this point in the history
  • Loading branch information
kristianmandrup committed Apr 5, 2012
1 parent acd6715 commit 7eff97c
Show file tree
Hide file tree
Showing 9 changed files with 155 additions and 13 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Expand Up @@ -28,7 +28,7 @@ pkg
#
# For MacOS:
#
#.DS_Store
.DS_Store

# For TextMate
#*.tmproj
Expand Down
15 changes: 6 additions & 9 deletions Gemfile
@@ -1,14 +1,11 @@
source "http://rubygems.org"
# Add dependencies required to use your gem here.
# Example:
# gem "activesupport", ">= 2.3.5"
source :rubygems

# Add dependencies to develop your gem here.
# Include everything needed to run rake, tests, features, etc.
group :development do
gem "rspec", "~> 2.8.0"
gem "rdoc", "~> 3.12"
gem "bundler", "~> 1.0.0"
gem "jeweler", "~> 1.8.3"
gem "rcov", ">= 0"
gem "rspec", "~> 2.9.0"
gem "rdoc", "~> 3.12"
gem "bundler", "~> 1.1.0"
gem "jeweler", ">= 1.8.3"
gem "simplecov",">= 0.5"
end
37 changes: 37 additions & 0 deletions Gemfile.lock
@@ -0,0 +1,37 @@
GEM
remote: http://rubygems.org/
specs:
diff-lcs (1.1.3)
git (1.2.5)
jeweler (1.8.3)
bundler (~> 1.0)
git (>= 1.2.5)
rake
rdoc
json (1.6.6)
multi_json (1.2.0)
rake (0.9.2.2)
rdoc (3.12)
json (~> 1.4)
rspec (2.9.0)
rspec-core (~> 2.9.0)
rspec-expectations (~> 2.9.0)
rspec-mocks (~> 2.9.0)
rspec-core (2.9.0)
rspec-expectations (2.9.1)
diff-lcs (~> 1.1.3)
rspec-mocks (2.9.0)
simplecov (0.6.1)
multi_json (~> 1.0)
simplecov-html (~> 0.5.3)
simplecov-html (0.5.3)

PLATFORMS
ruby

DEPENDENCIES
bundler (~> 1.1.0)
jeweler (>= 1.8.3)
rdoc (~> 3.12)
rspec (~> 2.9.0)
simplecov (>= 0.5)
37 changes: 35 additions & 2 deletions README.rdoc
@@ -1,6 +1,39 @@
= mobile_view_paths
= Mobile view paths for Rails

Description goes here.
Based on http://erniemiller.org/2011/01/05/mobile-devices-and-rails-maintaining-your-sanity/

First, let’s set up our mobile app at m.mydomain.com. Requests made to the “m” subdomain will use our mobile templates, if they exist. Once we have that working, we’ll handle user agent detection and allow toggling between the mobile and full version of our app (because sites that don’t allow you to get at the full version even when your device is capable of rendering it are downright rude).

=== View Paths

When Rails sets out to render one of our templates it looks for them in our controller’s array of view paths. Normally, this is going to contain app/views. View paths work much like the $PATH environment variable in your shell. If you type a command into your shell, your system goes through the directories listed in your $PATH, in order, and runs the first executable of the given name that it finds. Similarly, if Rails wants to render the action for widgets/index, it goes through your view paths in order, looking for a suitable candidate. If it finds app/views/widgets/index.html.erb, it will stop looking and render this file.

This means that if we prepend app/mobile_views to the array of view paths, we can place our custom mobile view for our widget index into app/mobile_views/widgets/index.html.erb. When Rails finds this file, it won’t bother looking in app/views for our default template. However, if we don’t bother creating an app/mobile_views/widgets/show.html.erb file, we can fall back to using the one in app/views. Laziness satisfied!

=== Prepending our Mobile View Path

We can connect to m.mydomain.com (assuming our server is properly configured — I’d suggest ghosting m.[yourhostname].local if you’re testing locally on OS X) and our app will render from app/mobile_views before falling back to the standard app/views.

We’re going to check if a user has specifically requested the mobile or full site in set_mobile_preferences, and if the user’s asked for the full site, we’ll store a “permanent” cookie that says so — this way the next time they visit our application from this device, they’ll immediately be in their preferred viewing format, because the next filter, redirect_to_mobile_if_applicable, only redirects if the request isn’t already being made to m.mydomain.com, the user hasn’t previously stored a cookie that says they’d like the full site, and the user agent appears to be a browser we’d like to redirect to the mobile site. You may want to season your mobile_browser? method to taste. The one I used here works well for my needs.

The only thing that remains is to place a link allowing the mobile user to toggle between sites.

=== View helpers

The following view helpers are made available for switching site

To insert link to the full site

<%= link_to_mobile_site %>

And to link to the full site (only from mobile)

<%= link_to_full_site %>

Translation keys: "app.view_mobile_site" and "app.view_full_site" respectively (for localization)
Or you can explicitly set the label to use (takes any html).

<%= link_to_full_site 'Link to the big site' %>

== Contributing to mobile_view_paths

Expand Down
2 changes: 1 addition & 1 deletion VERSION
@@ -1 +1 @@
0.0.0
0.1.0
3 changes: 3 additions & 0 deletions lib/mobile_view_paths.rb
@@ -0,0 +1,3 @@
require 'mobile_view_paths/mobile_view_path_controller'
require 'mobile_view_paths/view_helper'
require 'mobile_view_paths/engine' if defined?(::Rails::Engine)
9 changes: 9 additions & 0 deletions lib/mobile_view_paths/engine.rb
@@ -0,0 +1,9 @@
module MobileViewPaths
module Rails
module Engine < ::Rails::Engine
initializer 'setup rails' do
ActionView::Base.send :include, MobileViewPaths::DeviseSwitchHelper
end
end
end
end
50 changes: 50 additions & 0 deletions lib/mobile_view_paths/mobile_view_path_controller.rb
@@ -0,0 +1,50 @@
class MobileViewPathController < ActionController::Base
before_filter :set_mobile_preferences
before_filter :redirect_to_mobile_if_applicable
before_filter :prepend_view_path_if_mobile

private

def set_mobile_preferences
if params[:mobile_site]
cookies.delete(:prefer_full_site)
elsif params[:full_site]
cookies.permanent[:prefer_full_site] = 1
redirect_to_full_site if mobile_request?
end
end

def prepend_view_path_if_mobile
if mobile_request?
mobile_path = Rails.root.join("app", "views_mobile")
p = Pathname.new(mobile_path)
controller_path.split('/').each do |a|
p = p + a
end
p = p.join(action_name + ".html.erb")
prepend_view_path(mobile_path) if File.exists?(p)
end
end

def redirect_to_full_site
redirect_to request.protocol + request.host_with_port.gsub(/^m\./, '') +
request.request_uri.gsub(/\?full_site=1/, '') and return
end

def redirect_to_mobile_if_applicable
unless mobile_request? || cookies[:prefer_full_site] || !mobile_browser?
redirect_to request.protocol + "m." + request.host_with_port.gsub(/^www\./, '') +
request.request_uri and return
end
end

def mobile_request?
request.subdomains.first == 'm'
end
helper_method :mobile_request?

def mobile_browser?
request.env["HTTP_USER_AGENT"] && request.env["HTTP_USER_AGENT"][/(iPhone|iPod|iPad|Android)/]
end
helper_method :mobile_browser?
end
13 changes: 13 additions & 0 deletions lib/mobile_view_paths/view_helper.rb
@@ -0,0 +1,13 @@
module MobileViewPaths
module DeviseSwitchHelper
def link_to_mobile_site label
label = t("app.view_mobile_site") || label.html_safe
link_to label, url_for(:mobile_site => 1) if mobile_browser?
end

def link_to_full_site label
label = t("app.view_full_site") || label.html_safe
link_to label, url_for(:full_site => 1)
end
end
end

0 comments on commit 7eff97c

Please sign in to comment.