Domanda

I am using two default parameters within my routes:

scope '(/:locale)(/:currency)', currency: /eur|usd/, locale: /de|en/, defaults: { currency: 'eur' } do ...

Because the currency should be used for the whole visit, I added locale and currency to the default_url_options in the ApplicationController:

def default_url_options options = {}
 { locale: I18n.locale, currency: params['currency'] }
end

When I generate URLs, i.e. with url_for(), Rails forgets about the currency by default. It only works, when I add it manually. For example:

root_path(currency: params['currency'])

I would like this to be added by default (of course). There is no problem with locale. Rails handles that correctly. (Perhaps because of the globalize3 gem?)

Thank you for any help!

È stato utile?

Soluzione

When your routes are mapped, the defaults from the route declarations are stored in a hash. When you call your route helper foo_path, these defaults are passed as a hash of options to ActionDispatch::Routing.url_for:

def url_for(options = nil)
  case options
  when nil
    _routes.url_for(url_options.symbolize_keys)
  when Hash
    _routes.url_for(options.symbolize_keys.reverse_merge!(url_options))
  when String
    options
  else
    polymorphic_url(options)
  end
end

Now, as we're receiving a hash, it reverse_merge!s with url_options (where your default from overriding the default_url_options is declared!). As it's a reverse_merge! it means that the values in options take precedence over that in url_options, so the default value for currency will always be what it is set to in the routes file, regardless of what you put in your default_url_options in your ApplicationController. These defaults then get passed onto a chain of url_for methods and the like, and your path is returned.

What's more, the currency parameter gets removed from your returned path completetely, with these lines of code:

def format path_options
  path_options.delete_if do |key, value|
    value.to_s == defaults[key].to_s && !required_parts.include?(key)
  end

  Visitors::Formatter.new(path_options).accept(path.spec)
end

It determines that the default value in your path_options ('eur') is equivalent to the defaults from where it was selected (duhhh?), so it removes it for some reason.

So what we've learnt is that the defaults in your routes file will always take precedence over url_options.

My advice therefore, would be to remove the defaults: key from your routing scope, and then you will always have a :currency parameter in your URL, and you can specify the default in the controller.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top