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]
6 7
    def initialize(request, parameters)
      @request, @parameters = request, parameters
D
Initial  
David Heinemeier Hansson 已提交
8 9 10 11
      @rewritten_path = @request.path ? @request.path.dup : ""
    end
    
    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)        
D
Initial  
David Heinemeier Hansson 已提交
23
        rewritten_url = ""
24 25
        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 已提交
26

D
David Heinemeier Hansson 已提交
27
        rewritten_url << options[:application_prefix] if options[:application_prefix]
D
Initial  
David Heinemeier Hansson 已提交
28 29
        rewritten_url << path
        rewritten_url << "##{options[:anchor]}" if options[:anchor]
30

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

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

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

D
Initial  
David Heinemeier Hansson 已提交
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
        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 = ""
92
        
93
        hash.each do |key, value|
94
          key = key.to_s
D
David Heinemeier Hansson 已提交
95 96 97 98
          key = CGI.escape key
          key += '[]' if value.class == Array
          value = [ value ] unless value.class == Array
          value.each { |val| elements << "#{key}=#{CGI.escape(val.to_s)}" }
99
        end
D
Initial  
David Heinemeier Hansson 已提交
100
        
101
        query_string << ("?" + elements.join("&")) unless elements.empty?
D
Initial  
David Heinemeier Hansson 已提交
102 103 104
        return query_string
      end
  end
105
end