Rails路由基于条件
我有三个角色:Instuctor,Student,Admin,每个角色都有一个带有“home”视图的控制器。
所以这很好,
get "instructor/home", :to => "instructor#home" get "student/home", :to => "student#home" get "admin/home", :to => "admin#home"
我想写一个类似于下面的虚荣url,它会根据user_id
的角色路由到正确的主页。
get "/:user_id/home", :to => "instructor#home" or "student#home" or "admin#home"
我该如何做到这一点?
您不能对路由执行此操作,因为路由系统没有做出此决定所需的信息。 所有Rails在此时都知道请求是参数是什么,并且不能访问数据库中的任何内容。
您需要的是一种控制器方法,可以加载所需的任何数据,可能是用户记录,并使用redirect_to
相应的redirect_to
。
这是一个相当标准的事情。
更新:
要在单个控制器操作中执行所有这些操作,您需要根据角色拆分逻辑。 一个例子是:
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
我正在提供一种替代方法,因为当在Rails中搜索基于角色的路由时,这个问题出现在顶部附近。
我最近需要实现类似的东西,但希望避免在控制器中有大量的条件 – 由于我的每个用户角色都需要加载和呈现完全不同的数据这一事实。 我选择使用路由约束将决策逻辑移动到路由层。
# 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
上面代码中最重要的部分是matches?
确定路线是否匹配的方法。 该方法传递给request
对象,该对象包含有关正在进行的请求的各种信息。 在我的情况下,我正在查找存储在会话cookie中的:user_id
,并使用它来查找发出请求的用户。
然后,您可以在定义路线时使用此约束。
# 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
完成上述操作后,向/home
发出请求的管理员将被路由到AdministratorsController
的主动作,向/home
发出请求的教师将被路由到InstructorsController
主动作,并且学生发出请求/home
将被路由到StudentsController
的主页操作。
更多信息
如果您正在寻找更多信息,我最近在我的博客上写了这个方法。