Rutas Rutas según la condición

Tengo tres roles: Instuctor, Student, Admin y cada uno tiene controladores con una vista “de inicio”.

así que esto funciona bien,

get "instructor/home", :to => "instructor#home" get "student/home", :to => "student#home" get "admin/home", :to => "admin#home" 

Quiero escribir una url de tocador como la que se muestra a continuación, que enrutará en función del rol del user_id en la página de inicio correcta.

 get "/:user_id/home", :to => "instructor#home" or "student#home" or "admin#home" 

¿Cómo logro esto?

No puede hacer esto con las rutas porque el sistema de enrutamiento no cuenta con la información necesaria para tomar esta decisión. Todos los Rails saben en este punto de la solicitud cuáles son los parámetros y no tienen acceso a nada en la base de datos.

Lo que necesita es un método de controlador que pueda cargar cualquier dato que se requiera, presumiblemente el registro del usuario, y redirecciona en consecuencia usando redirect_to .

Esta es una cosa bastante estándar para hacer.

Actualizar:

Para realizar todo esto dentro de una acción de controlador único, deberá dividir su lógica según la función. Un ejemplo es:

 class HomeController < ApplicationController def home case when @user.student? student_home when @user.admin? admin_home when @user.instructor instructor_home else # Unknown user type? Render error or use a default. end end protected def instructor_home # ... render(:template => 'instructor_home') end def student_home # ... render(:template => 'student_home') end def admin_home # ... render(:template => 'admin_home') end end 

Proporciono un enfoque alternativo ya que esta pregunta SO aparece cerca de la parte superior cuando se busca el enrutamiento basado en roles en Rails.

Recientemente necesité implementar algo similar, pero quería evitar tener una gran cantidad de condicionales en el controlador; esto se vio agravado por el hecho de que cada uno de mis roles de usuario requería que se cargaran y presentaran datos completamente diferentes. Opté por mover la lógica de decisión a la capa de enrutamiento mediante el uso de una restricción de enrutamiento .

 # app/constraints/role_route_constraint.rb class RoleRouteConstraint def initialize(&block) @block = block || lambda { |user| true } end def matches?(request) user = current_user(request) user.present? && @block.call(user) end def current_user(request) User.find_by_id(request.session[:user_id]) end end 

La parte más importante del código anterior son las matches? método que determinará si la ruta coincidirá o no. El método se pasa al objeto de request que contiene diversa información sobre la solicitud que se realiza. En mi caso, estoy buscando el :user_id almacenado en la cookie de sesión y usándolo para encontrar al usuario que realiza la solicitud.

Luego puede usar esta restricción al definir sus rutas.

 # config/routes.rb Rails.application.routes.draw do get 'home', to: 'administrators#home', constraints: RoleRouteConstraint.new { |user| user.admin? } get 'home', to: 'instructors#home', constraints: RoleRouteConstraint.new { |user| user.instructor? } get 'home', to: 'students#home', constraints: RoleRouteConstraint.new { |user| user.student? } end 

Con lo anterior en su lugar, un administrador que realice una solicitud a /home se enrutará la acción de inicio del AdministratorsController , un instructor que realice una solicitud a /home se enrutará a la acción de inicio del InstructorsController , y un estudiante haciendo una solicitud a /home se enrutará a la acción local del StudentsController .

Más información

Si está buscando más información, recientemente escribí sobre este enfoque en mi blog .