【问题标题】:How can I globally override a rails url helper?如何全局覆盖 rails url helper?
【发布时间】:2015-02-23 13:45:16
【问题描述】:

我需要对 foo_path 添加一个简单的更改,所以我这样做了:

module ApplicationHelper
  # [...]

  def foo_path(foo, options = {})
    options.merge!(bar: foo.some_attribute)
    super
  end

  # [...]
end

现在,当从视图调用时,它可以工作,但是当从控制器调用时,将使用没有我添加的原始变体。

如何在应用程序范围内覆盖相应的帮助程序 (_path/_url)?

【问题讨论】:

    标签: ruby-on-rails


    【解决方案1】:

    我认为最简洁的方法是自定义routes.rb 文件(至少对于静态默认参数)。文档:http://guides.rubyonrails.org/routing.html#customizing-resourceful-routes

    默认参数示例

    get "/foo(/:bar)" => "my_controller#index", defaults: { bar: "my_default" }
    

    默认参数值示例+范围

    scope '/(:rec_type)', defaults: { rec_type: 'mammo' }, rec_type: /mammo|face/ do
      resources :patients
    end
    

    其他选项(用于动态限制):

    高级路由约束:

    如果您需要更多高级/动态限制,请查看本指南:http://guides.rubyonrails.org/routing.html#advanced-constraints

    覆盖 default_url_options:

    此外,您可以覆盖default_url_options 方法以使用路由助手自动添加一些属性(参数):http://guides.rubyonrails.org/action_controller_overview.html#default-url-options

    您可以通过在控制器中定义一个名为 default_url_options 的方法来设置 URL 生成的全局默认参数。这样的方法必须返回具有所需默认值的哈希,其键必须是符号:

    class ApplicationController < ActionController::Base
      def default_url_options(options = {})
        if action_name == 'foo' # or other conditions
          options[:bar] = 'your_defaults' # add here your default attributes
        end
    
        options
      end
    end
    

    覆盖 to_param:

    Rails 路由系统在模型上调用 to_param 以获取 :id 占位符的值。 ActiveRecord::Base#to_param 返回模型的 id,但您可以在模型中重新定义该方法。例如,给定:

    class Product < ActiveRecord::Base
      def to_param
        "#{id}-#{title}"
      end
    end
    

    这将生成:/products/254-Foo

    【讨论】:

    • 我更新了相关行以澄清实际上动态值已合并到options (foo.some_attribute)。
    【解决方案2】:

    在 Rails 3 和 4 中,路由 url 助手都驻留在这个模块 Rails.application.routes.url_helpers 中。所以我们可以包含一个模块来覆盖其中的方法。

    module FooUrlHelper
      def foo_path(foo, options = {})
        options.merge!(bar: foo.some_attribute)
        super
      end
    end
    
    # Works at Rails 4.2.1
    Rails.application.routes.url_helpers.send(:include, FooUrlHelper)
    
    # For Rails 4.2.6, I thought the following worked, but there seems to be issues, don't have time to figure out a solution yet
    Rails.application.routes.named_routes.url_helpers_module.send(:include, FooUrlHelper)
    

    你可以把它放在初始化器中

    我在控制台和控制器中试过这个,似乎工作正常。

    【讨论】:

    • 这种方法的优点是,与ApplicationController中的添加或别名方法不同,它适用于所有使用URL助手的地方,例如邮件模板。
    • 你能解释一下你在初始化器中到底放了什么吗?您是否将module FooUrlHelper 放在/helpers/ 目录中,然后创建了一个包含单行Rails.application.routes.named_routes... 的初始化程序?
    • @DelPiero 我在初始化程序下创建了一个文件,其中包含模块定义和一个“包含”调用,因此它在启动时包含。
    【解决方案3】:

    看起来你的方向不对。您最好在路线中添加 :bar 参数,例如:

    get :foo, :bar => "bar"
    

    否则,请提供有关您的问题的更多描述性详细信息。

    编辑。

    这是解决方案(基于您的帖子更新):

    class ApplicationController < ActionController::Base
      def foo_path(foo, options = {})
        options.merge!(bar: foo.some_attribute)
        super
      end  
      helper_method :foo_path
    end
    

    【讨论】:

    • 我更新了相关行以澄清实际上动态值已合并到options (foo.some_attribute)。
    • 这样不行。该参数必须存在于 url 中,否则 rails 将如何知道 :bar 参数的值应该是什么。所以,主要是,答案是foo_path(foo, :bar =&gt; foo.some_attribute),它将生成类似/foo/:id?bar=some_attr_value的url
    • 它已经可以工作了——只是从控制器调用时它没有被使用。它“知道”是因为它明确分配了foo.some_attribute 的值。
    • 看起来像是误会。我的意思是 :bar 参数必须存在于 url 中。所以,基本上,您只希望 foo_path 在调用时始终添加 :bar 参数而不显式传递它?
    • 是的——我想打电话给foo_path(@foo),而不是foo_path(@foo, bar: @foo.some_attribute):bar 是已定义路由的一部分(类似于get ':id/:bar' ...)。
    【解决方案4】:

    正如当前答案所示,您不是覆盖 rails 助手(定义在 app/helpers 文件夹中的某处),而是覆盖路由助手(定义在 config/routes.rb 中)。

    从视图中调用方法foo_path 是可行的,因为首先Rails 会先查看所有可用的应用程序助手方法,然后再查看可用的路由助手方法。

    从控制器调用方法不起作用,因为 Rails 只会通过可用的路由助手方法,而不是通过路由助手。

    如果您想从控制器调用应用程序助手,请在控制器中使用它:

    view_context.foo_path(...)
    

    这要求您在每个控制器内每次调用 foo_path 之前都添加 view_context.,因此它不是一个完美的解决方案,但它应该可以工作。

    【讨论】:

    • +1 进行解释。谢谢。也许这应该说“不通过rails helpers”? "[...] 只会通过可用的路由助手方法,而不是通过路由助手。[...]"
    猜你喜欢
    • 1970-01-01
    • 2020-07-28
    • 1970-01-01
    • 1970-01-01
    • 2014-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-21
    相关资源
    最近更新 更多