Module: ActionDispatch::Routing::Mapper::CustomUrls

Included in:
ActionDispatch::Routing::Mapper
Defined in:
lib/action_dispatch/routing/mapper.rb

Instance Method Summary collapse

Instance Method Details

#direct(name, options = {}, &block) ⇒ Object

Define custom URL helpers that will be added to the application’s routes. This allows you to override and/or replace the default behavior of routing helpers, e.g:

direct :homepage do
  "https://rubyonrails.org"
end

direct :commentable do |model|
  [ model, anchor: model.dom_id ]
end

direct :main do
  { controller: "pages", action: "index", subdomain: "www" }
end

The return value from the block passed to ‘direct` must be a valid set of arguments for `url_for` which will actually build the URL string. This can be one of the following:

  • A string, which is treated as a generated URL

  • A hash, e.g. ‘{ controller: “pages”, action: “index” }`

  • An array, which is passed to ‘polymorphic_url`

  • An Active Model instance

  • An Active Model class

NOTE: Other URL helpers can be called in the block but be careful not to invoke your custom URL helper again otherwise it will result in a stack overflow error.

You can also specify default options that will be passed through to your URL helper definition, e.g:

direct :browse, page: 1, size: 10 do |options|
  [ :products, options.merge(params.permit(:page, :size).to_h.symbolize_keys) ]
end

In this instance the ‘params` object comes from the context in which the block is executed, e.g. generating a URL inside a controller action or a view. If the block is executed where there isn’t a ‘params` object such as this:

Rails.application.routes.url_helpers.browse_path

then it will raise a ‘NameError`. Because of this you need to be aware of the context in which you will use your custom URL helper when defining it.

NOTE: The ‘direct` method can’t be used inside of a scope block such as ‘namespace` or `scope` and will raise an error if it detects that it is.



2223
2224
2225
2226
2227
2228
2229
# File 'lib/action_dispatch/routing/mapper.rb', line 2223

def direct(name, options = {}, &block)
  unless @scope.root?
    raise RuntimeError, "The direct method can't be used inside a routes scope block"
  end

  @set.add_url_helper(name, options, &block)
end

#resolve(*args, &block) ⇒ Object

Define custom polymorphic mappings of models to URLs. This alters the behavior of ‘polymorphic_url` and consequently the behavior of `link_to`, `form_with` and `form_for` when passed a model instance, e.g:

resource :basket

resolve "Basket" do
  [:basket]
end

This will now generate “/basket” when a ‘Basket` instance is passed to `link_to`, `form_with` or `form_for` instead of the standard “/baskets/:id”.

NOTE: This custom behavior only applies to simple polymorphic URLs where a single model instance is passed and not more complicated forms, e.g:

# config/routes.rb
resource :profile
namespace :admin do
  resources :users
end

resolve("User") { [:profile] }

# app/views/application/_menu.html.erb
link_to "Profile", @current_user
link_to "Profile", [:admin, @current_user]

The first ‘link_to` will generate “/profile” but the second will generate the standard polymorphic URL of “/admin/users/1”.

You can pass options to a polymorphic mapping - the arity for the block needs to be two as the instance is passed as the first argument, e.g:

resolve "Basket", anchor: "items" do |basket, options|
  [:basket, options]
end

This generates the URL “/basket#items” because when the last item in an array passed to ‘polymorphic_url` is a hash then it’s treated as options to the URL helper that gets called.

NOTE: The ‘resolve` method can’t be used inside of a scope block such as ‘namespace` or `scope` and will raise an error if it detects that it is.



2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
# File 'lib/action_dispatch/routing/mapper.rb', line 2275

def resolve(*args, &block)
  unless @scope.root?
    raise RuntimeError, "The resolve method can't be used inside a routes scope block"
  end

  options = args.extract_options!
  args = args.flatten(1)

  args.each do |klass|
    @set.add_polymorphic_mapping(klass, options, &block)
  end
end