【问题标题】:Rails route scope default based on current_userRails 路由范围默认基于 current_user
【发布时间】:2016-03-27 20:28:59
【问题描述】:

我有一条类似的路线:

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)

【问题讨论】:

  • 没有。 current_user,这是您的控制器的一种方法,在执行路由并选择控制器/动作并实例化控制器之前不存在。
  • 如果这不可能,那么我该如何克服我的问题。我已经更新了我的问题,提供了更多详细信息。

标签: ruby-on-rails ruby


【解决方案1】:

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

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 路径段的每个 路由,您都拥有像department_students_path 这样的辅助方法。这些将像students_path 一样工作——您可以传入 opts,您甚至可以显式设置:department,它将覆盖默认值。他们会及时更新您的 routes.rb 的更改,而无需您维护它。

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

define_method :"#{route.name}_path"

不必在它们前面加上department_--我没有这样做,因为我宁愿避免这样的命名冲突。我不确定它是如何工作的(当从视图模板调用它时,哪个方法会赢得方法查找),但你可以研究一下。

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

要使助手在控制器和视图上可用,只需在 ApplicationController 中添加 include UrlHelper

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

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

【讨论】:

  • 这会起作用,但这不会将department 参数添加到甚至不接受此属性的路由中吗?因此,例如,如果我链接到 about_path(位于根级别而不是部门),我会得到 /about?department=math
  • 是的,没错。这就是我的意思,您可能只想在控制器子集上定义它或添加一些其他逻辑。例如,如果您关心自动添加此链接的唯一链接是 StudentsController 的路由,您可以在该控制器上定义此链接,而不是 ApplicationController
  • 关于页面的链接位于我的应用程序的每个页面的页脚中。这使得在没有我上面提到的副作用的情况下实现您的解决方案是不可能的。
  • 好吧,我看到了问题 - default_url_options 实际上并没有按照我的预期工作。将使用修改后的解决方案编辑上面的答案,尽管它会涉及猴子补丁。
  • helper只是一个模块,你可以include UrlHelper in ApplicationController
【解决方案2】:

路由约束可以接受一个过程,所以你可以用下面的“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

路由问题是 rails 4 的一个特性。如果你不使用 rails 4,你能通过这个 gem 获得这个特性吗:https://github.com/rails/routing_concerns

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

【讨论】:

    【解决方案3】:

    你可以使用

    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!
    

    【讨论】:

    • 我没有访问/students?department=any_department。我已经更新了我的问题以指示 URL。另外,我不喜欢必须为我的每条路线制作一个助手的想法。这会变得非常难看,很快
    • 我不明白这怎么会变得丑陋。
    • 好吧,因为我有数百条路线。我只是提供了学生资源作为示例。我不想为每一个都实现一个助手。此外,如果我的路线名称因某种原因发生更改,我还必须更新帮助程序以保持命名同步。
    【解决方案4】:

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

    resources :departments do
      resources :students
    end
    

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

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

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

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

    # 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
    

    【讨论】:

    • 我想到处通过当前用户的部门。另外,我需要为我拥有的每条路线制作一个助手
    • 对不起,但至少它是一种更短的编写方式(没有助手)。没有“好”的方法可以做你想做的事,但我发布了一个可能会有所帮助的技巧。
    【解决方案5】:

    我最终在ApplicationController 中指定了它:

    def default_url_options(options={})
        {department: current_user.department.name}
    end
    

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

    【讨论】:

      猜你喜欢
      • 2011-09-02
      • 1970-01-01
      • 1970-01-01
      • 2014-01-30
      • 1970-01-01
      • 1970-01-01
      • 2015-04-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多