简体   繁体   中英

Rails 3 - default_url_options based on url being generated

In rails 3, is it possible to gain access to the controller/action of the URL being generated inside of default_url_options()? In rails 2 you were passed a Hash of the options that were about to be passed to url_for() that you could of course alter.

Eg Rails 2 code:

==== config/routes.rb
  map.foo '/foo/:shard/:id', :controller => 'foo', :action => 'show'

==== app/controllers/application.rb
  def default_url_options options = {}
    options = super(options)
    if options[:controller] == 'some_controller' and options[:id]
      options[:shard] = options[:id].to_s[0..2]
    end
    options
  end

==== anywhere
  foo_path(:id => 12345) # => /foo/12/12345

However, in rails 3, that same code fails due to the fact that default_url_options is not passed any options hash, and I have yet to find out how to test what the controller is.

FWIW, the above "sharding" is due to when you turn caching on, if you have a large number of foo rows in your DB, then you're going to hit the inode limit on unix based systems for number of files in 1 folder at some point. The correct "fix" here is to probably alter the cache settings to store the file in the sharded path rather than shard the route completely. At the time of writing the above code though, part of me felt it was nice to always have the cached file in the same structure as the route, in case you ever wanted something outside of rails to serve the cache.

But alas, I'd still be interested in a solution for the above, purely because it's eating at me that I couldn't figure it out.

Edit: Currently I have the following which I'll have to ditch, since you lose all other named_route functionality.

==== config/routes.rb
  match 'foo/:shard/:id' => 'foo#show', :as => 'original_foo'

==== app/controllers/application.rb
  helpers :foo_path

  def foo_path *args
    opts = args.first if opts.is_a?(Array)
    args = opts.merge(:shard => opts[:id].to_s[0..2]) if opts.is_a?(Hash) and opts[:id]
    original_foo_path(args)
  end

define a helper like

# app/helpers/foo_helper.rb
module FooHelper
  def link_to name, options = {}, &block
    options[:shard] = options[:id].to_s[0..1] if options[:id]
    super name, options, &block
  end 
end

and then do the following in your view, seems to work for me

<%= link_to("my shard", id: 12345) %>

edit: or customize the foo_path as

module FooHelper
  def link_to name, options = {}, &block
    options[:shard] = options[:id].to_s[0..1] if options[:id]
    super name, options, &block
  end 

  def foo_path options = {}
    options[:shard] = options[:id].to_s[0..1] if options[:id]
    super options
  end 
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM