Cómo tener root_path diferentes para mobile y desktop en Ruby on Rails

A veces, necesitamos responder a las requests direccionando a diferentes rutas según ciertas condiciones; como pueden ser, si el usuario está logueado o no, desde qué tipo de dispositivo está accediendo (desktop o mobile), o incluso restringir el acceso por IP. Una solución común es redirigir desde el controlador a la ruta correspondiente; sin embargo, esta no siempre es la forma más eficiente de resolverlo.

En nuestro caso, queremos renderizar dos vistas distintas según si el acceso es desde un celular o una computadora. Para lograr esto de esta manera, podríamos tener algo así 👇

# config/routes.rb
Rails.application.routes.draw do
...
resource :calendar, only: [:show]
resource :home, only: [:show], controller: 'home'
root 'root#index'
...
end

# app/controllers
class RootController < ApplicationController
def index
case request.user_agent.downcase
when /iphone|android|mobile/
redirect_to home_path
else
redirect_to calendar_path
end
end
end

Por suerte, Rails ofrece otra manera de lograr esto, mediante el uso de request-based constraints, lo que nos permite definir condiciones directamente junto a las rutas. Esto resuelve a nivel de capa de red a qué ruta direccionar.

Dado que ya no necesitamos la lógica en el controlador, vamos a actualizar routes.rb, definiendo una constraint que según el user agent de la request determina a qué root path direccionar.

# config/routes.rb
Rails.application.routes.draw do
...
resource :calendar, only: [:show]
resource :home, only: [:show], controller: 'home'

constraints(lambda { |req| req.user_agent.downcase.match?(/iphone|android|mobile/) }) do
root 'home#show', as: :mobile_root
end

root 'calendars#show'
...
end

Es importante que siempre haya un root path definido, ya que si Rails no encuentra un root path que coincida con la constraint, usará el root path por defecto como respaldo. A su vez, los root paths deben tener nombres distintos (y ser únicos); por eso es que agregamos as: :mobile_root.

Entonces, root ‘calendars#show’ define la ruta para usuarios cuya request no provenga de un dispositivo móvil. En cambio, root ‘home#show’ define la ruta raíz para aquellas requests donde el user agent sea iPhone, Android o mobile, es decir, que provengan de un dispositivo móvil.

En resumen, aprovechar las constraints para definir rutas dinámicas no solo simplifica como se adapta la aplicación a diferentes situaciones, sino que también refuerza el principio de Rails de “convention over configuration”. De esta manera se evitan redirecciones innecesarias en el controlador, logrando un código más limpio, directo y fácil de mantener.