Rails路由范围默认基于current_user

时间:2013-06-14 15:15:06

标签: ruby-on-rails ruby

我的路线如下:

scope ":department", department: /admin|english|math/, defaults: { department: 'admin' }

是否可以使此路线的默认部门基于current_user.department.name

如果无法做到这一点,那么解决问题的另一种方法是什么。问题是除非另有说明,否则我希望所有链接都默认为当前范围。我目前正在很多地方做以下事情:

# links to /math/students
link_to 'students', students_path(department: current_user.department.name.downcase)

5 个答案:

答案 0 :(得分:6)

如果我理解正确,你想要写的是:

link_to 'students', students_path

并根据当前用户自动设置部门选项。

这是一个解决方案,就像其他一些提供的解决方案:为每个需要部门的路线定义帮助器。但是,我们可以通过编程方式执行此操作。

我们走了: app/helpers/url_helper.rb

module UrlHelper

  Rails.application.routes.routes.named_routes.values.
    select{ |route| route.parts.include?(:department) }.each do |route|
      define_method :"department_#{route.name}_path" do |*args|
        opts = args.extract_options!
        if args.size > 0
          keys = route.parts - [:department]
          opts.merge!(Hash[*keys.zip(args).flatten])
        end
        opts.reverse_merge!(department: current_user.department.name.downcase)
        Rails.application.routes.url_helpers.send(:"#{route.name}_path", opts)
      end
  end

end

现在,对于每个路径都有department_students_path路径段的:department辅助方法。这些工作就像students_path一样 - 您可以传入opts,甚至可以显式设置:department,它将覆盖默认值。并且他们会及时了解您routes.rb的更改,而无需维护它。

您甚至可以将它们命名为与原始助手相同,即

define_method :"#{route.name}_path"

不必用department_作为前缀 - 我没有这样做,因为我宁愿避免命名这样的碰撞。我不确定它是如何工作的(当从视图模板调用方法时,哪种方法会赢得方法查找),但你可能会研究它。

您当然可以针对_url辅助方法重复此块,因此除了_path之外,您还可以使用这些方法。

要在控制器和视图中使用帮助程序,只需include UrlHelper中的ApplicationController

所以我认为这符合您的标准:

  1. 您可以为范围为:department的路径调用辅助方法,默认为current_user的部门,这样您就不必每次都明确指定。
  2. 帮助程序是通过元编程生成的,基于实际定义的具有:department段的命名路径,因此您无需维护它们。
  3. 与内置的rails url_helpers一样,这些人可以将位置args用于其他路径段,例如department_student_path(@student)。但是,一个限制是,如果要覆盖部门,则需要在最终的opts哈希(department_student_path(@student, department: 'math'))中执行此操作。再说一次,在这种情况下你可以随时做student_path('math', @student),所以我认为这不是一个限制。

答案 1 :(得分:1)

路线约束可以接受一个proc,所以你可以通过以下“hack”来解决这个问题:

concern :student_routes do
  # all your routes where you want this functionality
end

# repeat this for all departments
scope ":department", constraints: lambda{|req| req.session[:user_id] && User.find(req.session[:user_id]).department.name.downcase == "english"}, defaults: { department: 'english' } do
  concerns :student_routes
end

路线问题是导轨4的一项功能。如果您不使用导轨4,您是否可以获得此宝石的功能:https://github.com/rails/routing_concerns

您也可以将学生的所有路线复制到所有范围。

答案 2 :(得分:0)

您可以使用

link_to 'students', polymorphic_path([current_user.department.name.downcase, :students])

这将调用

math_students_path

所以上班我觉得你应该添加你的路线

scope ':department', as: 'department' do
  ...

as键生成以下形式的帮助:department_something_path

由于该行太长,您可以将其提取给帮助者

# students path taking into account department
def students_path!(other_params = {}, user = current_user)
  polymorphic_path([user.department.name.downcase, :students], other_params)

然后您将在您的观点中使用

link_to 'students', students_path!

答案 3 :(得分:0)

使用嵌套路由怎么样?您可以通过以下方式实现此目的:

resources :departments do
  resources :students
end

如果您想使用友好的网址(例如“数学”而不是ID),可以将以下内容添加到部门模型中:

  # in models/department.rb
  def to_param
    name.downcase
  end

记住每个部门的名称必须是唯一的。 Ryan B对此提出了railscast。你也可以使用像friendly id这样的宝石。

您现在可以在视图中添加以下内容:

# links to /math/students
link_to 'students', department_students_path(current_user.department)

如果你经常使用它,那么创建一个帮手:

# helpers/student_helpers.rb
def students_path_for_current_user
  department_students_path(current_user.department)
end

# in view
link_to 'students', students_path_for_current_user

答案 4 :(得分:0)

我最终在ApplicationController中使用:

指定了它
def default_url_options(options={})
    {department: current_user.department.name}
end

路径助手将填充自动填写:department参数然后...