How can I globally override a rails url helper?

前端 未结 4 2181
时光取名叫无心
时光取名叫无心 2020-12-06 12:30

I needed to add a simple change to foo_path, so I did this:

module ApplicationHelper
  # [...]

  def foo_path(foo, options = {})
    option         


        
相关标签:
4条回答
  • 2020-12-06 13:10

    I think the cleanest way to achieve that is to customize routes.rb file (at least for static default parameters). Docs: http://guides.rubyonrails.org/routing.html#customizing-resourceful-routes

    Default param example:

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

    Default param value example + scope:

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

    Other options (for dynamic restriccions):

    Advanced routing constraints:

    If you need more advanced/dynamic restrictions, take a look to this guide: http://guides.rubyonrails.org/routing.html#advanced-constraints.

    Override default_url_options:

    Also, you can override default_url_options method to automatically add some attributes (params) using routes helpers: http://guides.rubyonrails.org/action_controller_overview.html#default-url-options.

    You can set global default parameters for URL generation by defining a method called default_url_options in your controller. Such a method must return a hash with the desired defaults, whose keys must be symbols:

    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
    

    Override to_param:

    Rails routing system calls to_param on models to get a value for the :id placeholder. ActiveRecord::Base#to_param returns the id of a model, but you can redefine that method in your models. For example, given:

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

    This would generate: /products/254-Foo

    0 讨论(0)
  • 2020-12-06 13:10

    In Rails 3 and 4, route url helpers all resides in this module Rails.application.routes.url_helpers. So we can include a module to override methods inside it.

    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)
    

    You can just place this inside initializers

    I tried this in console and controller and seems to work fine.

    0 讨论(0)
  • 2020-12-06 13:12

    As the current answers show, you are not overriding a rails helper (as defined somewhere in the app/helpers folder) but a route helper (as defined in config/routes.rb).

    Calling the method foo_path from a view works, because first Rails will look through all available application helper methods before looking through the available routing helper methods.

    Calling the method from a controller does not work, because Rails will only go through the available routing helper methods, not through the routing helpers.

    If you want to call an application helper from a controller, use this inside your controller:

    view_context.foo_path(...)
    

    This requires you to prepend view_context. for every call to foo_path inside every controller, so it is not a perfect solution but it should work.

    0 讨论(0)
  • 2020-12-06 13:26

    Looks like you are facing wrong way. You would better add :bar param in your route, like:

    get :foo, :bar => "bar"
    

    Otherwise, please provide more descriptive details about your problem.

    Edit.

    Here is the solution(basic on your post update):

    class ApplicationController < ActionController::Base
      def foo_path(foo, options = {})
        options.merge!(bar: foo.some_attribute)
        super
      end  
      helper_method :foo_path
    end
    
    0 讨论(0)
提交回复
热议问题