ruby-on-rails - learn - ruby on rails pdf
Rutas de carriles basadas en condiciĆ³n (2)
Tengo tres roles: Instructor, Estudiante, Administrador 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 vanidad como la de abajo, que se enrutará según la función del user_id
de user_id
a la página de inicio correcta.
get "/:user_id/home", :to => "instructor#home" or "student#home" or "admin#home"
¿Cómo logro esto?
Estoy proporcionando un enfoque alternativo a medida que esta pregunta de SO se acerca a la cima cuando se busca el enrutamiento basado en roles en Rails.
Hace poco tuve que 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 decisiva a la capa de enrutamiento utilizando 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. Al método se le pasa el objeto de request
que contiene información diversa sobre la solicitud que se está realizando. En mi caso, estoy buscando el :user_id
almacenado en la cookie de sesión y lo uso para encontrar al usuario que realiza la solicitud.
A continuación, puede utilizar 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á a la acción de inicio del AdministratorsController
de AdministratorsController
, un instructor que haga una solicitud a /home
se enrutará a la acción de inicio del Control de InstructorsController
, y un estudiante que haga una solicitud a /home
sería enrutado a la acción de home del StudentsController
.
Más información
Si está buscando más información, recientemente escribí sobre este enfoque en mi blog .
No puede hacer esto con rutas porque el sistema de enrutamiento no tiene la información necesaria para tomar esta decisión. All Rails sabe que en este punto de la solicitud es lo que son los parámetros y no tiene 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 redireccione en consecuencia usando redirect_to
.
Esto es una cosa bastante estándar para hacer.
Actualizar:
Para realizar todo esto dentro de una única acción del controlador, deberá dividir su lógica de acuerdo con el rol. 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