【问题标题】:How can I redirect a user's home (root) path based on their role using Devise?如何使用 Devise 根据用户的角色重定向用户的主(根)路径?
【发布时间】:2014-02-03 01:14:15
【问题描述】:

我正在开发一个项目管理应用程序,在该应用程序中,我有 project_managersclients。我正在使用 Devise 和 CanCan 进行身份验证/授权。

我应该在登录后的什么时候将用户重定向到他们自己的特定控制器/布局/视图?有没有办法在routes.rb 中检查current_user.role 并根据他们是项目经理还是客户来设置根(或重定向)?这是我可以在 Devise 的某个地方做出的改变吗?

提前感谢您的帮助! --马克

【问题讨论】:

标签: ruby-on-rails authentication routes devise cancan


【解决方案1】:

您的routes.rb 文件不知道用户拥有什么角色,因此您将无法使用它来分配特定的根路由。

您可以做的是设置一个控制器(例如,passthrough_controller.rb),它反过来可以读取角色并重定向。像这样的:

# passthrough_controller.rb
class PassthroughController < ApplicationController
  def index
    path = case current_user.role
      when 'project_manager'
        some_path
      when 'client'
        some_other_path
      else
        # If you want to raise an exception or have a default root for users without roles
    end

    redirect_to path     
  end
end

# routes.rb
root :to => 'passthrough#index'

这样,所有用户都将拥有一个入口点,然后根据他们的角色将他们重定向到适当的控制器/操作。

【讨论】:

  • stackoverflow.com/questions/4753871/… 是一个更好的实现,因为它不会为重定向创建新的控制器。此外,每次将用户重定向到 root_path 时,这将导致从浏览器到服务器的 1 次额外往返
  • 优雅的解决方案,不需要更改任何现有代码,即我可以将所有redirect_to root_path 语句保持原样。我喜欢它:)
  • 这对我很有效。我决定把它放在我的应用程序控制器中,一切看起来都很花哨……但是你有什么理由为它设置一个全新的控制器吗?只是想知道我是否忽略了什么。
【解决方案2】:

另一种选择是像这样将 proc 传递给 authenticated 方法(我在这个例子中使用 rolify):

authenticated :user, ->(u) { u.has_role?(:manager) } do
  root to: "managers#index", as: :manager_root
end

authenticated :user, ->(u) { u.has_role?(:employee) } do
  root to: "employees#index", as: :employee_root
end

root to: "landing_page#index"

请注意,在 Rails 4 中,您必须为每个根路由指定一个唯一名称,有关详细信息,请参阅 this issue

【讨论】:

  • 让我们为这个答案投票吧!应该被接受为正确的
  • 有没有办法让用户决定路径? IE。 root to: organization_path(user.organization)
【解决方案3】:

最简单的解决方案是使用lambda

root :to => 'project_managers#index', :constraints => lambda { |request| request.env['warden'].user.role == 'project_manager' }
root :to => 'clients#index'

【讨论】:

  • 它对我有用。但我有个问题。我正在使用 Ruby 2.3.0,它允许我使用新的 stabby lambda 语法。但是我收到constraints: -&gt; { ... } 的语法错误。如果我使用lambda 而不是-&gt;,它工作正常。对此有任何想法吗?
  • 应该可以为:to 选项(root to: proc { |env| ...})使用 proc/lambda,但我遇到了各种问题,因为它似乎破坏了url_for。该解决方案在不破坏url_for 的情况下有效。 +1!
【解决方案4】:

我在使用 Warden 的 Rails 3 应用程序中执行此操作。由于 Devise 是建立在 Warden 之上的,我认为它会为您工作,但请务必在依赖它之前对其进行一些试验。

class ProjectManagerChecker
  def self.matches?(request)
    request.env['warden'].user.role == 'project_manager'
  end
end

# routes.rb
get  '/' => 'project_managers#index', :constraints => ProjectManagerChecker
get  '/' => 'clients#index'

如果用户的角色是“project_manager”,则将使用 ProjectManagersController - 如果不是,则使用 ClientsController。如果他们根本没有登录,env['warden'].user 将为 nil 并且您会收到一个错误,因此您可能想要解决这个问题,但这会让您开始。

【讨论】:

  • 感谢您的回答!我实际上首先尝试了这个,但我无法让它工作(可能是因为我是新手)。更不用说——我现在几乎不知道自己在做什么,所以“试验一下”的想法简直太可怕了!
【解决方案5】:
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-29
相关资源
最近更新 更多