url_rewriter.rb 3.8 KB
Newer Older
D
Initial  
David Heinemeier Hansson 已提交
1
module ActionController
2
  # Rewrites URLs for Base.redirect_to and Base.url_for in the controller.
3

D
Initial  
David Heinemeier Hansson 已提交
4
  class UrlRewriter #:nodoc:
5
    RESERVED_OPTIONS = [:anchor, :params, :only_path, :host, :protocol, :application_prefix]
6 7
    def initialize(request, parameters)
      @request, @parameters = request, parameters
D
Initial  
David Heinemeier Hansson 已提交
8 9 10
      @rewritten_path = @request.path ? @request.path.dup : ""
    end
    
11
    def rewrite(options = {})      
12
      rewrite_url(rewrite_path(options), options)
D
Initial  
David Heinemeier Hansson 已提交
13 14 15
    end

    def to_str
16
  		"#{@request.protocol}, #{@request.host_with_port}, #{@request.path}, #{@parameters[:controller]}, #{@parameters[:action]}, #{@request.parameters.inspect}"
D
Initial  
David Heinemeier Hansson 已提交
17 18
    end

19 20
    alias_method :to_s, :to_str

D
Initial  
David Heinemeier Hansson 已提交
21
    private
22
      def rewrite_url(path, options)        
23
      
D
Initial  
David Heinemeier Hansson 已提交
24
        rewritten_url = ""
25 26
        rewritten_url << (options[:protocol] || @request.protocol) unless options[:only_path]
        rewritten_url << (options[:host] || @request.host_with_port) unless options[:only_path]
D
Initial  
David Heinemeier Hansson 已提交
27

28
        rewritten_url << (options[:application_prefix] || @request.relative_url_root) 
D
Initial  
David Heinemeier Hansson 已提交
29 30
        rewritten_url << path
        rewritten_url << "##{options[:anchor]}" if options[:anchor]
31

D
Initial  
David Heinemeier Hansson 已提交
32 33 34
        return rewritten_url
      end

35 36
      def rewrite_path(options)
        options = options.symbolize_keys
37
        options.update((options[:params]).symbolize_keys) if options[:params]
38 39 40
        RESERVED_OPTIONS.each {|k| options.delete k}
        
        path, extras = Routing::Routes.generate(options, @request)
41
        path = "/#{path.join('/')}".chomp '/'
42
        path = '/' if path.empty?
43 44
        path += build_query_string(extras)
        
D
Initial  
David Heinemeier Hansson 已提交
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
        return path
      end

      def action_name(options, action_prefix = nil, action_suffix = nil)
        ensure_slash_suffix(options, :action_prefix)
        ensure_slash_prefix(options, :action_suffix)

        prefix = options[:action_prefix] || action_prefix || ""
        suffix = options[:action] == "index" ? "" : (options[:action_suffix] || action_suffix || "")
        name   = (options[:action] == "index" ? "" : options[:action]) || ""

        return prefix + name + suffix
      end
      
      def controller_name(options, controller_prefix)
        ensure_slash_suffix(options, :controller_prefix)
61 62 63 64 65 66 67

        controller_name = case options[:controller_prefix]
          when String:  options[:controller_prefix]
          when false : ""
          when nil   : controller_prefix || ""
        end

D
Initial  
David Heinemeier Hansson 已提交
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
        controller_name << (options[:controller] + "/") if options[:controller] 
        return controller_name
      end
      
      def path_params_in_list(options)
        options[:path_params].inject("") { |path, pair| path += "/#{pair.last}" }
      end

      def ensure_slash_suffix(options, key)
        options[key] = options[key] + "/" if options[key] && !options[key].empty? && options[key][-1..-1] != "/"
      end

      def ensure_slash_prefix(options, key)
        options[key] = "/" + options[key] if options[key] && !options[key].empty? && options[key][0..1] != "/"
      end

      def include_id_in_path_params(options)
        options[:path_params] = (options[:path_params] || {}).merge({"id" => options[:id]}) if options[:id]
      end

      # Returns a query string with escaped keys and values from the passed hash. If the passed hash contains an "id" it'll
      # be added as a path element instead of a regular parameter pair.
      def build_query_string(hash)
        elements = []
        query_string = ""
93
        
94
        hash.each do |key, value|
95
          key = key.to_s
D
David Heinemeier Hansson 已提交
96 97 98
          key = CGI.escape key
          key += '[]' if value.class == Array
          value = [ value ] unless value.class == Array
99
          value.each { |val| elements << "#{key}=#{Routing.extract_parameter_value(val)}" }
100
        end
D
Initial  
David Heinemeier Hansson 已提交
101
        
102
        query_string << ("?" + elements.join("&")) unless elements.empty?
D
Initial  
David Heinemeier Hansson 已提交
103 104 105
        return query_string
      end
  end
106
end