How to create simple mobile version of an existing rails application.
Lets imagine, we have an existing project that we are developing for some time already - 1 year. At the begginig, the client did not want to have mobile version of his website so our all styles and views were developed to work correctly only on desktop and noone bothered about mobile version. Suddenly, after 1 year client wants his site to work properly on mobile devices.
What options do we have?
- refactor all views and stylesheets to work properly on both desktop and mobile version
- create new mobile module that will handle mobile devices
The main goals we had to achieve:
- keep mobile version as simple as possible - advanced stuff only on desktop version
- all links from desktop version should work on mobile version
- mobile version should have mobile subdomain
- index all pages of mobile version in sitemap
To refactor all views to work properly on mobile version, would take quite alot of time. So we decided to create a mobile module that would handle all requests that are comming from mobile versions.
- duplicate controller from frontend with some changes to keep mobile version as simple as possible
- create mobile constrain in routes.rb to redirect all requests with mobile subdomain to controller from mobile module
- create method that will be fired before each action to check whether or not, the request is commign from mobile device
- redirect desktop urls to mobile, for example: www.sampleweb.com to www.mobile.sampleweb.com
About controllers what we did is absolutely not DRY, but in our case we would need to add additional logic to our controller and we love skinny controller, not fat ones !
First duplicate controllers, and adjust them to return only informations that you will need in mobile version. In our case, we cut down some of the advanced searching mechanisms.
Next lets take care of routes, our main goal is to check whether or not the subdomain consists the mobile pharse. We check it using regexp, /mobile/. If so, we will use controllers from mobile module.
constraints(subdomain: /mobile/) do namespace 'mobile', path: '' do root 'home#show' resources :articles, only: [:index, :show], param: :slug end end scope 'frontend' do root 'home#show' resources :articles, only: [:index, :show], params: :slug end
Another important thing, in our TODO list is to create method that will redirect to mobile version from desktop urls and analogicly.
module CheckMobile class << self def included(klass) klass.send :define_singleton_method, :check_mobile do before_filter :check_if_user_in_on_mobile_device, only: [:show, :index] define_method(:check_if_user_in_on_mobile_device) do if browser.device.mobile? return if request.subdomain == 'mobile' || request.subdomain == 'www.mobile' redirect_to subdomain: 'mobile' else return if request.subdomain == '' || request.subdomain == 'www' redirect_to subdomain: '' end end end end end ActionController::Base.send(:include, CheckMobile) end
First things first, we are creating singleton method inside ActionController::Base class. The method will be fired before each show/index action to check if request.agent is mobile device. To make things simpler, we are using
gem "browser" to check request.agent. If browser.device.mobile? is true, we will change requests subdomain if there is a need to mobile. And analogicly if browser.device.mobile? is false. Of course we have to launch that method in controller, just like any other callback. For example:
class FrontendController < ApplicationController check_mobile end class MobileController < ApplicationController check_mobile end
So wtih those few simple steps we were able to create backend for mobile version of our application.