diff options
Diffstat (limited to 'actionpack')
80 files changed, 1254 insertions, 722 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 32630e5ded..99602f14d9 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,5 +1,24 @@  ## Rails 4.0.0 (unreleased) ## +*   Replace `include_seconds` boolean argument with `:include_seconds => true` option +    in `distance_of_time_in_words` and `time_ago_in_words` signature. *Dmitriy Kiriyenko* + +*   Remove `button_to_function` and `link_to_function` helpers. *Rafael Mendonça França* + +*   Make current object and counter (when it applies) variables accessible when +    rendering templates with :object / :collection. *Carlos Antonio da Silva* + +*   JSONP now uses mimetype application/javascript instead of application/json *omjokine* + +*   Allow to lazy load `default_form_builder` by passing a `String` instead of a constant. *Piotr Sarnacki* + +*   Session arguments passed to `process` calls in functional tests are now merged into +    the existing session, whereas previously they would replace the existing session. +    This change may break some existing tests if they are asserting the exact contents of +    the session but should not break existing tests that only assert individual keys. + +    *Andrew White* +  *   Add `index` method to FormBuilder class. *Jorge Bejar*  *   Remove the leading \n added by textarea on assert_select. *Santiago Pastorino* @@ -135,7 +154,7 @@      HTML5 `mark` element. *Brian Cardarella* -## Rails 3.2.3 (unreleased) ## +## Rails 3.2.3 (March 30, 2012) ##  *   Add `config.action_view.embed_authenticity_token_in_remote_forms` (defaults to true) which allows to set if authenticity token will be included by default in remote forms. If you change it to false, you can still force authenticity token by passing `:authenticity_token => true` in form options *Piotr Sarnacki* diff --git a/actionpack/lib/action_controller/metal/data_streaming.rb b/actionpack/lib/action_controller/metal/data_streaming.rb index 369741fb12..374645c9ce 100644 --- a/actionpack/lib/action_controller/metal/data_streaming.rb +++ b/actionpack/lib/action_controller/metal/data_streaming.rb @@ -8,10 +8,8 @@ module ActionController #:nodoc:      include ActionController::Rendering -    DEFAULT_SEND_FILE_OPTIONS = { -      :type         => 'application/octet-stream'.freeze, -      :disposition  => 'attachment'.freeze, -    }.freeze +    DEFAULT_SEND_FILE_TYPE        = 'application/octet-stream'.freeze #:nodoc: +    DEFAULT_SEND_FILE_DISPOSITION = 'attachment'.freeze #:nodoc:      protected        # Sends the file. This uses a server-appropriate method (such as X-Sendfile) @@ -127,7 +125,7 @@ module ActionController #:nodoc:        #        # See +send_file+ for more information on HTTP Content-* headers and caching.        def send_data(data, options = {}) #:doc: -        send_file_headers! options.dup +        send_file_headers! options          render options.slice(:status, :content_type).merge(:text => data)        end @@ -135,15 +133,8 @@ module ActionController #:nodoc:        def send_file_headers!(options)          type_provided = options.has_key?(:type) -        options.update(DEFAULT_SEND_FILE_OPTIONS.merge(options)) -        [:type, :disposition].each do |arg| -          raise ArgumentError, ":#{arg} option required" if options[arg].nil? -        end - -        disposition = options[:disposition] -        disposition += %(; filename="#{options[:filename]}") if options[:filename] - -        content_type = options[:type] +        content_type = options.fetch(:type, DEFAULT_SEND_FILE_TYPE) +        raise ArgumentError, ":type option required" if content_type.nil?          if content_type.is_a?(Symbol)            extension = Mime[content_type] @@ -157,10 +148,13 @@ module ActionController #:nodoc:            self.content_type = content_type          end -        headers.merge!( -          'Content-Disposition'       => disposition, -          'Content-Transfer-Encoding' => 'binary' -        ) +        disposition = options.fetch(:disposition, DEFAULT_SEND_FILE_DISPOSITION) +        unless disposition.nil? +          disposition += %(; filename="#{options[:filename]}") if options[:filename] +          headers['Content-Disposition'] = disposition +        end + +        headers['Content-Transfer-Encoding'] = 'binary'          response.sending_file = true diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb index fa760f2658..17e2db74d4 100644 --- a/actionpack/lib/action_controller/metal/params_wrapper.rb +++ b/actionpack/lib/action_controller/metal/params_wrapper.rb @@ -66,7 +66,7 @@ module ActionController    #     class Admin::UsersController < ApplicationController    #     end    # -  # will try to check if +Admin::User+ or +User+ model exists, and use it to +  # will try to check if <tt>Admin::User</tt> or +User+ model exists, and use it to    # determine the wrapper key respectively. If both models don't exist,    # it will then fallback to use +user+ as the key.    module ParamsWrapper diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb index 35ded8a56c..5e7bd44562 100644 --- a/actionpack/lib/action_controller/metal/redirecting.rb +++ b/actionpack/lib/action_controller/metal/redirecting.rb @@ -45,6 +45,16 @@ module ActionController      # integer, or a symbol representing the downcased, underscored and symbolized description.      # Note that the status code must be a 3xx HTTP code, or redirection will not occur.      # +    # If you are using XHR requests other than GET or POST and redirecting after the +    # request then some browsers will follow the redirect using the original request +    # method. This may lead to undesirable behavior such as a double DELETE. To work +    # around this  you can return a <tt>303 See Other</tt> status code which will be +    # followed using a GET request. +    # +    # Examples: +    #   redirect_to posts_url, :status => :see_other +    #   redirect_to :action => 'index', :status => 303 +    #      # It is also possible to assign a flash message as part of the redirection. There are two special accessors for the commonly used flash names      # +alert+ and +notice+ as well as a general purpose +flash+ bucket.      # diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb index 6e9ce450ac..4a0c1c7dd7 100644 --- a/actionpack/lib/action_controller/metal/renderers.rb +++ b/actionpack/lib/action_controller/metal/renderers.rb @@ -91,9 +91,14 @@ module ActionController      add :json do |json, options|        json = json.to_json(options) unless json.kind_of?(String) -      json = "#{options[:callback]}(#{json})" unless options[:callback].blank? -      self.content_type ||= Mime::JSON -      json + +      if options[:callback].present? +        self.content_type ||= Mime::JS +        "#{options[:callback]}(#{json})" +      else +        self.content_type ||= Mime::JSON +        json +      end      end      add :js do |js, options| diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb index 52aaed0ed4..eeb37db2e7 100644 --- a/actionpack/lib/action_controller/metal/streaming.rb +++ b/actionpack/lib/action_controller/metal/streaming.rb @@ -139,17 +139,17 @@ module ActionController #:nodoc:    # session or flash after the template starts rendering will not propagate    # to the client.    # -  # If you try to modify cookies, session or flash, an +ActionDispatch::ClosedError+ +  # If you try to modify cookies, session or flash, an <tt>ActionDispatch::ClosedError</tt>    # will be raised, showing those objects are closed for modification.    #    # == Middlewares    #    # Middlewares that need to manipulate the body won't work with streaming.    # You should disable those middlewares whenever streaming in development -  # or production. For instance, +Rack::Bug+ won't work when streaming as it +  # or production. For instance, <tt>Rack::Bug</tt> won't work when streaming as it    # needs to inject contents in the HTML body.    # -  # Also +Rack::Cache+ won't work with streaming as it does not support +  # Also <tt>Rack::Cache</tt> won't work with streaming as it does not support    # streaming bodies yet. Whenever streaming Cache-Control is automatically    # set to "no-cache".    # diff --git a/actionpack/lib/action_controller/record_identifier.rb b/actionpack/lib/action_controller/record_identifier.rb index 5c40889f6b..e7af3f5b8d 100644 --- a/actionpack/lib/action_controller/record_identifier.rb +++ b/actionpack/lib/action_controller/record_identifier.rb @@ -75,12 +75,7 @@ module ActionController      def record_key_for_dom_id(record)        record = record.to_model if record.respond_to?(:to_model)        key = record.to_key -      key ? sanitize_dom_id(key.join('_')) : key -    end - -    # Replaces characters that are invalid in HTML DOM ids with valid ones. -    def sanitize_dom_id(candidate_id) -      candidate_id # TODO implement conversion to valid DOM id values +      key ? key.join('_') : key      end    end  end diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index 55a9819316..21997c4d79 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -27,13 +27,13 @@ module ActionController          path = payload[:virtual_path]          next unless path          partial = path =~ /^.*\/_[^\/]*$/ +          if partial            @partials[path] += 1            @partials[path.split("/").last] += 1 -          @templates[path] += 1 -        else -          @templates[path] += 1          end + +        @templates[path] += 1        end      end @@ -147,17 +147,23 @@ module ActionController        extra_keys = routes.extra_keys(parameters)        non_path_parameters = get? ? query_parameters : request_parameters        parameters.each do |key, value| -        if value.is_a? Fixnum -          value = value.to_s -        elsif value.is_a? Array -          value = Result.new(value.map { |v| v.is_a?(String) ? v.dup : v }) -        elsif value.is_a? String +        if value.is_a?(Array) && (value.frozen? || value.any?(&:frozen?)) +          value = value.map{ |v| v.duplicable? ? v.dup : v } +        elsif value.is_a?(Hash) && (value.frozen? || value.any?{ |k,v| v.frozen? }) +          value = Hash[value.map{ |k,v| [k, v.duplicable? ? v.dup : v] }] +        elsif value.frozen? && value.duplicable?            value = value.dup          end          if extra_keys.include?(key.to_sym)            non_path_parameters[key] = value          else +          if value.is_a?(Array) +            value = Result.new(value.map(&:to_param)) +          else +            value = value.to_param +          end +            path_parameters[key.to_s] = value          end        end @@ -453,7 +459,7 @@ module ActionController          # Ensure that numbers and symbols passed as params are converted to          # proper params, as is the case when engaging rack. -        parameters = paramify_values(parameters) +        parameters = paramify_values(parameters) if html_format?(parameters)          @request.recycle!          @response.recycle! @@ -466,14 +472,13 @@ module ActionController          parameters ||= {}          controller_class_name = @controller.class.anonymous? ? -          "anonymous_controller" : +          "anonymous" :            @controller.class.name.underscore.sub(/_controller$/, '')          @request.assign_parameters(@routes, controller_class_name, action.to_s, parameters) -        @request.session = ActionController::TestSession.new(session) if session +        @request.session.update(session) if session          @request.session["flash"] = @request.flash.update(flash || {}) -        @request.session["flash"].sweep          @controller.request = @request          build_request_uri(action, parameters) @@ -546,6 +551,12 @@ module ActionController            @request.env["QUERY_STRING"] = query_string || ""          end        end + +      def html_format?(parameters) +        return true unless parameters.is_a?(Hash) +        format = Mime[parameters[:format]] +        format.nil? || format.html? +      end      end      # When the request.remote_addr remains the default for testing, which is 0.0.0.0, the exception is simply raised inline diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb index e9b50ff8ce..114b0e73c9 100644 --- a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +++ b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb @@ -99,7 +99,7 @@ module HTML      self.allowed_protocols      = Set.new(%w(ed2k ftp http https irc mailto news gopher nntp telnet webcal xmpp callto        feed svn urn aim rsync tag ssh sftp rtsp afs)) -    # Specifies the default Set of acceptable css keywords that #sanitize and #sanitize_css will accept. +    # Specifies the default Set of acceptable css properties that #sanitize and #sanitize_css will accept.      self.allowed_css_properties = Set.new(%w(azimuth background-color border-bottom-color border-collapse        border-color border-left-color border-right-color border-top-color clear color cursor direction display        elevation float font font-family font-size font-style font-variant font-weight height letter-spacing line-height diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index 5c48a60469..e31f3b823d 100644 --- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb +++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/module/attribute_accessors' +  module ActionDispatch    module Http      module MimeNegotiation diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index 078229efd2..cc46f9983c 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -29,7 +29,7 @@ module ActionDispatch # :nodoc:    #  class DemoControllerTest < ActionDispatch::IntegrationTest    #    def test_print_root_path_to_console    #      get('/') -  #      puts @response.body +  #      puts response.body    #    end    #  end    class Response diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb index f9dae5dad7..4266ec042e 100644 --- a/actionpack/lib/action_dispatch/http/url.rb +++ b/actionpack/lib/action_dispatch/http/url.rb @@ -23,23 +23,6 @@ module ActionDispatch          end          def url_for(options = {}) -          if options[:host].blank? && options[:only_path].blank? -            raise ArgumentError, 'Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true' -          end - -          rewritten_url = "" - -          unless options[:only_path] -            unless options[:protocol] == false -              rewritten_url << (options[:protocol] || "http") -              rewritten_url << ":" unless rewritten_url.match(%r{:|//}) -            end -            rewritten_url << "//" unless rewritten_url.match("//") -            rewritten_url << rewrite_authentication(options) -            rewritten_url << host_or_subdomain_and_domain(options) -            rewritten_url << ":#{options.delete(:port)}" if options[:port] -          end -            path = ""            path << options.delete(:script_name).to_s.chomp("/")            path << options.delete(:path).to_s @@ -47,14 +30,36 @@ module ActionDispatch            params = options[:params] || {}            params.reject! {|k,v| v.to_param.nil? } -          rewritten_url << (options[:trailing_slash] ? path.sub(/\?|\z/) { "/" + $& } : path) -          rewritten_url << "?#{params.to_query}" unless params.empty? -          rewritten_url << "##{Journey::Router::Utils.escape_fragment(options[:anchor].to_param.to_s)}" if options[:anchor] -          rewritten_url +          result = build_host_url(options) + +          result << (options[:trailing_slash] ? path.sub(/\?|\z/) { "/" + $& } : path) +          result << "?#{params.to_query}" unless params.empty? +          result << "##{Journey::Router::Utils.escape_fragment(options[:anchor].to_param.to_s)}" if options[:anchor] +          result          end          private +        def build_host_url(options) +          if options[:host].blank? && options[:only_path].blank? +            raise ArgumentError, 'Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true' +          end + +          result = "" + +          unless options[:only_path] +            unless options[:protocol] == false +              result << (options[:protocol] || "http") +              result << ":" unless result.match(%r{:|//}) +            end +            result << "//" unless result.match("//") +            result << rewrite_authentication(options) +            result << host_or_subdomain_and_domain(options) +            result << ":#{options.delete(:port)}" if options[:port] +          end +          result +        end +          def named_host?(host)            host && IP_HOST_REGEXP !~ host          end diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb index 0c717c8503..e1016977ab 100644 --- a/actionpack/lib/action_dispatch/middleware/cookies.rb +++ b/actionpack/lib/action_dispatch/middleware/cookies.rb @@ -339,7 +339,6 @@ module ActionDispatch      end      def call(env) -      cookie_jar = nil        status, headers, body = @app.call(env)        if cookie_jar = env['action_dispatch.cookies'] diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb index cff0877030..54f2669f43 100644 --- a/actionpack/lib/action_dispatch/middleware/flash.rb +++ b/actionpack/lib/action_dispatch/middleware/flash.rb @@ -4,7 +4,7 @@ module ActionDispatch      # read a notice you put there or <tt>flash["notice"] = "hello"</tt>      # to put a new one.      def flash -      @env[Flash::KEY] ||= (session["flash"] || Flash::FlashHash.new) +      @env[Flash::KEY] ||= (session["flash"] || Flash::FlashHash.new).tap(&:sweep)      end    end @@ -17,7 +17,7 @@ module ActionDispatch    #     def create    #       # save post    #       flash[:notice] = "Post successfully created" -  #       redirect_to posts_path(@post) +  #       redirect_to @post    #     end    #    #     def show @@ -217,10 +217,6 @@ module ActionDispatch      end      def call(env) -      if (session = env['rack.session']) && (flash = session['flash']) -        flash.sweep -      end -        @app.call(env)      ensure        session    = env['rack.session'] || {} @@ -237,7 +233,8 @@ module ActionDispatch          env[KEY] = new_hash        end -      if session.key?('flash') && session['flash'].empty? +      if (!session.respond_to?(:loaded?) || session.loaded?) && # (reset_session uses {}, which doesn't implement #loaded?) +         session.key?('flash') && session['flash'].empty?          session.delete('flash')        end      end diff --git a/actionpack/lib/action_dispatch/middleware/remote_ip.rb b/actionpack/lib/action_dispatch/middleware/remote_ip.rb index d924f21fad..ec15a2a715 100644 --- a/actionpack/lib/action_dispatch/middleware/remote_ip.rb +++ b/actionpack/lib/action_dispatch/middleware/remote_ip.rb @@ -5,11 +5,14 @@ module ActionDispatch      # IP addresses that are "trusted proxies" that can be stripped from      # the comma-delimited list in the X-Forwarded-For header. See also:      # http://en.wikipedia.org/wiki/Private_network#Private_IPv4_address_spaces +    # http://en.wikipedia.org/wiki/Private_network#Private_IPv6_addresses.      TRUSTED_PROXIES = %r{        ^127\.0\.0\.1$                | # localhost +      ^::1$                         |        ^(10                          | # private IP 10.x.x.x          172\.(1[6-9]|2[0-9]|3[0-1]) | # private IP in the range 172.16.0.0 .. 172.31.255.255 -        192\.168                      # private IP 192.168.x.x +        192\.168                    | # private IP 192.168.x.x +        fc00::                        # private IP fc00         )\.      }x @@ -19,13 +22,13 @@ module ActionDispatch        @app = app        @check_ip = check_ip_spoofing        @proxies = case custom_proxies -      when Regexp -        custom_proxies -      when nil -        TRUSTED_PROXIES -      else -        Regexp.union(TRUSTED_PROXIES, custom_proxies) -      end +        when Regexp +          custom_proxies +        when nil +          TRUSTED_PROXIES +        else +          Regexp.union(TRUSTED_PROXIES, custom_proxies) +        end      end      def call(env) @@ -34,6 +37,31 @@ module ActionDispatch      end      class GetIp + +      # IP v4 and v6 (with compression) validation regexp +      # https://gist.github.com/1289635 +      VALID_IP = %r{ +        (^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9]{1,2})){3}$)                                                        | # ip v4 +        (^( +        (([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})                                                                                                                   | # ip v6 not abbreviated +        (([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})                                                                                                                  | # ip v6 with double colon in the end +        (([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})                                                                                              | # - ip addresses v6 +        (([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})                                                                                          | # - with +        (([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})                                                                                          | # - double colon +        (([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})                                                                                          | # - in the middle +        (([0-9A-Fa-f]{1,4}:){6} ((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3} (\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))                            | # ip v6 with compatible to v4 +        (([0-9A-Fa-f]{1,4}:){1,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))                           | # ip v6 with compatible to v4 +        (([0-9A-Fa-f]{1,4}:){1}:([0-9A-Fa-f]{1,4}:){0,4}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))     | # ip v6 with compatible to v4 +        (([0-9A-Fa-f]{1,4}:){0,2}:([0-9A-Fa-f]{1,4}:){0,3}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))   | # ip v6 with compatible to v4 +        (([0-9A-Fa-f]{1,4}:){0,3}:([0-9A-Fa-f]{1,4}:){0,2}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))   | # ip v6 with compatible to v4 +        (([0-9A-Fa-f]{1,4}:){0,4}:([0-9A-Fa-f]{1,4}:){1}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))     | # ip v6 with compatible to v4 +        (::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d) |(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))                         | # ip v6 with compatible to v4 +        ([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})                                                                                               | # ip v6 with compatible to v4 +        (::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})                                                                                                               | # ip v6 with double colon at the begining +        (([0-9A-Fa-f]{1,4}:){1,7}:)                                                                                                                                  # ip v6 without ending +        )$) +      }x +        def initialize(env, middleware)          @env           = env          @middleware    = middleware @@ -44,25 +72,31 @@ module ActionDispatch        # but will be wrong if the user is behind a proxy. Proxies will set        # HTTP_CLIENT_IP and/or HTTP_X_FORWARDED_FOR, so we prioritize those.        # HTTP_X_FORWARDED_FOR may be a comma-delimited list in the case of -      # multiple chained proxies. The last address which is not a known proxy -      # will be the originating IP. +      # multiple chained proxies. The first address which is in this list +      # if it's not a known proxy will be the originating IP. +      # Format of HTTP_X_FORWARDED_FOR: +      # client_ip, proxy_ip1, proxy_ip2... +      # http://en.wikipedia.org/wiki/X-Forwarded-For        def calculate_ip -        client_ip     = @env['HTTP_CLIENT_IP'] -        forwarded_ips = ips_from('HTTP_X_FORWARDED_FOR') -        remote_addrs  = ips_from('REMOTE_ADDR') +        client_ip    = @env['HTTP_CLIENT_IP'] +        forwarded_ip = ips_from('HTTP_X_FORWARDED_FOR').first +        remote_addrs = ips_from('REMOTE_ADDR')          check_ip = client_ip && @middleware.check_ip -        if check_ip && !forwarded_ips.include?(client_ip) +        if check_ip && forwarded_ip != client_ip            # We don't know which came from the proxy, and which from the user            raise IpSpoofAttackError, "IP spoofing attack?!" \              "HTTP_CLIENT_IP=#{@env['HTTP_CLIENT_IP'].inspect}" \              "HTTP_X_FORWARDED_FOR=#{@env['HTTP_X_FORWARDED_FOR'].inspect}"          end -        not_proxy = client_ip || forwarded_ips.first || remote_addrs.first - -        # Return first REMOTE_ADDR if there are no other options -        not_proxy || ips_from('REMOTE_ADDR', :allow_proxies).first +        client_ips = remove_proxies [client_ip, forwarded_ip, remote_addrs].flatten +        if client_ips.present? +          client_ips.first +        else +          # If there is no client ip we can return first valid proxy ip from REMOTE_ADDR +          remote_addrs.find { |ip| valid_ip? ip } +        end        end        def to_s @@ -71,12 +105,24 @@ module ActionDispatch          @ip = calculate_ip        end -    protected +      private -      def ips_from(header, allow_proxies = false) -        ips = @env[header] ? @env[header].strip.split(/[,\s]+/) : [] -        allow_proxies ? ips : ips.reject{|ip| ip =~ @middleware.proxies } +      def ips_from(header) +        @env[header] ? @env[header].strip.split(/[,\s]+/) : []        end + +      def valid_ip?(ip) +        ip =~ VALID_IP +      end + +      def not_a_proxy?(ip) +        ip !~ @middleware.proxies +      end + +      def remove_proxies(ips) +        ips.select { |ip| valid_ip?(ip) && not_a_proxy?(ip) } +      end +      end    end diff --git a/actionpack/lib/action_dispatch/middleware/stack.rb b/actionpack/lib/action_dispatch/middleware/stack.rb index 28e8fbdab8..12bc438be3 100644 --- a/actionpack/lib/action_dispatch/middleware/stack.rb +++ b/actionpack/lib/action_dispatch/middleware/stack.rb @@ -110,7 +110,7 @@ module ActionDispatch      def build(app = nil, &block)        app ||= block        raise "MiddlewareStack#build requires an app" unless app -      middlewares.reverse.inject(app) { |a, e| e.build(a) } +      middlewares.freeze.reverse.inject(app) { |a, e| e.build(a) }      end    protected diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index ba4cfb482d..1a1a054985 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -1,4 +1,5 @@  require 'active_support/core_ext/hash/except' +require 'active_support/core_ext/hash/reverse_merge'  require 'active_support/core_ext/object/blank'  require 'active_support/core_ext/enumerable'  require 'active_support/inflector' @@ -58,6 +59,16 @@ module ActionDispatch            @options = (@scope[:options] || {}).merge(options)            @path = normalize_path(path)            normalize_options! + +          via_all = @options.delete(:via) if @options[:via] == :all + +          if !via_all && request_method_condition.empty? +            msg = "You should not use the `match` method in your router without specifying an HTTP method.\n" \ +                  "If you want to expose your action to GET, use `get` in the router:\n\n" \ +                  "  Instead of: match \"controller#action\"\n" \ +                  "  Do: get \"controller#action\"" +            raise msg +          end          end          def to_route @@ -263,7 +274,7 @@ module ActionDispatch          # of most Rails applications, this is beneficial.          def root(options = {})            options = { :to => options } if options.is_a?(String) -          match '/', { :as => :root }.merge(options) +          match '/', { :as => :root, :via => :get }.merge(options)          end          # Matches a url pattern to one or more routes. Any symbols in a pattern @@ -416,7 +427,7 @@ module ActionDispatch            options[:as] ||= app_name(app) -          match(path, options.merge(:to => app, :anchor => false, :format => false)) +          match(path, options.merge(:to => app, :anchor => false, :format => false, :via => :all))            define_generate_prefix(app, options[:as])            self @@ -1294,6 +1305,21 @@ module ActionDispatch            parent_resource.instance_of?(Resource) && @scope[:shallow]          end +        def draw(name) +          path = @draw_paths.find do |_path| +            _path.join("#{name}.rb").file? +          end + +          unless path +            msg  = "Your router tried to #draw the external file #{name}.rb,\n" \ +                   "but the file was not found in:\n\n" +            msg += @draw_paths.map { |_path| " * #{_path}" }.join("\n") +            raise msg +          end + +          instance_eval(path.join("#{name}.rb").read) +        end +          # match 'path' => 'controller#action'          # match 'path', to: 'controller#action'          # match 'path', 'otherpath', on: :member, via: :get @@ -1543,6 +1569,7 @@ module ActionDispatch        def initialize(set) #:nodoc:          @set = set +        @draw_paths = set.draw_paths          @scope = { :path_names => @set.resources_path_names }        end diff --git a/actionpack/lib/action_dispatch/routing/redirection.rb b/actionpack/lib/action_dispatch/routing/redirection.rb index 617b24b46a..444a79c50d 100644 --- a/actionpack/lib/action_dispatch/routing/redirection.rb +++ b/actionpack/lib/action_dispatch/routing/redirection.rb @@ -1,4 +1,6 @@  require 'action_dispatch/http/request' +require 'active_support/core_ext/uri' +require 'rack/utils'  module ActionDispatch    module Routing @@ -46,8 +48,17 @@ module ActionDispatch            :params   => request.query_parameters          }.merge options +        if !params.empty? && url_options[:path].match(/%\{\w*\}/) +          url_options[:path] = (url_options[:path] % escape_path(params)) +        end +          ActionDispatch::Http::URL.url_for url_options        end + +      private +        def escape_path(params) +          Hash[params.map{ |k,v| [k, URI.parser.escape(v)] }] +        end      end      module Redirection @@ -67,10 +78,13 @@ module ActionDispatch        # params, depending of how many arguments your block accepts. A string is required as a        # return value.        # -      #   match 'jokes/:number', :to => redirect do |params, request| -      #     path = (params[:number].to_i.even? ? "/wheres-the-beef" : "/i-love-lamp") +      #   match 'jokes/:number', :to => redirect { |params, request| +      #     path = (params[:number].to_i.even? ? "wheres-the-beef" : "i-love-lamp")        #     "http://#{request.host_with_port}/#{path}" -      #   end +      #   } +      # +      # Note that the +do end+ syntax for the redirect block wouldn't work, as Ruby would pass +      # the block to +match+ instead of +redirect+. Use <tt>{ ... }</tt> instead.        #        # The options version of redirect allows you to supply only the parts of the url which need        # to change, it also supports interpolation of the path similar to the first example. @@ -93,13 +107,18 @@ module ActionDispatch          path = args.shift          block = lambda { |params, request| -          (params.empty? || !path.match(/%\{\w*\}/)) ? path : (path % params) +          (params.empty? || !path.match(/%\{\w*\}/)) ? path : (path % escape(params))          } if String === path          block = path if path.respond_to? :call          raise ArgumentError, "redirection argument not supported" unless block          Redirect.new status, block        end + +      private +        def escape(params) +          Hash[params.map{ |k,v| [k, Rack::Utils.escape(v)] }] +        end      end    end  end diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 45075050eb..7a7810a95c 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -96,7 +96,25 @@ module ActionDispatch          def initialize            @routes  = {}            @helpers = [] -          @module  = Module.new +          @module  = Module.new do +            protected + +            def handle_positional_args(args, options, route) +              inner_options = args.extract_options! +              result = options.dup + +              if args.any? +                keys = route.segment_keys +                if args.size < keys.size - 1 # take format into account +                  keys -= self.url_options.keys if self.respond_to?(:url_options) +                  keys -= options.keys +                end +                result.merge!(Hash[keys.zip(args)]) +              end + +              result.merge!(inner_options) +            end +          end          end          def helper_names @@ -135,40 +153,37 @@ module ActionDispatch          end          private -          def url_helper_name(name, kind = :url) -            :"#{name}_#{kind}" +          def url_helper_name(name, only_path) +            if only_path +              :"#{name}_path" +            else +              :"#{name}_url" +            end            end -          def hash_access_name(name, kind = :url) -            :"hash_for_#{name}_#{kind}" +          def hash_access_name(name, only_path) +            if only_path +              :"hash_for_#{name}_path" +            else +              :"hash_for_#{name}_url" +            end            end            def define_named_route_methods(name, route) -            {:url => {:only_path => false}, :path => {:only_path => true}}.each do |kind, opts| -              hash = route.defaults.merge(:use_route => name).merge(opts) -              define_hash_access route, name, kind, hash -              define_url_helper route, name, kind, hash +            [true, false].each do |only_path| +              hash = route.defaults.merge(:use_route => name, :only_path => only_path) +              define_hash_access route, name, hash +              define_url_helper route, name, hash              end            end -          def define_hash_access(route, name, kind, options) -            selector = hash_access_name(name, kind) +          def define_hash_access(route, name, options) +            selector = hash_access_name(name, options[:only_path])              @module.module_eval do -              remove_possible_method selector - -              define_method(selector) do |*args| -                inner_options = args.extract_options! -                result = options.dup - -                if args.any? -                  result[:_positional_args] = args -                  result[:_positional_keys] = route.segment_keys -                end - -                result.merge(inner_options) +              redefine_method(selector) do |*args| +                self.handle_positional_args(args, options, route)                end -                protected selector              end              helpers << selector @@ -187,9 +202,9 @@ module ActionDispatch            #            #   foo_url(bar, baz, bang, :sort_by => 'baz')            # -          def define_url_helper(route, name, kind, options) -            selector = url_helper_name(name, kind) -            hash_access_method = hash_access_name(name, kind) +          def define_url_helper(route, name, options) +            selector = url_helper_name(name, options[:only_path]) +            hash_access_method = hash_access_name(name, options[:only_path])              if optimize_helper?(route)                @module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1 @@ -240,6 +255,7 @@ module ActionDispatch        attr_accessor :formatter, :set, :named_routes, :default_scope, :router        attr_accessor :disable_clear_and_finalize, :resources_path_names        attr_accessor :default_url_options, :request_class, :valid_conditions +      attr_accessor :draw_paths        alias :routes :set @@ -251,6 +267,7 @@ module ActionDispatch          self.named_routes = NamedRouteCollection.new          self.resources_path_names = self.class.default_resources_path_names.dup          self.default_url_options = {} +        self.draw_paths = []          self.request_class = request_class          @valid_conditions = {} @@ -609,8 +626,6 @@ module ActionDispatch        def url_for(options)          options = default_url_options.merge(options || {}) -        handle_positional_args(options) -          user, password = extract_authentication(options)          path_segments  = options.delete(:_path_segments)          script_name    = options.delete(:script_name).presence || _generate_prefix(options) @@ -680,16 +695,6 @@ module ActionDispatch            end          end -        def handle_positional_args(options) -          return unless args = options.delete(:_positional_args) - -          keys = options.delete(:_positional_keys) -          keys -= options.keys if args.size < keys.size - 1 # take format into account - -          # Tell url_for to skip default_url_options -          options.merge!(Hash[args.zip(keys).map { |v, k| [k, v] }]) -        end -      end    end  end diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index d4d09e2ee9..7985683a72 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -442,7 +442,7 @@ module ActionView        #    <video><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video>        #  video_tag(["trailer.ogg", "trailer.flv"]) # =>        #    <video><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video> -      #  video_tag(["trailer.ogg", "trailer.flv"] :size => "160x120") # => +      #  video_tag(["trailer.ogg", "trailer.flv"], :size => "160x120") # =>        #    <video height="120" width="160"><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video>        def video_tag(*sources)          multiple_sources_tag('video', sources) do |options| diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb index dd4e9ae4cc..35f91cec18 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb @@ -1,5 +1,6 @@  require 'thread'  require 'active_support/core_ext/file' +require 'active_support/core_ext/module/attribute_accessors'  module ActionView    module Helpers diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb index 1f237cd013..76ffb0657b 100644 --- a/actionpack/lib/action_view/helpers/date_helper.rb +++ b/actionpack/lib/action_view/helpers/date_helper.rb @@ -19,7 +19,7 @@ module ActionView      #   of \date[month].      module DateHelper        # Reports the approximate distance in time between two Time, Date or DateTime objects or integers as seconds. -      # Set <tt>include_seconds</tt> to true if you want more detailed approximations when distance < 1 min, 29 secs. +      # Pass <tt>:include_seconds => true</tt> if you want more detailed approximations when distance < 1 min, 29 secs.        # Distances are reported based on the following table:        #        #   0 <-> 29 secs                                                             # => less than a minute @@ -36,7 +36,7 @@ module ActionView        #   1 yr, 9 months <-> 2 yr minus 1 sec                                       # => almost 2 years        #   2 yrs <-> max time or date                                                # => (same rules as 1 yr)        # -      # With <tt>include_seconds</tt> = true and the difference < 1 minute 29 seconds: +      # With <tt>:include_seconds => true</tt> and the difference < 1 minute 29 seconds:        #   0-4   secs      # => less than 5 seconds        #   5-9   secs      # => less than 10 seconds        #   10-19 secs      # => less than 20 seconds @@ -46,36 +46,45 @@ module ActionView        #        # ==== Examples        #   from_time = Time.now -      #   distance_of_time_in_words(from_time, from_time + 50.minutes)        # => about 1 hour -      #   distance_of_time_in_words(from_time, 50.minutes.from_now)           # => about 1 hour -      #   distance_of_time_in_words(from_time, from_time + 15.seconds)        # => less than a minute -      #   distance_of_time_in_words(from_time, from_time + 15.seconds, true)  # => less than 20 seconds -      #   distance_of_time_in_words(from_time, 3.years.from_now)              # => about 3 years -      #   distance_of_time_in_words(from_time, from_time + 60.hours)          # => 3 days -      #   distance_of_time_in_words(from_time, from_time + 45.seconds, true)  # => less than a minute -      #   distance_of_time_in_words(from_time, from_time - 45.seconds, true)  # => less than a minute -      #   distance_of_time_in_words(from_time, 76.seconds.from_now)           # => 1 minute -      #   distance_of_time_in_words(from_time, from_time + 1.year + 3.days)   # => about 1 year -      #   distance_of_time_in_words(from_time, from_time + 3.years + 6.months) # => over 3 years +      #   distance_of_time_in_words(from_time, from_time + 50.minutes)                                # => about 1 hour +      #   distance_of_time_in_words(from_time, 50.minutes.from_now)                                   # => about 1 hour +      #   distance_of_time_in_words(from_time, from_time + 15.seconds)                                # => less than a minute +      #   distance_of_time_in_words(from_time, from_time + 15.seconds, :include_seconds => true)      # => less than 20 seconds +      #   distance_of_time_in_words(from_time, 3.years.from_now)                                      # => about 3 years +      #   distance_of_time_in_words(from_time, from_time + 60.hours)                                  # => 3 days +      #   distance_of_time_in_words(from_time, from_time + 45.seconds, :include_seconds => true)      # => less than a minute +      #   distance_of_time_in_words(from_time, from_time - 45.seconds, :include_seconds => true)      # => less than a minute +      #   distance_of_time_in_words(from_time, 76.seconds.from_now)                                   # => 1 minute +      #   distance_of_time_in_words(from_time, from_time + 1.year + 3.days)                           # => about 1 year +      #   distance_of_time_in_words(from_time, from_time + 3.years + 6.months)                        # => over 3 years        #   distance_of_time_in_words(from_time, from_time + 4.years + 9.days + 30.minutes + 5.seconds) # => about 4 years        #        #   to_time = Time.now + 6.years + 19.days -      #   distance_of_time_in_words(from_time, to_time, true)     # => about 6 years -      #   distance_of_time_in_words(to_time, from_time, true)     # => about 6 years -      #   distance_of_time_in_words(Time.now, Time.now)           # => less than a minute -      # -      def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false, options = {}) +      #   distance_of_time_in_words(from_time, to_time, :include_seconds => true)                     # => about 6 years +      #   distance_of_time_in_words(to_time, from_time, :include_seconds => true)                     # => about 6 years +      #   distance_of_time_in_words(Time.now, Time.now)                                               # => less than a minute +      # +      def distance_of_time_in_words(from_time, to_time = 0, include_seconds_or_options = {}, options = {}) +        unless include_seconds_or_options.is_a?(Hash) +          ActiveSupport::Deprecation.warn "distance_of_time_in_words and time_ago_in_words now accept :include_seconds " + +                                          "as a part of options hash, not a boolean argument", caller +          options[:include_seconds] ||= !!include_seconds_or_options +        else +          options = include_seconds_or_options +        end +          from_time = from_time.to_time if from_time.respond_to?(:to_time)          to_time = to_time.to_time if to_time.respond_to?(:to_time) -        distance_in_minutes = (((to_time - from_time).abs)/60).round -        distance_in_seconds = ((to_time - from_time).abs).round +        from_time, to_time = to_time, from_time if from_time > to_time +        distance_in_minutes = ((to_time - from_time)/60.0).round +        distance_in_seconds = (to_time - from_time).round          I18n.with_options :locale => options[:locale], :scope => :'datetime.distance_in_words' do |locale|            case distance_in_minutes              when 0..1                return distance_in_minutes == 0 ?                       locale.t(:less_than_x_minutes, :count => 1) : -                     locale.t(:x_minutes, :count => distance_in_minutes) unless include_seconds +                     locale.t(:x_minutes, :count => distance_in_minutes) unless options[:include_seconds]                case distance_in_seconds                  when 0..4   then locale.t :less_than_x_seconds, :count => 5 @@ -94,18 +103,22 @@ module ActionView              when 43200..86399    then locale.t :about_x_months, :count => 1              when 86400..525599   then locale.t :x_months,       :count => (distance_in_minutes.to_f / 43200.0).round              else -              fyear = from_time.year -              fyear += 1 if from_time.month >= 3 -              tyear = to_time.year -              tyear -= 1 if to_time.month < 3 -              leap_years = (fyear > tyear) ? 0 : (fyear..tyear).count{|x| Date.leap?(x)} -              minute_offset_for_leap_year = leap_years * 1440 -              # Discount the leap year days when calculating year distance. -              # e.g. if there are 20 leap year days between 2 dates having the same day -              # and month then the based on 365 days calculation -              # the distance in years will come out to over 80 years when in written -              # english it would read better as about 80 years. -              minutes_with_offset         = distance_in_minutes - minute_offset_for_leap_year +              if from_time.acts_like?(:time) && to_time.acts_like?(:time) +                fyear = from_time.year +                fyear += 1 if from_time.month >= 3 +                tyear = to_time.year +                tyear -= 1 if to_time.month < 3 +                leap_years = (fyear > tyear) ? 0 : (fyear..tyear).count{|x| Date.leap?(x)} +                minute_offset_for_leap_year = leap_years * 1440 +                # Discount the leap year days when calculating year distance. +                # e.g. if there are 20 leap year days between 2 dates having the same day +                # and month then the based on 365 days calculation +                # the distance in years will come out to over 80 years when in written +                # english it would read better as about 80 years. +                minutes_with_offset = distance_in_minutes - minute_offset_for_leap_year +              else +                minutes_with_offset = distance_in_minutes +              end                remainder                   = (minutes_with_offset % 525600)                distance_in_years           = (minutes_with_offset / 525600)                if remainder < 131400 @@ -122,15 +135,16 @@ module ActionView        # Like <tt>distance_of_time_in_words</tt>, but where <tt>to_time</tt> is fixed to <tt>Time.now</tt>.        #        # ==== Examples -      #   time_ago_in_words(3.minutes.from_now)       # => 3 minutes -      #   time_ago_in_words(Time.now - 15.hours)      # => about 15 hours -      #   time_ago_in_words(Time.now)                 # => less than a minute +      #   time_ago_in_words(3.minutes.from_now)                 # => 3 minutes +      #   time_ago_in_words(Time.now - 15.hours)                # => about 15 hours +      #   time_ago_in_words(Time.now)                           # => less than a minute +      #   time_ago_in_words(Time.now, :include_seconds => true) # => less than 5 seconds        #        #   from_time = Time.now - 3.days - 14.minutes - 25.seconds        #   time_ago_in_words(from_time)      # => 3 days        # -      def time_ago_in_words(from_time, include_seconds = false) -        distance_of_time_in_words(from_time, Time.now, include_seconds) +      def time_ago_in_words(from_time, include_seconds_or_options = {}) +        distance_of_time_in_words(from_time, Time.now, include_seconds_or_options)        end        alias_method :distance_of_time_in_words_to_now, :time_ago_in_words diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 3f5829d86a..67f2abe509 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -10,6 +10,7 @@ require 'active_support/core_ext/object/blank'  require 'active_support/core_ext/string/output_safety'  require 'active_support/core_ext/array/extract_options'  require 'active_support/deprecation' +require 'active_support/core_ext/string/inflections'  module ActionView    # = Action View Form Helpers @@ -184,7 +185,7 @@ module ActionView        #     First name: <%= f.text_field :first_name %>        #     Last name : <%= f.text_field :last_name %>        #     Biography : <%= text_area :person, :biography %> -      #     Admin?    : <%= check_box_tag "person[admin]", @person.company.admin? %> +      #     Admin?    : <%= check_box_tag "person[admin]", "1", @person.company.admin? %>        #     <%= f.submit %>        #   <% end %>        # @@ -902,7 +903,7 @@ module ActionView        #   # Let's say that @post.validated? is 1:        #   check_box("post", "validated")        #   # => <input name="post[validated]" type="hidden" value="0" /> -      #   #    <input type="checkbox" id="post_validated" name="post[validated]" value="1" /> +      #   #    <input checked="checked" type="checkbox" id="post_validated" name="post[validated]" value="1" />        #        #   # Let's say that @puppy.gooddog is "no":        #   check_box("puppy", "gooddog", {}, "yes", "no") @@ -1039,9 +1040,14 @@ module ActionView              object_name = ActiveModel::Naming.param_key(object)            end -          builder = options[:builder] || ActionView::Base.default_form_builder +          builder = options[:builder] || default_form_builder            builder.new(object_name, object, self, options)          end + +        def default_form_builder +          builder = ActionView::Base.default_form_builder +          builder.respond_to?(:constantize) ? builder.constantize : builder +        end      end      class FormBuilder diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb index 5a869d6303..cc20518b93 100644 --- a/actionpack/lib/action_view/helpers/javascript_helper.rb +++ b/actionpack/lib/action_view/helpers/javascript_helper.rb @@ -15,7 +15,6 @@ module ActionView        JS_ESCAPE_MAP["\342\200\250".force_encoding('UTF-8').encode!] = '
'        JS_ESCAPE_MAP["\342\200\251".force_encoding('UTF-8').encode!] = '
' -              # Escapes carriage returns and single and double quotes for JavaScript segments.        # @@ -68,40 +67,6 @@ module ActionView        def javascript_cdata_section(content) #:nodoc:          "\n//#{cdata_section("\n#{content}\n//")}\n".html_safe        end - -      # Returns a button whose +onclick+ handler triggers the passed JavaScript. -      # -      # The helper receives a name, JavaScript code, and an optional hash of HTML options. The -      # name is used as button label and the JavaScript code goes into its +onclick+ attribute. -      # If +html_options+ has an <tt>:onclick</tt>, that one is put before +function+. -      # -      #   button_to_function "Greeting", "alert('Hello world!')", :class => "ok" -      #   # => <input class="ok" onclick="alert('Hello world!');" type="button" value="Greeting" /> -      # -      def button_to_function(name, function=nil, html_options={}) -        onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function};" - -        tag(:input, html_options.merge(:type => 'button', :value => name, :onclick => onclick)) -      end - -      # Returns a link whose +onclick+ handler triggers the passed JavaScript. -      # -      # The helper receives a name, JavaScript code, and an optional hash of HTML options. The -      # name is used as the link text and the JavaScript code goes into the +onclick+ attribute. -      # If +html_options+ has an <tt>:onclick</tt>, that one is put before +function+. Once all -      # the JavaScript is set, the helper appends "; return false;". -      # -      # The +href+ attribute of the tag is set to "#" unless +html_options+ has one. -      # -      #   link_to_function "Greeting", "alert('Hello world!')", :class => "nav_link" -      #   # => <a class="nav_link" href="#" onclick="alert('Hello world!'); return false;">Greeting</a> -      # -      def link_to_function(name, function, html_options={}) -        onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function}; return false;" -        href = html_options[:href] || '#' - -        content_tag(:a, name, html_options.merge(:href => href, :onclick => onclick)) -      end      end    end  end diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb index d3a7a1bb96..2011351bd2 100644 --- a/actionpack/lib/action_view/helpers/number_helper.rb +++ b/actionpack/lib/action_view/helpers/number_helper.rb @@ -233,7 +233,7 @@ module ActionView          parts = number.to_s.to_str.split('.')          parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}") -        parts.join(options[:separator]).html_safe +        safe_join(parts, options[:separator])        end        # Formats a +number+ with the specified level of <tt>:precision</tt> (e.g., 112.32 has a precision @@ -392,10 +392,10 @@ module ActionView        #   * *integers*: <tt>:unit</tt>, <tt>:ten</tt>, <tt>:hundred</tt>, <tt>:thousand</tt>,  <tt>:million</tt>,  <tt>:billion</tt>, <tt>:trillion</tt>, <tt>:quadrillion</tt>        #   * *fractionals*: <tt>:deci</tt>, <tt>:centi</tt>, <tt>:mili</tt>, <tt>:micro</tt>, <tt>:nano</tt>, <tt>:pico</tt>, <tt>:femto</tt>        # * <tt>:format</tt> - Sets the format of the output string (defaults to "%n %u"). The field types are: -      # * <tt>:raise</tt>         - If true, raises +InvalidNumberError+ when the argument is invalid. -      #        #     %u  The quantifier (ex.: 'thousand')        #     %n  The number +      # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when the argument is invalid. +      #        #        # ==== Examples        #  number_to_human(123)                                          # => "123" diff --git a/actionpack/lib/action_view/helpers/record_tag_helper.rb b/actionpack/lib/action_view/helpers/record_tag_helper.rb index 1a15459406..9b35f076e5 100644 --- a/actionpack/lib/action_view/helpers/record_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/record_tag_helper.rb @@ -94,10 +94,10 @@ module ActionView          # for each record.          def content_tag_for_single_record(tag_name, record, prefix, options, &block)            options = options ? options.dup : {} -          options.merge!(:class => "#{dom_class(record, prefix)} #{options[:class]}".rstrip, :id => dom_id(record, prefix)) +          options[:class] = "#{dom_class(record, prefix)} #{options[:class]}".rstrip +          options[:id]    = dom_id(record, prefix) -          content = block.arity == 0 ? capture(&block) : capture(record, &block) -          content_tag(tag_name, content, options) +          content_tag(tag_name, capture(record, &block), options)          end      end    end diff --git a/actionpack/lib/action_view/helpers/tags/check_box.rb b/actionpack/lib/action_view/helpers/tags/check_box.rb index 1a4aebb936..9d17a1dde3 100644 --- a/actionpack/lib/action_view/helpers/tags/check_box.rb +++ b/actionpack/lib/action_view/helpers/tags/check_box.rb @@ -41,17 +41,15 @@ module ActionView          def checked?(value)            case value            when TrueClass, FalseClass -            value +            value == !!@checked_value            when NilClass              false -          when Integer -            value != 0            when String              value == @checked_value            when Array              value.include?(@checked_value)            else -            value.to_i != 0 +            value.to_i == @checked_value.to_i            end          end diff --git a/actionpack/lib/action_view/helpers/translation_helper.rb b/actionpack/lib/action_view/helpers/translation_helper.rb index cc74eff53a..fd06bfa2a8 100644 --- a/actionpack/lib/action_view/helpers/translation_helper.rb +++ b/actionpack/lib/action_view/helpers/translation_helper.rb @@ -45,6 +45,7 @@ module ActionView        # you know what kind of output to expect when you call translate in a template.        def translate(key, options = {})          options.merge!(:rescue_format => :html) unless options.key?(:rescue_format) +        options[:default] = wrap_translate_defaults(options[:default]) if options[:default]          if html_safe_translation_key?(key)            html_safe_options = options.dup            options.except(*I18n::RESERVED_KEYS).each do |name, value| @@ -83,6 +84,21 @@ module ActionView          def html_safe_translation_key?(key)            key.to_s =~ /(\b|_|\.)html$/          end + +        def wrap_translate_defaults(defaults) +          new_defaults = [] +          defaults     = Array(defaults) +          while key = defaults.shift +            if key.is_a?(Symbol) +              new_defaults << lambda { |_, options| translate key, options.merge(:default => defaults) } +              break +            else +              new_defautls << key +            end +          end + +          new_defaults +        end      end    end  end diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb index 8b53867aea..c5d5540510 100644 --- a/actionpack/lib/action_view/renderer/partial_renderer.rb +++ b/actionpack/lib/action_view/renderer/partial_renderer.rb @@ -158,8 +158,8 @@ module ActionView    #     Name: <%= user.name %>    #   </div>    # -  # If a collection is given, the layout will be rendered once for each item in the collection. Just think -  # these two snippets have the same output: +  # If a collection is given, the layout will be rendered once for each item in +  # the collection. Just think these two snippets have the same output:    #    #   <%# app/views/users/_user.html.erb %>    #   Name: <%= user.name %> @@ -184,7 +184,7 @@ module ActionView    #     <%= render :partial => "user", :layout => "li_layout", :collection => users %>    #   </ul>    # -  #   Given two users whose names are Alice and Bob, these snippets return: +  # Given two users whose names are Alice and Bob, these snippets return:    #    #   <ul>    #     <li> @@ -195,6 +195,10 @@ module ActionView    #     </li>    #   </ul>    # +  # The current object being rendered, as well as the object_counter, will be +  # available as local variables inside the layout template under the same names +  # as available in the partial. +  #    # You can also apply a layout to a block within any template:    #    #   <%# app/views/users/_chief.html.erb &> @@ -282,14 +286,7 @@ module ActionView          spacer = find_template(@options[:spacer_template]).render(@view, @locals)        end -      if layout = @options[:layout] -        layout = find_template(layout) -      end -        result = @template ? collection_with_template : collection_without_template -       -      result.map!{|content| layout.render(@view, @locals) { content } } if layout -              result.join(spacer).html_safe      end @@ -298,7 +295,7 @@ module ActionView        object, as = @object, @variable        if !block && (layout = @options[:layout]) -        layout = find_template(layout) +        layout = find_template(layout, @locals.keys + [@variable])        end        object ||= locals[as] @@ -384,17 +381,23 @@ module ActionView        segments, locals, template = [], @locals, @template        as, counter = @variable, @variable_counter +      if layout = @options[:layout] +        layout = find_template(layout, @locals.keys + [@variable, @variable_counter]) +      end +        locals[counter] = -1        @collection.each do |object|          locals[counter] += 1          locals[as] = object -        segments << template.render(@view, locals) + +        content = template.render(@view, locals) +        content = layout.render(@view, locals) { content } if layout +        segments << content        end -       +        segments      end -          def collection_without_template        segments, locals, collection_data = [], @locals, @collection_data @@ -451,7 +454,7 @@ module ActionView      end      def retrieve_variable(path) -      variable = @options[:as].try(:to_sym) || path[%r'_?(\w+)(\.\w+)*$', 1].to_sym +      variable = @options.fetch(:as) { path[%r'_?(\w+)(\.\w+)*$', 1] }.try(:to_sym)        variable_counter = :"#{variable}_counter" if @collection        [variable, variable_counter]      end diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index b1a5356ddd..22ba047328 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -125,11 +125,11 @@ module ActiveSupport      # have been loaded.      setup_once do        SharedTestRoutes.draw do -        match ':controller(/:action)' +        get ':controller(/:action)'        end        ActionDispatch::IntegrationTest.app.routes.draw do -        match ':controller(/:action)' +        get ':controller(/:action)'        end      end    end diff --git a/actionpack/test/activerecord/active_record_store_test.rb b/actionpack/test/activerecord/active_record_store_test.rb index 2fe7959f5a..fceebe1858 100644 --- a/actionpack/test/activerecord/active_record_store_test.rb +++ b/actionpack/test/activerecord/active_record_store_test.rb @@ -259,7 +259,7 @@ class ActiveRecordStoreTest < ActionDispatch::IntegrationTest      def with_test_route_set(options = {})        with_routing do |set|          set.draw do -          match ':action', :to => 'active_record_store_test/test' +          get ':action', :to => 'active_record_store_test/test'          end          @app = self.class.build_app(set) do |middleware| diff --git a/actionpack/test/activerecord/render_partial_with_record_identification_test.rb b/actionpack/test/activerecord/render_partial_with_record_identification_test.rb index 8187eb72d5..409370104d 100644 --- a/actionpack/test/activerecord/render_partial_with_record_identification_test.rb +++ b/actionpack/test/activerecord/render_partial_with_record_identification_test.rb @@ -16,7 +16,7 @@ class RenderPartialWithRecordIdentificationController < ActionController::Base    end    def render_with_has_many_through_association -    @developer = Developer.find(:first) +    @developer = Developer.first      render :partial => @developer.topics    end @@ -31,7 +31,7 @@ class RenderPartialWithRecordIdentificationController < ActionController::Base    end    def render_with_record -    @developer = Developer.find(:first) +    @developer = Developer.first      render :partial => @developer    end diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb index 01cafe1aca..b121ca9481 100644 --- a/actionpack/test/controller/action_pack_assertions_test.rb +++ b/actionpack/test/controller/action_pack_assertions_test.rb @@ -162,7 +162,7 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase    def test_string_constraint      with_routing do |set|        set.draw do -        match "photos", :to => 'action_pack_assertions#nothing', :constraints => {:subdomain => "admin"} +        get "photos", :to => 'action_pack_assertions#nothing', :constraints => {:subdomain => "admin"}        end      end    end @@ -170,9 +170,9 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase    def test_assert_redirect_to_named_route_failure      with_routing do |set|        set.draw do -        match 'route_one', :to => 'action_pack_assertions#nothing', :as => :route_one -        match 'route_two', :to => 'action_pack_assertions#nothing', :id => 'two', :as => :route_two -        match ':controller/:action' +        get 'route_one', :to => 'action_pack_assertions#nothing', :as => :route_one +        get 'route_two', :to => 'action_pack_assertions#nothing', :id => 'two', :as => :route_two +        get ':controller/:action'        end        process :redirect_to_named_route        assert_raise(ActiveSupport::TestCase::Assertion) do @@ -192,8 +192,8 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase      with_routing do |set|        set.draw do -        match 'admin/inner_module', :to => 'admin/inner_module#index', :as => :admin_inner_module -        match ':controller/:action' +        get 'admin/inner_module', :to => 'admin/inner_module#index', :as => :admin_inner_module +        get ':controller/:action'        end        process :redirect_to_index        # redirection is <{"action"=>"index", "controller"=>"admin/admin/inner_module"}> @@ -206,8 +206,8 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase      with_routing do |set|        set.draw do -        match '/action_pack_assertions/:id', :to => 'action_pack_assertions#index', :as => :top_level -        match ':controller/:action' +        get '/action_pack_assertions/:id', :to => 'action_pack_assertions#index', :as => :top_level +        get ':controller/:action'        end        process :redirect_to_top_level_named_route        # assert_redirected_to "http://test.host/action_pack_assertions/foo" would pass because of exact match early return @@ -221,8 +221,8 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase      with_routing do |set|        set.draw do          # this controller exists in the admin namespace as well which is the only difference from previous test -        match '/user/:id', :to => 'user#index', :as => :top_level -        match ':controller/:action' +        get '/user/:id', :to => 'user#index', :as => :top_level +        get ':controller/:action'        end        process :redirect_to_top_level_named_route        # assert_redirected_to top_level_url('foo') would pass because of exact match early return diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb index 2032aca52e..b9513ccff4 100644 --- a/actionpack/test/controller/base_test.rb +++ b/actionpack/test/controller/base_test.rb @@ -158,7 +158,7 @@ class UrlOptionsTest < ActionController::TestCase    def test_url_for_query_params_included      rs = ActionDispatch::Routing::RouteSet.new      rs.draw do -      match 'home' => 'pages#home' +      get 'home' => 'pages#home'      end      options = { @@ -174,8 +174,8 @@ class UrlOptionsTest < ActionController::TestCase    def test_url_options_override      with_routing do |set|        set.draw do -        match 'from_view', :to => 'url_options#from_view', :as => :from_view -        match ':controller/:action' +        get 'from_view', :to => 'url_options#from_view', :as => :from_view +        get ':controller/:action'        end        get :from_view, :route => "from_view_url" @@ -189,7 +189,7 @@ class UrlOptionsTest < ActionController::TestCase    def test_url_helpers_does_not_become_actions      with_routing do |set|        set.draw do -        match "account/overview" +        get "account/overview"        end        assert !@controller.class.action_methods.include?("account_overview_path") @@ -208,8 +208,8 @@ class DefaultUrlOptionsTest < ActionController::TestCase    def test_default_url_options_override      with_routing do |set|        set.draw do -        match 'from_view', :to => 'default_url_options#from_view', :as => :from_view -        match ':controller/:action' +        get 'from_view', :to => 'default_url_options#from_view', :as => :from_view +        get ':controller/:action'        end        get :from_view, :route => "from_view_url" @@ -226,7 +226,7 @@ class DefaultUrlOptionsTest < ActionController::TestCase          scope("/:locale") do            resources :descriptions          end -        match ':controller/:action' +        get ':controller/:action'        end        get :from_view, :route => "description_path(1)" diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index a42c68a628..e8546cb154 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -102,8 +102,8 @@ class PageCachingTest < ActionController::TestCase    def test_page_caching_resources_saves_to_correct_path_with_extension_even_if_default_route      with_routing do |set|        set.draw do -        match 'posts.:format', :to => 'posts#index', :as => :formatted_posts -        match '/', :to => 'posts#index', :as => :main +        get 'posts.:format', :to => 'posts#index', :as => :formatted_posts +        get '/', :to => 'posts#index', :as => :main        end        @params[:format] = 'rss'        assert_equal '/posts.rss', @routes.url_for(@params) @@ -560,7 +560,7 @@ class ActionCacheTest < ActionController::TestCase    def test_xml_version_of_resource_is_treated_as_different_cache      with_routing do |set|        set.draw do -        match ':controller(/:action(.:format))' +        get ':controller(/:action(.:format))'        end        get :index, :format => 'xml' diff --git a/actionpack/test/controller/flash_test.rb b/actionpack/test/controller/flash_test.rb index 37ccc7a4a5..e4b34125ad 100644 --- a/actionpack/test/controller/flash_test.rb +++ b/actionpack/test/controller/flash_test.rb @@ -277,7 +277,7 @@ class FlashIntegrationTest < ActionDispatch::IntegrationTest      def with_test_route_set        with_routing do |set|          set.draw do -          match ':action', :to => FlashIntegrationTest::TestController +          get ':action', :to => FlashIntegrationTest::TestController          end          @app = self.class.build_app(set) do |middleware| diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index 44f033119d..877b91b563 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -466,7 +466,7 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest          end          set.draw do -          match ':action', :to => controller +          match ':action', :to => controller, :via => [:get, :post]            get 'get/:action', :to => controller          end @@ -530,10 +530,10 @@ class ApplicationIntegrationTest < ActionDispatch::IntegrationTest    end    routes.draw do -    match '',    :to => 'application_integration_test/test#index', :as => :empty_string +    get '',    :to => 'application_integration_test/test#index', :as => :empty_string -    match 'foo', :to => 'application_integration_test/test#index', :as => :foo -    match 'bar', :to => 'application_integration_test/test#index', :as => :bar +    get 'foo', :to => 'application_integration_test/test#index', :as => :foo +    get 'bar', :to => 'application_integration_test/test#index', :as => :bar    end    def app diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb index 0e4099ddc6..ac056319fc 100644 --- a/actionpack/test/controller/mime_responds_test.rb +++ b/actionpack/test/controller/mime_responds_test.rb @@ -1118,7 +1118,7 @@ class RespondWithControllerTest < ActionController::TestCase            resources :quiz_stores do              resources :customers            end -          match ":controller/:action" +          get ":controller/:action"          end          yield        end diff --git a/actionpack/test/controller/new_base/content_type_test.rb b/actionpack/test/controller/new_base/content_type_test.rb index 4b70031c90..9b57641e75 100644 --- a/actionpack/test/controller/new_base/content_type_test.rb +++ b/actionpack/test/controller/new_base/content_type_test.rb @@ -43,7 +43,7 @@ module ContentType      test "default response is HTML and UTF8" do        with_routing do |set|          set.draw do -          match ':controller', :action => 'index' +          get ':controller', :action => 'index'          end          get "/content_type/base" diff --git a/actionpack/test/controller/new_base/render_template_test.rb b/actionpack/test/controller/new_base/render_template_test.rb index ade204c387..00c7df2af8 100644 --- a/actionpack/test/controller/new_base/render_template_test.rb +++ b/actionpack/test/controller/new_base/render_template_test.rb @@ -164,7 +164,7 @@ module RenderTemplate      test "rendering with implicit layout" do        with_routing do |set| -        set.draw { match ':controller', :action => :index } +        set.draw { get ':controller', :action => :index }          get "/render_template/with_layout" diff --git a/actionpack/test/controller/new_base/render_test.rb b/actionpack/test/controller/new_base/render_test.rb index 60468bf5c7..cc7f12ac6d 100644 --- a/actionpack/test/controller/new_base/render_test.rb +++ b/actionpack/test/controller/new_base/render_test.rb @@ -57,7 +57,7 @@ module Render      test "render with blank" do        with_routing do |set|          set.draw do -          match ":controller", :action => 'index' +          get ":controller", :action => 'index'          end          get "/render/blank_render" @@ -70,7 +70,7 @@ module Render      test "rendering more than once raises an exception" do        with_routing do |set|          set.draw do -          match ":controller", :action => 'index' +          get ":controller", :action => 'index'          end          assert_raises(AbstractController::DoubleRenderError) do diff --git a/actionpack/test/controller/new_base/render_text_test.rb b/actionpack/test/controller/new_base/render_text_test.rb index 06d500cca7..e0b38b29fa 100644 --- a/actionpack/test/controller/new_base/render_text_test.rb +++ b/actionpack/test/controller/new_base/render_text_test.rb @@ -67,7 +67,7 @@ module RenderText      test "rendering text from a action with default options renders the text with the layout" do        with_routing do |set| -        set.draw { match ':controller', :action => 'index' } +        set.draw { get ':controller', :action => 'index' }          get "/render_text/simple"          assert_body "hello david" @@ -77,7 +77,7 @@ module RenderText      test "rendering text from a action with default options renders the text without the layout" do        with_routing do |set| -        set.draw { match ':controller', :action => 'index' } +        set.draw { get ':controller', :action => 'index' }          get "/render_text/with_layout" diff --git a/actionpack/test/controller/redirect_test.rb b/actionpack/test/controller/redirect_test.rb index 6dab42d75d..4331333b98 100644 --- a/actionpack/test/controller/redirect_test.rb +++ b/actionpack/test/controller/redirect_test.rb @@ -262,7 +262,7 @@ class RedirectTest < ActionController::TestCase      with_routing do |set|        set.draw do          resources :workshops -        match ':controller/:action' +        get ':controller/:action'        end        get :redirect_to_existing_record @@ -296,7 +296,7 @@ class RedirectTest < ActionController::TestCase    def test_redirect_to_with_block_and_accepted_options      with_routing do |set|        set.draw do -        match ':controller/:action' +        get ':controller/:action'        end        get :redirect_to_with_block_and_options diff --git a/actionpack/test/controller/render_json_test.rb b/actionpack/test/controller/render_json_test.rb index 75fed8e933..7c0a6bd67e 100644 --- a/actionpack/test/controller/render_json_test.rb +++ b/actionpack/test/controller/render_json_test.rb @@ -102,7 +102,7 @@ class RenderJsonTest < ActionController::TestCase    def test_render_json_with_callback      get :render_json_hello_world_with_callback      assert_equal 'alert({"hello":"world"})', @response.body -    assert_equal 'application/json', @response.content_type +    assert_equal 'text/javascript', @response.content_type    end    def test_render_json_with_custom_content_type diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index fce13d096c..10f62dad65 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -1188,7 +1188,7 @@ class RenderTest < ActionController::TestCase      with_routing do |set|        set.draw do          resources :customers -        match ':controller/:action' +        get ':controller/:action'        end        get :head_with_location_object diff --git a/actionpack/test/controller/render_xml_test.rb b/actionpack/test/controller/render_xml_test.rb index 8b4f2f5349..4f280c4bec 100644 --- a/actionpack/test/controller/render_xml_test.rb +++ b/actionpack/test/controller/render_xml_test.rb @@ -72,7 +72,7 @@ class RenderXmlTest < ActionController::TestCase      with_routing do |set|        set.draw do          resources :customers -        match ':controller/:action' +        get ':controller/:action'        end        get :render_with_object_location diff --git a/actionpack/test/controller/rescue_test.rb b/actionpack/test/controller/rescue_test.rb index 9c51db135b..48e2d6491e 100644 --- a/actionpack/test/controller/rescue_test.rb +++ b/actionpack/test/controller/rescue_test.rb @@ -60,11 +60,6 @@ class RescueController < ActionController::Base      render :text => exception.message    end -  # This is a Dispatcher exception and should be in ApplicationController. -  rescue_from ActionController::RoutingError do -    render :text => 'no way' -  end -    rescue_from ActionView::TemplateError do      render :text => 'action_view templater error'    end @@ -343,9 +338,9 @@ class RescueTest < ActionDispatch::IntegrationTest      def with_test_routing        with_routing do |set|          set.draw do -          match 'foo', :to => ::RescueTest::TestController.action(:foo) -          match 'invalid', :to => ::RescueTest::TestController.action(:invalid) -          match 'b00m', :to => ::RescueTest::TestController.action(:b00m) +          get 'foo', :to => ::RescueTest::TestController.action(:foo) +          get 'invalid', :to => ::RescueTest::TestController.action(:invalid) +          get 'b00m', :to => ::RescueTest::TestController.action(:b00m)          end          yield        end diff --git a/actionpack/test/controller/resources_test.rb b/actionpack/test/controller/resources_test.rb index 3c0a5d36ca..9fc875014c 100644 --- a/actionpack/test/controller/resources_test.rb +++ b/actionpack/test/controller/resources_test.rb @@ -680,7 +680,7 @@ class ResourcesTest < ActionController::TestCase          scope '/threads/:thread_id' do            resources :messages, :as => 'thread_messages' do              get :search, :on => :collection -            match :preview, :on => :new +            get :preview, :on => :new            end          end        end @@ -698,7 +698,7 @@ class ResourcesTest < ActionController::TestCase          scope '/admin' do            resource :account, :as => :admin_account do              get :login, :on => :member -            match :preview, :on => :new +            get :preview, :on => :new            end          end        end diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index 272a7da8c5..9441b46d47 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -17,7 +17,7 @@ class UriReservedCharactersRoutingTest < ActiveSupport::TestCase    def setup      @set = ActionDispatch::Routing::RouteSet.new      @set.draw do -      match ':controller/:action/:variable/*additional' +      get ':controller/:action/:variable/*additional'      end      safe, unsafe = %w(: @ & = + $ , ;), %w(^ ? # [ ]) @@ -85,7 +85,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_symbols_with_dashes      rs.draw do -      match '/:artist/:song-omg', :to => lambda { |env| +      get '/:artist/:song-omg', :to => lambda { |env|          resp = JSON.dump env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]          [200, {}, [resp]]        } @@ -97,7 +97,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_id_with_dash      rs.draw do -      match '/journey/:id', :to => lambda { |env| +      get '/journey/:id', :to => lambda { |env|          resp = JSON.dump env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]          [200, {}, [resp]]        } @@ -109,7 +109,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_dash_with_custom_regexp      rs.draw do -      match '/:artist/:song-omg', :constraints => { :song => /\d+/ }, :to => lambda { |env| +      get '/:artist/:song-omg', :constraints => { :song => /\d+/ }, :to => lambda { |env|          resp = JSON.dump env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]          [200, {}, [resp]]        } @@ -122,7 +122,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_pre_dash      rs.draw do -      match '/:artist/omg-:song', :to => lambda { |env| +      get '/:artist/omg-:song', :to => lambda { |env|          resp = JSON.dump env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]          [200, {}, [resp]]        } @@ -134,7 +134,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_pre_dash_with_custom_regexp      rs.draw do -      match '/:artist/omg-:song', :constraints => { :song => /\d+/ }, :to => lambda { |env| +      get '/:artist/omg-:song', :constraints => { :song => /\d+/ }, :to => lambda { |env|          resp = JSON.dump env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]          [200, {}, [resp]]        } @@ -147,7 +147,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_star_paths_are_greedy      rs.draw do -      match "/*path", :to => lambda { |env| +      get "/*path", :to => lambda { |env|          x = env["action_dispatch.request.path_parameters"][:path]          [200, {}, [x]]        }, :format => false @@ -159,7 +159,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_star_paths_are_greedy_but_not_too_much      rs.draw do -      match "/*path", :to => lambda { |env| +      get "/*path", :to => lambda { |env|          x = JSON.dump env["action_dispatch.request.path_parameters"]          [200, {}, [x]]        } @@ -172,7 +172,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_optional_star_paths_are_greedy      rs.draw do -      match "/(*filters)", :to => lambda { |env| +      get "/(*filters)", :to => lambda { |env|          x = env["action_dispatch.request.path_parameters"][:filters]          [200, {}, [x]]        }, :format => false @@ -184,7 +184,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_optional_star_paths_are_greedy_but_not_too_much      rs.draw do -      match "/(*filters)", :to => lambda { |env| +      get "/(*filters)", :to => lambda { |env|          x = JSON.dump env["action_dispatch.request.path_parameters"]          [200, {}, [x]]        } @@ -198,11 +198,11 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_regexp_precidence      @rs.draw do -      match '/whois/:domain', :constraints => { +      get '/whois/:domain', :constraints => {          :domain => /\w+\.[\w\.]+/ },          :to     => lambda { |env| [200, {}, %w{regexp}] } -      match '/whois/:id', :to => lambda { |env| [200, {}, %w{id}] } +      get '/whois/:id', :to => lambda { |env| [200, {}, %w{id}] }      end      assert_equal 'regexp', get(URI('http://example.org/whois/example.org')) @@ -217,9 +217,9 @@ class LegacyRouteSetTests < ActiveSupport::TestCase      }      @rs.draw do -      match '/', :constraints => subdomain.new, +      get '/', :constraints => subdomain.new,                   :to          => lambda { |env| [200, {}, %w{default}] } -      match '/', :constraints => { :subdomain => 'clients' }, +      get '/', :constraints => { :subdomain => 'clients' },                   :to          => lambda { |env| [200, {}, %w{clients}] }      end @@ -229,11 +229,11 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_lambda_constraints      @rs.draw do -      match '/', :constraints => lambda { |req| +      get '/', :constraints => lambda { |req|          req.subdomain.present? and req.subdomain != "clients" },                   :to          => lambda { |env| [200, {}, %w{default}] } -      match '/', :constraints => lambda { |req| +      get '/', :constraints => lambda { |req|          req.subdomain.present? && req.subdomain == "clients" },                   :to          => lambda { |env| [200, {}, %w{clients}] }      end @@ -271,7 +271,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    end    def test_default_setup -    @rs.draw { match '/:controller(/:action(/:id))' } +    @rs.draw { get '/:controller(/:action(/:id))' }      assert_equal({:controller => "content", :action => 'index'}, rs.recognize_path("/content"))      assert_equal({:controller => "content", :action => 'list'},  rs.recognize_path("/content/list"))      assert_equal({:controller => "content", :action => 'show', :id => '10'}, rs.recognize_path("/content/show/10")) @@ -289,21 +289,21 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_ignores_leading_slash      @rs.clear! -    @rs.draw { match '/:controller(/:action(/:id))'} +    @rs.draw { get '/:controller(/:action(/:id))'}      test_default_setup    end    def test_route_with_colon_first      rs.draw do -      match '/:controller/:action/:id', :action => 'index', :id => nil -      match ':url', :controller => 'tiny_url', :action => 'translate' +      get '/:controller/:action/:id', :action => 'index', :id => nil +      get ':url', :controller => 'tiny_url', :action => 'translate'      end    end    def test_route_with_regexp_for_controller      rs.draw do -      match ':controller/:admintoken(/:action(/:id))', :controller => /admin\/.+/ -      match '/:controller(/:action(/:id))' +      get ':controller/:admintoken(/:action(/:id))', :controller => /admin\/.+/ +      get '/:controller(/:action(/:id))'      end      assert_equal({:controller => "admin/user", :admintoken => "foo", :action => "index"}, @@ -317,7 +317,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_route_with_regexp_and_captures_for_controller      rs.draw do -      match '/:controller(/:action(/:id))', :controller => /admin\/(accounts|users)/ +      get '/:controller(/:action(/:id))', :controller => /admin\/(accounts|users)/      end      assert_equal({:controller => "admin/accounts", :action => "index"}, rs.recognize_path("/admin/accounts"))      assert_equal({:controller => "admin/users", :action => "index"}, rs.recognize_path("/admin/users")) @@ -326,7 +326,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_route_with_regexp_and_dot      rs.draw do -      match ':controller/:action/:file', +      get ':controller/:action/:file',                  :controller => /admin|user/,                  :action => /upload|download/,                  :defaults => {:file => nil}, @@ -356,7 +356,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_named_route_with_option      rs.draw do -      match 'page/:title' => 'content#show_page', :as => 'page' +      get 'page/:title' => 'content#show_page', :as => 'page'      end      assert_equal("http://test.host/page/new%20stuff", @@ -365,7 +365,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_named_route_with_default      rs.draw do -      match 'page/:title' => 'content#show_page', :title => 'AboutPage', :as => 'page' +      get 'page/:title' => 'content#show_page', :title => 'AboutPage', :as => 'page'      end      assert_equal("http://test.host/page/AboutRails", @@ -375,7 +375,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_named_route_with_path_prefix      rs.draw do        scope "my" do -        match 'page' => 'content#show_page', :as => 'page' +        get 'page' => 'content#show_page', :as => 'page'        end      end @@ -386,7 +386,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_named_route_with_blank_path_prefix      rs.draw do        scope "" do -        match 'page' => 'content#show_page', :as => 'page' +        get 'page' => 'content#show_page', :as => 'page'        end      end @@ -396,7 +396,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_named_route_with_nested_controller      rs.draw do -      match 'admin/user' => 'admin/user#index', :as => "users" +      get 'admin/user' => 'admin/user#index', :as => "users"      end      assert_equal("http://test.host/admin/user", @@ -405,7 +405,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_optimised_named_route_with_host      rs.draw do -      match 'page' => 'content#show_page', :as => 'pages', :host => 'foo.com' +      get 'page' => 'content#show_page', :as => 'pages', :host => 'foo.com'      end      routes = setup_for_named_route      routes.expects(:url_for).with({ @@ -424,7 +424,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_named_route_without_hash      rs.draw do -      match ':controller/:action/:id', :as => 'normal' +      get ':controller/:action/:id', :as => 'normal'      end    end @@ -448,9 +448,9 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_named_route_with_regexps      rs.draw do -      match 'page/:year/:month/:day/:title' => 'page#show', :as => 'article', +      get 'page/:year/:month/:day/:title' => 'page#show', :as => 'article',          :year => /\d+/, :month => /\d+/, :day => /\d+/ -      match ':controller/:action/:id' +      get ':controller/:action/:id'      end      routes = setup_for_named_route @@ -460,7 +460,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    end    def test_changing_controller -    @rs.draw { match ':controller/:action/:id' } +    @rs.draw { get ':controller/:action/:id' }      assert_equal '/admin/stuff/show/10',          url_for(rs, {:controller => 'stuff', :action => 'show', :id => 10}, @@ -469,8 +469,8 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_paths_escaped      rs.draw do -      match 'file/*path' => 'content#show_file', :as => 'path' -      match ':controller/:action/:id' +      get 'file/*path' => 'content#show_file', :as => 'path' +      get ':controller/:action/:id'      end      # No + to space in URI escaping, only for query params. @@ -486,7 +486,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_paths_slashes_unescaped_with_ordered_parameters      rs.draw do -      match '/file/*path' => 'content#index', :as => 'path' +      get '/file/*path' => 'content#index', :as => 'path'      end      # No / to %2F in URI, only for query params. @@ -495,14 +495,14 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_non_controllers_cannot_be_matched      rs.draw do -      match ':controller/:action/:id' +      get ':controller/:action/:id'      end      assert_raise(ActionController::RoutingError) { rs.recognize_path("/not_a/show/10") }    end    def test_should_list_options_diff_when_routing_constraints_dont_match      rs.draw do -      match 'post/:id' => 'post#show', :constraints => { :id => /\d+/ }, :as => 'post' +      get 'post/:id' => 'post#show', :constraints => { :id => /\d+/ }, :as => 'post'      end      assert_raise(ActionController::RoutingError) do        url_for(rs, { :controller => 'post', :action => 'show', :bad_param => "foo", :use_route => "post" }) @@ -511,7 +511,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_dynamic_path_allowed      rs.draw do -      match '*path' => 'content#show_file' +      get '*path' => 'content#show_file'      end      assert_equal '/pages/boo', @@ -520,7 +520,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_dynamic_recall_paths_allowed      rs.draw do -      match '*path' => 'content#show_file' +      get '*path' => 'content#show_file'      end      assert_equal '/pages/boo', @@ -529,8 +529,8 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_backwards      rs.draw do -      match 'page/:id(/:action)' => 'pages#show' -      match ':controller(/:action(/:id))' +      get 'page/:id(/:action)' => 'pages#show' +      get ':controller(/:action(/:id))'      end      assert_equal '/page/20',   url_for(rs, { :id => 20 }, { :controller => 'pages', :action => 'show' }) @@ -540,8 +540,8 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_route_with_fixnum_default      rs.draw do -      match 'page(/:id)' => 'content#show_page', :id => 1 -      match ':controller/:action/:id' +      get 'page(/:id)' => 'content#show_page', :id => 1 +      get ':controller/:action/:id'      end      assert_equal '/page',    url_for(rs, { :controller => 'content', :action => 'show_page' }) @@ -557,8 +557,8 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    # For newer revision    def test_route_with_text_default      rs.draw do -      match 'page/:id' => 'content#show_page', :id => 1 -      match ':controller/:action/:id' +      get 'page/:id' => 'content#show_page', :id => 1 +      get ':controller/:action/:id'      end      assert_equal '/page/foo', url_for(rs, { :controller => 'content', :action => 'show_page', :id => 'foo' }) @@ -573,13 +573,13 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    end    def test_action_expiry -    @rs.draw { match ':controller(/:action(/:id))' } +    @rs.draw { get ':controller(/:action(/:id))' }      assert_equal '/content', url_for(rs, { :controller => 'content' }, { :controller => 'content', :action => 'show' })    end    def test_requirement_should_prevent_optional_id      rs.draw do -      match 'post/:id' => 'post#show', :constraints => {:id => /\d+/}, :as => 'post' +      get 'post/:id' => 'post#show', :constraints => {:id => /\d+/}, :as => 'post'      end      assert_equal '/post/10', url_for(rs, { :controller => 'post', :action => 'show', :id => 10 }) @@ -591,11 +591,11 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_both_requirement_and_optional      rs.draw do -      match('test(/:year)' => 'post#show', :as => 'blog', +      get('test(/:year)' => 'post#show', :as => 'blog',          :defaults => { :year => nil },          :constraints => { :year => /\d{4}/ }        ) -      match ':controller/:action/:id' +      get ':controller/:action/:id'      end      assert_equal '/test', url_for(rs, { :controller => 'post', :action => 'show' }) @@ -606,8 +606,8 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_set_to_nil_forgets      rs.draw do -      match 'pages(/:year(/:month(/:day)))' => 'content#list_pages', :month => nil, :day => nil -      match ':controller/:action/:id' +      get 'pages(/:year(/:month(/:day)))' => 'content#list_pages', :month => nil, :day => nil +      get ':controller/:action/:id'      end      assert_equal '/pages/2005', @@ -649,8 +649,8 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_named_route_method      rs.draw do -      match 'categories' => 'content#categories', :as => 'categories' -      match ':controller(/:action(/:id))' +      get 'categories' => 'content#categories', :as => 'categories' +      get ':controller(/:action(/:id))'      end      assert_equal '/categories', url_for(rs, { :controller => 'content', :action => 'categories' }) @@ -664,9 +664,9 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_nil_defaults      rs.draw do -      match 'journal' => 'content#list_journal', +      get 'journal' => 'content#list_journal',          :date => nil, :user_id => nil -      match ':controller/:action/:id' +      get ':controller/:action/:id'      end      assert_equal '/journal', url_for(rs, { @@ -698,7 +698,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_recognize_array_of_methods      rs.draw do        match '/match' => 'books#get_or_post', :via => [:get, :post] -      match '/match' => 'books#not_get_or_post' +      put '/match' => 'books#not_get_or_post'      end      params = rs.recognize_path("/match", :method => :post) @@ -710,10 +710,10 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_subpath_recognized      rs.draw do -      match '/books/:id/edit'    => 'subpath_books#edit' -      match '/items/:id/:action' => 'subpath_books' -      match '/posts/new/:action' => 'subpath_books' -      match '/posts/:id'         => 'subpath_books#show' +      get '/books/:id/edit'    => 'subpath_books#edit' +      get '/items/:id/:action' => 'subpath_books' +      get '/posts/new/:action' => 'subpath_books' +      get '/posts/:id'         => 'subpath_books#show'      end      hash = rs.recognize_path "/books/17/edit" @@ -735,9 +735,9 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_subpath_generated      rs.draw do -      match '/books/:id/edit'    => 'subpath_books#edit' -      match '/items/:id/:action' => 'subpath_books' -      match '/posts/new/:action' => 'subpath_books' +      get '/books/:id/edit'    => 'subpath_books#edit' +      get '/items/:id/:action' => 'subpath_books' +      get '/posts/new/:action' => 'subpath_books'      end      assert_equal "/books/7/edit",      url_for(rs, { :controller => "subpath_books", :id => 7, :action => "edit" }) @@ -747,7 +747,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_failed_constraints_raises_exception_with_violated_constraints      rs.draw do -      match 'foos/:id' => 'foos#show', :as => 'foo_with_requirement', :constraints => { :id => /\d+/ } +      get 'foos/:id' => 'foos#show', :as => 'foo_with_requirement', :constraints => { :id => /\d+/ }      end      assert_raise(ActionController::RoutingError) do @@ -758,11 +758,11 @@ class LegacyRouteSetTests < ActiveSupport::TestCase    def test_routes_changed_correctly_after_clear      rs = ::ActionDispatch::Routing::RouteSet.new      rs.draw do -      match 'ca' => 'ca#aa' -      match 'cb' => 'cb#ab' -      match 'cc' => 'cc#ac' -      match ':controller/:action/:id' -      match ':controller/:action/:id.:format' +      get 'ca' => 'ca#aa' +      get 'cb' => 'cb#ab' +      get 'cc' => 'cc#ac' +      get ':controller/:action/:id' +      get ':controller/:action/:id.:format'      end      hash = rs.recognize_path "/cc" @@ -771,10 +771,10 @@ class LegacyRouteSetTests < ActiveSupport::TestCase      assert_equal %w(cc ac), [hash[:controller], hash[:action]]      rs.draw do -      match 'cb' => 'cb#ab' -      match 'cc' => 'cc#ac' -      match ':controller/:action/:id' -      match ':controller/:action/:id.:format' +      get 'cb' => 'cb#ab' +      get 'cc' => 'cc#ac' +      get ':controller/:action/:id' +      get ':controller/:action/:id.:format'      end      hash = rs.recognize_path "/cc" @@ -799,29 +799,29 @@ class RouteSetTest < ActiveSupport::TestCase      @default_route_set ||= begin        set = ROUTING::RouteSet.new        set.draw do -        match '/:controller(/:action(/:id))' +        get '/:controller(/:action(/:id))'        end        set      end    end    def test_generate_extras -    set.draw { match ':controller/(:action(/:id))' } +    set.draw { get ':controller/(:action(/:id))' }      path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")      assert_equal "/foo/bar/15", path      assert_equal %w(that this), extras.map { |e| e.to_s }.sort    end    def test_extra_keys -    set.draw { match ':controller/:action/:id' } +    set.draw { get ':controller/:action/:id' }      extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")      assert_equal %w(that this), extras.map { |e| e.to_s }.sort    end    def test_generate_extras_not_first      set.draw do -      match ':controller/:action/:id.:format' -      match ':controller/:action/:id' +      get ':controller/:action/:id.:format' +      get ':controller/:action/:id'      end      path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")      assert_equal "/foo/bar/15", path @@ -830,8 +830,8 @@ class RouteSetTest < ActiveSupport::TestCase    def test_generate_not_first      set.draw do -      match ':controller/:action/:id.:format' -      match ':controller/:action/:id' +      get ':controller/:action/:id.:format' +      get ':controller/:action/:id'      end      assert_equal "/foo/bar/15?this=hello",          url_for(set, { :controller => "foo", :action => "bar", :id => 15, :this => "hello" }) @@ -839,8 +839,8 @@ class RouteSetTest < ActiveSupport::TestCase    def test_extra_keys_not_first      set.draw do -      match ':controller/:action/:id.:format' -      match ':controller/:action/:id' +      get ':controller/:action/:id.:format' +      get ':controller/:action/:id'      end      extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")      assert_equal %w(that this), extras.map { |e| e.to_s }.sort @@ -849,7 +849,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_draw      assert_equal 0, set.routes.size      set.draw do -      match '/hello/world' => 'a#b' +      get '/hello/world' => 'a#b'      end      assert_equal 1, set.routes.size    end @@ -857,7 +857,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_draw_symbol_controller_name      assert_equal 0, set.routes.size      set.draw do -      match '/users/index' => 'users#index' +      get '/users/index' => 'users#index'      end      set.recognize_path('/users/index', :method => :get)      assert_equal 1, set.routes.size @@ -866,7 +866,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_named_draw      assert_equal 0, set.routes.size      set.draw do -      match '/hello/world' => 'a#b', :as => 'hello' +      get '/hello/world' => 'a#b', :as => 'hello'      end      assert_equal 1, set.routes.size      assert_equal set.routes.first, set.named_routes[:hello] @@ -874,18 +874,18 @@ class RouteSetTest < ActiveSupport::TestCase    def test_earlier_named_routes_take_precedence      set.draw do -      match '/hello/world' => 'a#b', :as => 'hello' -      match '/hello'       => 'a#b', :as => 'hello' +      get '/hello/world' => 'a#b', :as => 'hello' +      get '/hello'       => 'a#b', :as => 'hello'      end      assert_equal set.routes.first, set.named_routes[:hello]    end    def setup_named_route_test      set.draw do -      match '/people(/:id)' => 'people#show', :as => 'show' -      match '/people' => 'people#index', :as => 'index' -      match '/people/go/:foo/:bar/joe(/:id)' => 'people#multi', :as => 'multi' -      match '/admin/users' => 'admin/users#index', :as => "users" +      get '/people(/:id)' => 'people#show', :as => 'show' +      get '/people' => 'people#index', :as => 'index' +      get '/people/go/:foo/:bar/joe(/:id)' => 'people#multi', :as => 'multi' +      get '/admin/users' => 'admin/users#index', :as => "users"      end      MockController.build(set.url_helpers).new @@ -985,7 +985,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_draw_default_route      set.draw do -      match '/:controller/:action/:id' +      get '/:controller/:action/:id'      end      assert_equal 1, set.routes.size @@ -999,8 +999,8 @@ class RouteSetTest < ActiveSupport::TestCase    def test_route_with_parameter_shell      set.draw do -      match 'page/:id' => 'pages#show', :id => /\d+/ -      match '/:controller(/:action(/:id))' +      get 'page/:id' => 'pages#show', :id => /\d+/ +      get '/:controller(/:action(/:id))'      end      assert_equal({:controller => 'pages', :action => 'index'}, set.recognize_path('/pages')) @@ -1014,7 +1014,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_route_constraints_on_request_object_with_anchors_are_valid      assert_nothing_raised do        set.draw do -        match 'page/:id' => 'pages#show', :constraints => { :host => /^foo$/ } +        get 'page/:id' => 'pages#show', :constraints => { :host => /^foo$/ }        end      end    end @@ -1022,27 +1022,27 @@ class RouteSetTest < ActiveSupport::TestCase    def test_route_constraints_with_anchor_chars_are_invalid      assert_raise ArgumentError do        set.draw do -        match 'page/:id' => 'pages#show', :id => /^\d+/ +        get 'page/:id' => 'pages#show', :id => /^\d+/        end      end      assert_raise ArgumentError do        set.draw do -        match 'page/:id' => 'pages#show', :id => /\A\d+/ +        get 'page/:id' => 'pages#show', :id => /\A\d+/        end      end      assert_raise ArgumentError do        set.draw do -        match 'page/:id' => 'pages#show', :id => /\d+$/ +        get 'page/:id' => 'pages#show', :id => /\d+$/        end      end      assert_raise ArgumentError do        set.draw do -        match 'page/:id' => 'pages#show', :id => /\d+\Z/ +        get 'page/:id' => 'pages#show', :id => /\d+\Z/        end      end      assert_raise ArgumentError do        set.draw do -        match 'page/:id' => 'pages#show', :id => /\d+\z/ +        get 'page/:id' => 'pages#show', :id => /\d+\z/        end      end    end @@ -1057,7 +1057,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_recognize_with_encoded_id_and_regex      set.draw do -      match 'page/:id' => 'pages#show', :id => /[a-zA-Z0-9\+]+/ +      get 'page/:id' => 'pages#show', :id => /[a-zA-Z0-9\+]+/      end      assert_equal({:controller => 'pages', :action => 'show', :id => '10'}, set.recognize_path('/page/10')) @@ -1128,7 +1128,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_typo_recognition      set.draw do -      match 'articles/:year/:month/:day/:title' => 'articles#permalink', +      get 'articles/:year/:month/:day/:title' => 'articles#permalink',               :year => /\d{4}/, :day => /\d{1,2}/, :month => /\d{1,2}/      end @@ -1143,7 +1143,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_routing_traversal_does_not_load_extra_classes      assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded"      set.draw do -      match '/profile' => 'profile#index' +      get '/profile' => 'profile#index'      end      set.recognize_path("/profile") rescue nil @@ -1177,8 +1177,8 @@ class RouteSetTest < ActiveSupport::TestCase    def test_generate_with_default_action      set.draw do -      match "/people", :controller => "people", :action => "index" -      match "/people/list", :controller => "people", :action => "list" +      get "/people", :controller => "people", :action => "index" +      get "/people/list", :controller => "people", :action => "list"      end      url = url_for(set, { :controller => "people", :action => "list" }) @@ -1197,7 +1197,7 @@ class RouteSetTest < ActiveSupport::TestCase      set.draw do        namespace 'api' do -        match 'inventory' => 'products#inventory' +        get 'inventory' => 'products#inventory'        end      end @@ -1222,7 +1222,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_namespace_with_path_prefix      set.draw do        scope :module => "api", :path => "prefix" do -        match 'inventory' => 'products#inventory' +        get 'inventory' => 'products#inventory'        end      end @@ -1234,7 +1234,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_namespace_with_blank_path_prefix      set.draw do        scope :module => "api", :path => "" do -        match 'inventory' => 'products#inventory' +        get 'inventory' => 'products#inventory'        end      end @@ -1244,7 +1244,7 @@ class RouteSetTest < ActiveSupport::TestCase    end    def test_generate_changes_controller_module -    set.draw { match ':controller/:action/:id' } +    set.draw { get ':controller/:action/:id' }      current = { :controller => "bling/bloop", :action => "bap", :id => 9 }      assert_equal "/foo/bar/baz/7", @@ -1253,7 +1253,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_id_is_sticky_when_it_ought_to_be      set.draw do -      match ':controller/:id/:action' +      get ':controller/:id/:action'      end      url = url_for(set, { :action => "destroy" }, { :controller => "people", :action => "show", :id => "7" }) @@ -1262,8 +1262,8 @@ class RouteSetTest < ActiveSupport::TestCase    def test_use_static_path_when_possible      set.draw do -      match 'about' => "welcome#about" -      match ':controller/:action/:id' +      get 'about' => "welcome#about" +      get ':controller/:action/:id'      end      url = url_for(set, { :controller => "welcome", :action => "about" }, @@ -1273,7 +1273,7 @@ class RouteSetTest < ActiveSupport::TestCase    end    def test_generate -    set.draw { match ':controller/:action/:id' } +    set.draw { get ':controller/:action/:id' }      args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" }      assert_equal "/foo/bar/7?x=y",     url_for(set, args) @@ -1284,7 +1284,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_generate_with_path_prefix      set.draw do        scope "my" do -        match ':controller(/:action(/:id))' +        get ':controller(/:action(/:id))'        end      end @@ -1295,7 +1295,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_generate_with_blank_path_prefix      set.draw do        scope "" do -        match ':controller(/:action(/:id))' +        get ':controller(/:action(/:id))'        end      end @@ -1305,9 +1305,9 @@ class RouteSetTest < ActiveSupport::TestCase    def test_named_routes_are_never_relative_to_modules      set.draw do -      match "/connection/manage(/:action)" => 'connection/manage#index' -      match "/connection/connection" => "connection/connection#index" -      match '/connection' => 'connection#index', :as => 'family_connection' +      get "/connection/manage(/:action)" => 'connection/manage#index' +      get "/connection/connection" => "connection/connection#index" +      get '/connection' => 'connection#index', :as => 'family_connection'      end      url = url_for(set, { :controller => "connection" }, { :controller => 'connection/manage' }) @@ -1319,7 +1319,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_action_left_off_when_id_is_recalled      set.draw do -      match ':controller(/:action(/:id))' +      get ':controller(/:action(/:id))'      end      assert_equal '/books', url_for(set,        {:controller => 'books', :action => 'index'}, @@ -1329,8 +1329,8 @@ class RouteSetTest < ActiveSupport::TestCase    def test_query_params_will_be_shown_when_recalled      set.draw do -      match 'show_weblog/:parameter' => 'weblog#show' -      match ':controller(/:action(/:id))' +      get 'show_weblog/:parameter' => 'weblog#show' +      get ':controller(/:action(/:id))'      end      assert_equal '/weblog/edit?parameter=1', url_for(set,        {:action => 'edit', :parameter => 1}, @@ -1340,7 +1340,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_format_is_not_inherit      set.draw do -      match '/posts(.:format)' => 'posts#index' +      get '/posts(.:format)' => 'posts#index'      end      assert_equal '/posts', url_for(set, @@ -1355,7 +1355,7 @@ class RouteSetTest < ActiveSupport::TestCase    end    def test_expiry_determination_should_consider_values_with_to_param -    set.draw { match 'projects/:project_id/:controller/:action' } +    set.draw { get 'projects/:project_id/:controller/:action' }      assert_equal '/projects/1/weblog/show', url_for(set,        { :action => 'show', :project_id => 1 },        { :controller => 'weblog', :action => 'show', :project_id => '1' }) @@ -1365,7 +1365,7 @@ class RouteSetTest < ActiveSupport::TestCase      set.draw do        resources :projects do          member do -          match 'milestones' => 'milestones#index', :as => 'milestones' +          get 'milestones' => 'milestones#index', :as => 'milestones'          end        end      end @@ -1398,7 +1398,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_route_constraints_with_unsupported_regexp_options_must_error      assert_raise ArgumentError do        set.draw do -        match 'page/:name' => 'pages#show', +        get 'page/:name' => 'pages#show',            :constraints => { :name => /(david|jamis)/m }        end      end @@ -1407,13 +1407,13 @@ class RouteSetTest < ActiveSupport::TestCase    def test_route_constraints_with_supported_options_must_not_error      assert_nothing_raised do        set.draw do -        match 'page/:name' => 'pages#show', +        get 'page/:name' => 'pages#show',            :constraints => { :name => /(david|jamis)/i }        end      end      assert_nothing_raised do        set.draw do -        match 'page/:name' => 'pages#show', +        get 'page/:name' => 'pages#show',            :constraints => { :name => / # Desperately overcommented regexp                                        ( #Either                                         david #The Creator @@ -1427,7 +1427,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_route_with_subdomain_and_constraints_must_receive_params      name_param = nil      set.draw do -      match 'page/:name' => 'pages#show', :constraints => lambda {|request| +      get 'page/:name' => 'pages#show', :constraints => lambda {|request|          name_param = request.params[:name]          return true        } @@ -1439,7 +1439,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_route_requirement_recognize_with_ignore_case      set.draw do -      match 'page/:name' => 'pages#show', +      get 'page/:name' => 'pages#show',          :constraints => {:name => /(david|jamis)/i}      end      assert_equal({:controller => 'pages', :action => 'show', :name => 'jamis'}, set.recognize_path('/page/jamis')) @@ -1451,7 +1451,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_route_requirement_generate_with_ignore_case      set.draw do -      match 'page/:name' => 'pages#show', +      get 'page/:name' => 'pages#show',          :constraints => {:name => /(david|jamis)/i}      end @@ -1466,7 +1466,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_route_requirement_recognize_with_extended_syntax      set.draw do -      match 'page/:name' => 'pages#show', +      get 'page/:name' => 'pages#show',          :constraints => {:name => / # Desperately overcommented regexp                                      ( #Either                                       david #The Creator @@ -1486,7 +1486,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_route_requirement_with_xi_modifiers      set.draw do -      match 'page/:name' => 'pages#show', +      get 'page/:name' => 'pages#show',          :constraints => {:name => / # Desperately overcommented regexp                                      ( #Either                                       david #The Creator @@ -1504,8 +1504,8 @@ class RouteSetTest < ActiveSupport::TestCase    def test_routes_with_symbols      set.draw do -      match 'unnamed', :controller => :pages, :action => :show, :name => :as_symbol -      match 'named'  , :controller => :pages, :action => :show, :name => :as_symbol, :as => :named +      get 'unnamed', :controller => :pages, :action => :show, :name => :as_symbol +      get 'named'  , :controller => :pages, :action => :show, :name => :as_symbol, :as => :named      end      assert_equal({:controller => 'pages', :action => 'show', :name => :as_symbol}, set.recognize_path('/unnamed'))      assert_equal({:controller => 'pages', :action => 'show', :name => :as_symbol}, set.recognize_path('/named')) @@ -1513,8 +1513,8 @@ class RouteSetTest < ActiveSupport::TestCase    def test_regexp_chunk_should_add_question_mark_for_optionals      set.draw do -      match '/' => 'foo#index' -      match '/hello' => 'bar#index' +      get '/' => 'foo#index' +      get '/hello' => 'bar#index'      end      assert_equal '/',      url_for(set, { :controller => 'foo' }) @@ -1526,7 +1526,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_assign_route_options_with_anchor_chars      set.draw do -      match '/cars/:action/:person/:car/', :controller => 'cars' +      get '/cars/:action/:person/:car/', :controller => 'cars'      end      assert_equal '/cars/buy/1/2', url_for(set, { :controller => 'cars', :action => 'buy', :person => '1', :car => '2' }) @@ -1536,7 +1536,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_segmentation_of_dot_path      set.draw do -      match '/books/:action.rss', :controller => 'books' +      get '/books/:action.rss', :controller => 'books'      end      assert_equal '/books/list.rss', url_for(set, { :controller => 'books', :action => 'list' }) @@ -1546,7 +1546,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_segmentation_of_dynamic_dot_path      set.draw do -      match '/books(/:action(.:format))', :controller => 'books' +      get '/books(/:action(.:format))', :controller => 'books'      end      assert_equal '/books/list.rss', url_for(set, { :controller => 'books', :action => 'list', :format => 'rss' }) @@ -1562,7 +1562,7 @@ class RouteSetTest < ActiveSupport::TestCase    def test_slashes_are_implied      @set = nil -    set.draw { match("/:controller(/:action(/:id))") } +    set.draw { get("/:controller(/:action(/:id))") }      assert_equal '/content',        url_for(set, { :controller => 'content', :action => 'index' })      assert_equal '/content/list',   url_for(set, { :controller => 'content', :action => 'list' }) @@ -1647,13 +1647,13 @@ class RouteSetTest < ActiveSupport::TestCase    def test_generate_with_default_params      set.draw do -      match 'dummy/page/:page' => 'dummy#show' -      match 'dummy/dots/page.:page' => 'dummy#dots' -      match 'ibocorp(/:page)' => 'ibocorp#show', +      get 'dummy/page/:page' => 'dummy#show' +      get 'dummy/dots/page.:page' => 'dummy#dots' +      get 'ibocorp(/:page)' => 'ibocorp#show',                               :constraints => { :page => /\d+/ },                               :defaults => { :page => 1 } -      match ':controller/:action/:id' +      get ':controller/:action/:id'      end      assert_equal '/ibocorp', url_for(set, { :controller => 'ibocorp', :action => "show", :page => 1 }) @@ -1661,17 +1661,17 @@ class RouteSetTest < ActiveSupport::TestCase    def test_generate_with_optional_params_recalls_last_request      set.draw do -      match "blog/", :controller => "blog", :action => "index" +      get "blog/", :controller => "blog", :action => "index" -      match "blog(/:year(/:month(/:day)))", +      get "blog(/:year(/:month(/:day)))",              :controller => "blog",              :action => "show_date",              :constraints => { :year => /(19|20)\d\d/, :month => /[01]?\d/, :day => /[0-3]?\d/ },              :day => nil, :month => nil -      match "blog/show/:id", :controller => "blog", :action => "show", :id => /\d+/ -      match "blog/:controller/:action(/:id)" -      match "*anything", :controller => "blog", :action => "unknown_request" +      get "blog/show/:id", :controller => "blog", :action => "show", :id => /\d+/ +      get "blog/:controller/:action(/:id)" +      get "*anything", :controller => "blog", :action => "unknown_request"      end      assert_equal({:controller => "blog", :action => "index"}, set.recognize_path("/blog")) @@ -1719,7 +1719,7 @@ class RackMountIntegrationTests < ActiveSupport::TestCase        root :to => 'users#index'      end -    match '/blog(/:year(/:month(/:day)))' => 'posts#show_date', +    get '/blog(/:year(/:month(/:day)))' => 'posts#show_date',        :constraints => {          :year => /(19|20)\d\d/,          :month => /[01]?\d/, @@ -1728,37 +1728,37 @@ class RackMountIntegrationTests < ActiveSupport::TestCase        :day => nil,        :month => nil -    match 'archive/:year', :controller => 'archive', :action => 'index', +    get 'archive/:year', :controller => 'archive', :action => 'index',        :defaults => { :year => nil },        :constraints => { :year => /\d{4}/ },        :as => "blog"      resources :people -    match 'legacy/people' => "people#index", :legacy => "true" +    get 'legacy/people' => "people#index", :legacy => "true" -    match 'symbols', :controller => :symbols, :action => :show, :name => :as_symbol -    match 'id_default(/:id)' => "foo#id_default", :id => 1 +    get 'symbols', :controller => :symbols, :action => :show, :name => :as_symbol +    get 'id_default(/:id)' => "foo#id_default", :id => 1      match 'get_or_post' => "foo#get_or_post", :via => [:get, :post] -    match 'optional/:optional' => "posts#index" -    match 'projects/:project_id' => "project#index", :as => "project" -    match 'clients' => "projects#index" +    get 'optional/:optional' => "posts#index" +    get 'projects/:project_id' => "project#index", :as => "project" +    get 'clients' => "projects#index" -    match 'ignorecase/geocode/:postalcode' => 'geocode#show', :postalcode => /hx\d\d-\d[a-z]{2}/i -    match 'extended/geocode/:postalcode' => 'geocode#show',:constraints => { +    get 'ignorecase/geocode/:postalcode' => 'geocode#show', :postalcode => /hx\d\d-\d[a-z]{2}/i +    get 'extended/geocode/:postalcode' => 'geocode#show',:constraints => {                    :postalcode => /# Postcode format                                    \d{5} #Prefix                                    (-\d{4})? #Suffix                                    /x                    }, :as => "geocode" -    match 'news(.:format)' => "news#index" +    get 'news(.:format)' => "news#index" -    match 'comment/:id(/:action)' => "comments#show" -    match 'ws/:controller(/:action(/:id))', :ws => true -    match 'account(/:action)' => "account#subscription" -    match 'pages/:page_id/:controller(/:action(/:id))' -    match ':controller/ping', :action => 'ping' -    match ':controller(/:action(/:id))(.:format)' +    get 'comment/:id(/:action)' => "comments#show" +    get 'ws/:controller(/:action(/:id))', :ws => true +    get 'account(/:action)' => "account#subscription" +    get 'pages/:page_id/:controller(/:action(/:id))' +    get ':controller/ping', :action => 'ping' +    match ':controller(/:action(/:id))(.:format)', :via => :all      root :to => "news#index"    } diff --git a/actionpack/test/controller/send_file_test.rb b/actionpack/test/controller/send_file_test.rb index 3af17f495c..6fc3556e31 100644 --- a/actionpack/test/controller/send_file_test.rb +++ b/actionpack/test/controller/send_file_test.rb @@ -154,6 +154,17 @@ class SendFileTest < ActionController::TestCase      end    end +  def test_send_file_with_default_content_disposition_header +    process('data') +    assert_equal 'attachment', @controller.headers['Content-Disposition'] +  end + +  def test_send_file_without_content_disposition_header +    @controller.options = {:disposition => nil} +    process('data') +    assert_nil @controller.headers['Content-Disposition'] +  end +    %w(file data).each do |method|      define_method "test_send_#{method}_status" do        @controller.options = { :stream => false, :status => 500 } diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb index ecba9fed22..0d6d303b51 100644 --- a/actionpack/test/controller/test_case_test.rb +++ b/actionpack/test/controller/test_case_test.rb @@ -45,6 +45,10 @@ class TestCaseTest < ActionController::TestCase        render :text => request.fullpath      end +    def test_format +      render :text => request.format +    end +      def test_query_string        render :text => request.query_string      end @@ -138,7 +142,7 @@ XML      @request.env['PATH_INFO'] = nil      @routes = ActionDispatch::Routing::RouteSet.new.tap do |r|        r.draw do -        match ':controller(/:action(/:id))' +        get ':controller(/:action(/:id))'        end      end    end @@ -224,6 +228,26 @@ XML      assert_equal 'value2', session[:symbol]    end +  def test_process_merges_session_arg +    session[:foo] = 'bar' +    get :no_op, nil, { :bar => 'baz' } +    assert_equal 'bar', session[:foo] +    assert_equal 'baz', session[:bar] +  end + +  def test_merged_session_arg_is_retained_across_requests +    get :no_op, nil, { :foo => 'bar' } +    assert_equal 'bar', session[:foo] +    get :no_op +    assert_equal 'bar', session[:foo] +  end + +  def test_process_overwrites_existing_session_arg +    session[:foo] = 'bar' +    get :no_op, nil, { :foo => 'baz' } +    assert_equal 'baz', session[:foo] +  end +    def test_session_is_cleared_from_controller_after_reset_session      process :set_session      process :reset_the_session @@ -524,7 +548,7 @@ XML      with_routing do |set|        set.draw do          namespace :admin do -          match 'user' => 'user#index' +          get 'user' => 'user#index'          end        end @@ -534,7 +558,7 @@ XML    def test_assert_routing_with_glob      with_routing do |set| -      set.draw { match('*path' => "pages#show") } +      set.draw { get('*path' => "pages#show") }        assert_routing('/company/about', { :controller => 'pages', :action => 'show', :path => 'company/about' })      end    end @@ -559,14 +583,34 @@ XML      )    end +  def test_params_passing_with_fixnums_when_not_html_request +    get :test_params, :format => 'json', :count => 999 +    parsed_params = eval(@response.body) +    assert_equal( +      {'controller' => 'test_case_test/test', 'action' => 'test_params', +       'format' => 'json', 'count' => 999 }, +      parsed_params +    ) +  end + +  def test_params_passing_path_parameter_is_string_when_not_html_request +    get :test_params, :format => 'json', :id => 1 +    parsed_params = eval(@response.body) +    assert_equal( +      {'controller' => 'test_case_test/test', 'action' => 'test_params', +       'format' => 'json', 'id' => '1' }, +      parsed_params +    ) +  end +    def test_params_passing_with_frozen_values      assert_nothing_raised do -      get :test_params, :frozen => 'icy'.freeze, :frozens => ['icy'.freeze].freeze +      get :test_params, :frozen => 'icy'.freeze, :frozens => ['icy'.freeze].freeze, :deepfreeze => { :frozen => 'icy'.freeze }.freeze      end      parsed_params = eval(@response.body)      assert_equal(        {'controller' => 'test_case_test/test', 'action' => 'test_params', -       'frozen' => 'icy', 'frozens' => ['icy']}, +       'frozen' => 'icy', 'frozens' => ['icy'], 'deepfreeze' => { 'frozen' => 'icy' }},        parsed_params      )    end @@ -585,8 +629,8 @@ XML    def test_array_path_parameter_handled_properly      with_routing do |set|        set.draw do -        match 'file/*path', :to => 'test_case_test/test#test_params' -        match ':controller/:action' +        get 'file/*path', :to => 'test_case_test/test#test_params' +        get ':controller/:action'        end        get :test_params, :path => ['hello', 'world'] @@ -667,6 +711,20 @@ XML      assert_equal "http://", @response.body    end +  def test_request_format +    get :test_format, :format => 'html' +    assert_equal 'text/html', @response.body + +    get :test_format, :format => 'json' +    assert_equal 'application/json', @response.body + +    get :test_format, :format => 'xml' +    assert_equal 'application/xml', @response.body + +    get :test_format +    assert_equal 'text/html', @response.body +  end +    def test_should_have_knowledge_of_client_side_cookie_state_even_if_they_are_not_set      cookies['foo'] = 'bar'      get :no_op @@ -828,3 +886,24 @@ class NamedRoutesControllerTest < ActionController::TestCase      end    end  end + +class AnonymousControllerTest < ActionController::TestCase +  def setup +    @controller = Class.new(ActionController::Base) do +      def index +        render :text => params[:controller] +      end +    end.new + +    @routes = ActionDispatch::Routing::RouteSet.new.tap do |r| +      r.draw do +        get ':controller(/:action(/:id))' +      end +    end +  end + +  def test_controller_name +    get :index +    assert_equal 'anonymous', @response.body +  end +end
\ No newline at end of file diff --git a/actionpack/test/controller/url_for_integration_test.rb b/actionpack/test/controller/url_for_integration_test.rb index 451ea6027d..6c2311e7a5 100644 --- a/actionpack/test/controller/url_for_integration_test.rb +++ b/actionpack/test/controller/url_for_integration_test.rb @@ -18,7 +18,7 @@ module ActionPack          root :to => 'users#index'        end -      match '/blog(/:year(/:month(/:day)))' => 'posts#show_date', +      get '/blog(/:year(/:month(/:day)))' => 'posts#show_date',          :constraints => {            :year => /(19|20)\d\d/,            :month => /[01]?\d/, @@ -27,7 +27,7 @@ module ActionPack          :day => nil,          :month => nil -      match 'archive/:year', :controller => 'archive', :action => 'index', +      get 'archive/:year', :controller => 'archive', :action => 'index',          :defaults => { :year => nil },          :constraints => { :year => /\d{4}/ },          :as => "blog" @@ -35,29 +35,29 @@ module ActionPack        resources :people        #match 'legacy/people' => "people#index", :legacy => "true" -      match 'symbols', :controller => :symbols, :action => :show, :name => :as_symbol -      match 'id_default(/:id)' => "foo#id_default", :id => 1 +      get 'symbols', :controller => :symbols, :action => :show, :name => :as_symbol +      get 'id_default(/:id)' => "foo#id_default", :id => 1        match 'get_or_post' => "foo#get_or_post", :via => [:get, :post] -      match 'optional/:optional' => "posts#index" -      match 'projects/:project_id' => "project#index", :as => "project" -      match 'clients' => "projects#index" +      get 'optional/:optional' => "posts#index" +      get 'projects/:project_id' => "project#index", :as => "project" +      get 'clients' => "projects#index" -      match 'ignorecase/geocode/:postalcode' => 'geocode#show', :postalcode => /hx\d\d-\d[a-z]{2}/i -      match 'extended/geocode/:postalcode' => 'geocode#show',:constraints => { +      get 'ignorecase/geocode/:postalcode' => 'geocode#show', :postalcode => /hx\d\d-\d[a-z]{2}/i +      get 'extended/geocode/:postalcode' => 'geocode#show',:constraints => {          :postalcode => /# Postcode format          \d{5} #Prefix          (-\d{4})? #Suffix          /x        }, :as => "geocode" -      match 'news(.:format)' => "news#index" +      get 'news(.:format)' => "news#index" -      match 'comment/:id(/:action)' => "comments#show" -      match 'ws/:controller(/:action(/:id))', :ws => true -      match 'account(/:action)' => "account#subscription" -      match 'pages/:page_id/:controller(/:action(/:id))' -      match ':controller/ping', :action => 'ping' -      match ':controller(/:action(/:id))(.:format)' +      get 'comment/:id(/:action)' => "comments#show" +      get 'ws/:controller(/:action(/:id))', :ws => true +      get 'account(/:action)' => "account#subscription" +      get 'pages/:page_id/:controller(/:action(/:id))' +      get ':controller/ping', :action => 'ping' +      get ':controller(/:action(/:id))(.:format)'        root :to => "news#index"      } diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb index aa233d6135..b2cb5f80d5 100644 --- a/actionpack/test/controller/url_for_test.rb +++ b/actionpack/test/controller/url_for_test.rb @@ -5,7 +5,7 @@ module AbstractController      class UrlForTests < ActionController::TestCase        class W -        include ActionDispatch::Routing::RouteSet.new.tap { |r| r.draw { match ':controller(/:action(/:id(.:format)))' } }.url_helpers +        include ActionDispatch::Routing::RouteSet.new.tap { |r| r.draw { get ':controller(/:action(/:id(.:format)))' } }.url_helpers        end        def teardown @@ -210,8 +210,8 @@ module AbstractController        def test_named_routes          with_routing do |set|            set.draw do -            match 'this/is/verbose', :to => 'home#index', :as => :no_args -            match 'home/sweet/home/:user', :to => 'home#index', :as => :home +            get 'this/is/verbose', :to => 'home#index', :as => :no_args +            get 'home/sweet/home/:user', :to => 'home#index', :as => :home            end            # We need to create a new class in order to install the new named route. @@ -231,7 +231,7 @@ module AbstractController        def test_relative_url_root_is_respected_for_named_routes          with_routing do |set|            set.draw do -            match '/home/sweet/home/:user', :to => 'home#index', :as => :home +            get '/home/sweet/home/:user', :to => 'home#index', :as => :home            end            kls = Class.new { include set.url_helpers } @@ -245,8 +245,8 @@ module AbstractController        def test_only_path          with_routing do |set|            set.draw do -            match 'home/sweet/home/:user', :to => 'home#index', :as => :home -            match ':controller/:action/:id' +            get 'home/sweet/home/:user', :to => 'home#index', :as => :home +            get ':controller/:action/:id'            end            # We need to create a new class in order to install the new named route. @@ -313,8 +313,8 @@ module AbstractController        def test_named_routes_with_nil_keys          with_routing do |set|            set.draw do -            match 'posts.:format', :to => 'posts#index', :as => :posts -            match '/', :to => 'posts#index', :as => :main +            get 'posts.:format', :to => 'posts#index', :as => :posts +            get '/', :to => 'posts#index', :as => :main            end            # We need to create a new class in order to install the new named route. diff --git a/actionpack/test/controller/url_rewriter_test.rb b/actionpack/test/controller/url_rewriter_test.rb index f88903b10e..cc3706aeee 100644 --- a/actionpack/test/controller/url_rewriter_test.rb +++ b/actionpack/test/controller/url_rewriter_test.rb @@ -21,7 +21,7 @@ class UrlRewriterTests < ActionController::TestCase      @rewriter = Rewriter.new(@request) #.new(@request, @params)      @routes = ActionDispatch::Routing::RouteSet.new.tap do |r|        r.draw do -        match ':controller(/:action(/:id))' +        get ':controller(/:action(/:id))'        end      end    end diff --git a/actionpack/test/controller/webservice_test.rb b/actionpack/test/controller/webservice_test.rb index 351e61eeae..c0b9833603 100644 --- a/actionpack/test/controller/webservice_test.rb +++ b/actionpack/test/controller/webservice_test.rb @@ -254,7 +254,7 @@ class WebServiceTest < ActionDispatch::IntegrationTest      def with_test_route_set        with_routing do |set|          set.draw do -          match '/', :to => 'web_service_test/test#assign_parameters' +          match '/', :to => 'web_service_test/test#assign_parameters', :via => :all          end          yield        end diff --git a/actionpack/test/dispatch/mapper_test.rb b/actionpack/test/dispatch/mapper_test.rb index d3465589c1..bd078d2b21 100644 --- a/actionpack/test/dispatch/mapper_test.rb +++ b/actionpack/test/dispatch/mapper_test.rb @@ -4,11 +4,12 @@ module ActionDispatch    module Routing      class MapperTest < ActiveSupport::TestCase        class FakeSet -        attr_reader :routes +        attr_reader :routes, :draw_paths          alias :set :routes          def initialize            @routes = [] +          @draw_paths = []          end          def resources_path_names @@ -37,7 +38,7 @@ module ActionDispatch        end        def test_mapping_requirements -        options = { :controller => 'foo', :action => 'bar' } +        options = { :controller => 'foo', :action => 'bar', :via => :get }          m = Mapper::Mapping.new FakeSet.new, {}, '/store/:name(*rest)', options          _, _, requirements, _ = m.to_route          assert_equal(/.+?/, requirements[:rest]) @@ -46,7 +47,7 @@ module ActionDispatch        def test_map_slash          fakeset = FakeSet.new          mapper = Mapper.new fakeset -        mapper.match '/', :to => 'posts#index', :as => :main +        mapper.get '/', :to => 'posts#index', :as => :main          assert_equal '/', fakeset.conditions.first[:path_info]        end @@ -55,14 +56,14 @@ module ActionDispatch          mapper = Mapper.new fakeset          # FIXME: is this a desired behavior? -        mapper.match '/one/two/', :to => 'posts#index', :as => :main +        mapper.get '/one/two/', :to => 'posts#index', :as => :main          assert_equal '/one/two(.:format)', fakeset.conditions.first[:path_info]        end        def test_map_wildcard          fakeset = FakeSet.new          mapper = Mapper.new fakeset -        mapper.match '/*path', :to => 'pages#show' +        mapper.get '/*path', :to => 'pages#show'          assert_equal '/*path(.:format)', fakeset.conditions.first[:path_info]          assert_equal(/.+?/, fakeset.requirements.first[:path])        end @@ -70,7 +71,7 @@ module ActionDispatch        def test_map_wildcard_with_other_element          fakeset = FakeSet.new          mapper = Mapper.new fakeset -        mapper.match '/*path/foo/:bar', :to => 'pages#show' +        mapper.get '/*path/foo/:bar', :to => 'pages#show'          assert_equal '/*path/foo/:bar(.:format)', fakeset.conditions.first[:path_info]          assert_nil fakeset.requirements.first[:path]        end @@ -78,7 +79,7 @@ module ActionDispatch        def test_map_wildcard_with_multiple_wildcard          fakeset = FakeSet.new          mapper = Mapper.new fakeset -        mapper.match '/*foo/*bar', :to => 'pages#show' +        mapper.get '/*foo/*bar', :to => 'pages#show'          assert_equal '/*foo/*bar(.:format)', fakeset.conditions.first[:path_info]          assert_nil fakeset.requirements.first[:foo]          assert_equal(/.+?/, fakeset.requirements.first[:bar]) @@ -87,7 +88,7 @@ module ActionDispatch        def test_map_wildcard_with_format_false          fakeset = FakeSet.new          mapper = Mapper.new fakeset -        mapper.match '/*path', :to => 'pages#show', :format => false +        mapper.get '/*path', :to => 'pages#show', :format => false          assert_equal '/*path', fakeset.conditions.first[:path_info]          assert_nil fakeset.requirements.first[:path]        end @@ -95,7 +96,7 @@ module ActionDispatch        def test_map_wildcard_with_format_true          fakeset = FakeSet.new          mapper = Mapper.new fakeset -        mapper.match '/*path', :to => 'pages#show', :format => true +        mapper.get '/*path', :to => 'pages#show', :format => true          assert_equal '/*path.:format', fakeset.conditions.first[:path_info]        end      end diff --git a/actionpack/test/dispatch/prefix_generation_test.rb b/actionpack/test/dispatch/prefix_generation_test.rb index bd5b5edab0..ab2f7612ce 100644 --- a/actionpack/test/dispatch/prefix_generation_test.rb +++ b/actionpack/test/dispatch/prefix_generation_test.rb @@ -25,12 +25,12 @@ module TestGenerationPrefix          @routes ||= begin            routes = ActionDispatch::Routing::RouteSet.new            routes.draw do -            match "/posts/:id", :to => "inside_engine_generating#show", :as => :post -            match "/posts", :to => "inside_engine_generating#index", :as => :posts -            match "/url_to_application", :to => "inside_engine_generating#url_to_application" -            match "/polymorphic_path_for_engine", :to => "inside_engine_generating#polymorphic_path_for_engine" -            match "/conflicting_url", :to => "inside_engine_generating#conflicting" -            match "/foo", :to => "never#invoked", :as => :named_helper_that_should_be_invoked_only_in_respond_to_test +            get "/posts/:id", :to => "inside_engine_generating#show", :as => :post +            get "/posts", :to => "inside_engine_generating#index", :as => :posts +            get "/url_to_application", :to => "inside_engine_generating#url_to_application" +            get "/polymorphic_path_for_engine", :to => "inside_engine_generating#polymorphic_path_for_engine" +            get "/conflicting_url", :to => "inside_engine_generating#conflicting" +            get "/foo", :to => "never#invoked", :as => :named_helper_that_should_be_invoked_only_in_respond_to_test            end            routes @@ -51,12 +51,12 @@ module TestGenerationPrefix              scope "/:omg", :omg => "awesome" do                mount BlogEngine => "/blog", :as => "blog_engine"              end -            match "/posts/:id", :to => "outside_engine_generating#post", :as => :post -            match "/generate", :to => "outside_engine_generating#index" -            match "/polymorphic_path_for_app", :to => "outside_engine_generating#polymorphic_path_for_app" -            match "/polymorphic_path_for_engine", :to => "outside_engine_generating#polymorphic_path_for_engine" -            match "/polymorphic_with_url_for", :to => "outside_engine_generating#polymorphic_with_url_for" -            match "/conflicting_url", :to => "outside_engine_generating#conflicting" +            get "/posts/:id", :to => "outside_engine_generating#post", :as => :post +            get "/generate", :to => "outside_engine_generating#index" +            get "/polymorphic_path_for_app", :to => "outside_engine_generating#polymorphic_path_for_app" +            get "/polymorphic_path_for_engine", :to => "outside_engine_generating#polymorphic_path_for_engine" +            get "/polymorphic_with_url_for", :to => "outside_engine_generating#polymorphic_with_url_for" +            get "/conflicting_url", :to => "outside_engine_generating#conflicting"              root :to => "outside_engine_generating#index"            end @@ -282,7 +282,7 @@ module TestGenerationPrefix          @routes ||= begin            routes = ActionDispatch::Routing::RouteSet.new            routes.draw do -            match "/posts/:id", :to => "posts#show", :as => :post +            get "/posts/:id", :to => "posts#show", :as => :post            end            routes diff --git a/actionpack/test/dispatch/request/json_params_parsing_test.rb b/actionpack/test/dispatch/request/json_params_parsing_test.rb index ae425dd406..302bff0696 100644 --- a/actionpack/test/dispatch/request/json_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/json_params_parsing_test.rb @@ -65,7 +65,7 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest      def with_test_routing        with_routing do |set|          set.draw do -          match ':action', :to => ::JsonParamsParsingTest::TestController +          post ':action', :to => ::JsonParamsParsingTest::TestController          end          yield        end @@ -118,7 +118,7 @@ class RootLessJSONParamsParsingTest < ActionDispatch::IntegrationTest      def with_test_routing(controller)        with_routing do |set|          set.draw do -          match ':action', :to => controller +          post ':action', :to => controller          end          yield        end diff --git a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb index d144f013f5..63c5ea26a6 100644 --- a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb @@ -144,7 +144,7 @@ class MultipartParamsParsingTest < ActionDispatch::IntegrationTest      def with_test_routing        with_routing do |set|          set.draw do -          match ':action', :to => 'multipart_params_parsing_test/test' +          post ':action', :to => 'multipart_params_parsing_test/test'          end          yield        end diff --git a/actionpack/test/dispatch/request/query_string_parsing_test.rb b/actionpack/test/dispatch/request/query_string_parsing_test.rb index f6a1475d04..d14f188e30 100644 --- a/actionpack/test/dispatch/request/query_string_parsing_test.rb +++ b/actionpack/test/dispatch/request/query_string_parsing_test.rb @@ -109,7 +109,7 @@ class QueryStringParsingTest < ActionDispatch::IntegrationTest      def assert_parses(expected, actual)        with_routing do |set|          set.draw do -          match ':action', :to => ::QueryStringParsingTest::TestController +          get ':action', :to => ::QueryStringParsingTest::TestController          end          get "/parse", actual diff --git a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb index 05569561d2..568e220b15 100644 --- a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb @@ -130,7 +130,7 @@ class UrlEncodedParamsParsingTest < ActionDispatch::IntegrationTest      def with_test_routing        with_routing do |set|          set.draw do -          match ':action', :to => ::UrlEncodedParamsParsingTest::TestController +          post ':action', :to => ::UrlEncodedParamsParsingTest::TestController          end          yield        end diff --git a/actionpack/test/dispatch/request/xml_params_parsing_test.rb b/actionpack/test/dispatch/request/xml_params_parsing_test.rb index afd400c2a9..84823e2896 100644 --- a/actionpack/test/dispatch/request/xml_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/xml_params_parsing_test.rb @@ -106,7 +106,7 @@ class XmlParamsParsingTest < ActionDispatch::IntegrationTest      def with_test_routing        with_routing do |set|          set.draw do -          match ':action', :to => ::XmlParamsParsingTest::TestController +          post ':action', :to => ::XmlParamsParsingTest::TestController          end          yield        end @@ -155,7 +155,7 @@ class RootLessXmlParamsParsingTest < ActionDispatch::IntegrationTest      def with_test_routing        with_routing do |set|          set.draw do -          match ':action', :to => ::RootLessXmlParamsParsingTest::TestController +          post ':action', :to => ::RootLessXmlParamsParsingTest::TestController          end          yield        end diff --git a/actionpack/test/dispatch/request_id_test.rb b/actionpack/test/dispatch/request_id_test.rb index 4b98cd32f2..a8050b4fab 100644 --- a/actionpack/test/dispatch/request_id_test.rb +++ b/actionpack/test/dispatch/request_id_test.rb @@ -52,7 +52,7 @@ class RequestIdResponseTest < ActionDispatch::IntegrationTest    def with_test_route_set      with_routing do |set|        set.draw do -        match '/', :to => ::RequestIdResponseTest::TestController.action(:index) +        get '/', :to => ::RequestIdResponseTest::TestController.action(:index)        end        @app = self.class.build_app(set) do |middleware| @@ -62,4 +62,4 @@ class RequestIdResponseTest < ActionDispatch::IntegrationTest        yield      end    end -end
\ No newline at end of file +end diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb index 6c8b22c47f..94d0e09842 100644 --- a/actionpack/test/dispatch/request_test.rb +++ b/actionpack/test/dispatch/request_test.rb @@ -35,37 +35,40 @@ class RequestTest < ActiveSupport::TestCase      assert_equal '1.2.3.4', request.remote_ip      request = stub_request 'REMOTE_ADDR' => '1.2.3.4', -      'HTTP_X_FORWARDED_FOR' => '3.4.5.6' +                           'HTTP_X_FORWARDED_FOR' => '3.4.5.6'      assert_equal '3.4.5.6', request.remote_ip      request = stub_request 'REMOTE_ADDR' => '127.0.0.1', -      'HTTP_X_FORWARDED_FOR' => '3.4.5.6' +                           'HTTP_X_FORWARDED_FOR' => '3.4.5.6'      assert_equal '3.4.5.6', request.remote_ip      request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6,unknown'      assert_equal '3.4.5.6', request.remote_ip      request = stub_request 'HTTP_X_FORWARDED_FOR' => '172.16.0.1,3.4.5.6' -    assert_equal '3.4.5.6', request.remote_ip +    assert_equal nil, request.remote_ip      request = stub_request 'HTTP_X_FORWARDED_FOR' => '192.168.0.1,3.4.5.6' -    assert_equal '3.4.5.6', request.remote_ip +    assert_equal nil, request.remote_ip      request = stub_request 'HTTP_X_FORWARDED_FOR' => '10.0.0.1,3.4.5.6' -    assert_equal '3.4.5.6', request.remote_ip +    assert_equal nil, request.remote_ip      request = stub_request 'HTTP_X_FORWARDED_FOR' => '10.0.0.1, 10.0.0.1, 3.4.5.6' -    assert_equal '3.4.5.6', request.remote_ip +    assert_equal nil, request.remote_ip      request = stub_request 'HTTP_X_FORWARDED_FOR' => '127.0.0.1,3.4.5.6' -    assert_equal '3.4.5.6', request.remote_ip +    assert_equal nil, request.remote_ip      request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,192.168.0.1' -    assert_equal 'unknown', request.remote_ip +    assert_equal nil, request.remote_ip      request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6, 9.9.9.9, 10.0.0.1, 172.31.4.4'      assert_equal '3.4.5.6', request.remote_ip +    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'not_ip_address' +    assert_equal nil, request.remote_ip +      request = stub_request 'HTTP_X_FORWARDED_FOR' => '1.1.1.1',                             'HTTP_CLIENT_IP'       => '2.2.2.2'      e = assert_raise(ActionDispatch::RemoteIp::IpSpoofAttackError) { @@ -89,6 +92,68 @@ class RequestTest < ActiveSupport::TestCase      assert_equal '9.9.9.9', request.remote_ip    end +  test "remote ip v6" do +    request = stub_request 'REMOTE_ADDR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334' +    assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip + +    request = stub_request 'REMOTE_ADDR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334,fe80:0000:0000:0000:0202:b3ff:fe1e:8329' +    assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip + +    request = stub_request 'REMOTE_ADDR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334', +                           'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329' +    assert_equal 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip + +    request = stub_request 'REMOTE_ADDR' => '::1', +                           'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329' +    assert_equal 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip + +    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,fe80:0000:0000:0000:0202:b3ff:fe1e:8329' +    assert_equal nil, request.remote_ip + +    request = stub_request 'HTTP_X_FORWARDED_FOR' => '::1,fe80:0000:0000:0000:0202:b3ff:fe1e:8329' +    assert_equal nil, request.remote_ip + +    request = stub_request 'HTTP_X_FORWARDED_FOR' => '::1,fe80:0000:0000:0000:0202:b3ff:fe1e:8329' +    assert_equal nil, request.remote_ip + +    request = stub_request 'HTTP_X_FORWARDED_FOR' => '::1,fe80:0000:0000:0000:0202:b3ff:fe1e:8329' +    assert_equal nil, request.remote_ip + +    request = stub_request 'HTTP_X_FORWARDED_FOR' => '::1, ::1, fe80:0000:0000:0000:0202:b3ff:fe1e:8329' +    assert_equal nil, request.remote_ip + +    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,::1' +    assert_equal nil, request.remote_ip + +    request = stub_request 'HTTP_X_FORWARDED_FOR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334, fe80:0000:0000:0000:0202:b3ff:fe1e:8329, ::1, fc00::' +    assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip + +    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'not_ip_address' +    assert_equal nil, request.remote_ip + +    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', +                           'HTTP_CLIENT_IP'       => '2001:0db8:85a3:0000:0000:8a2e:0370:7334' +    e = assert_raise(ActionDispatch::RemoteIp::IpSpoofAttackError) { +      request.remote_ip +    } +    assert_match(/IP spoofing attack/, e.message) +    assert_match(/HTTP_X_FORWARDED_FOR="fe80:0000:0000:0000:0202:b3ff:fe1e:8329"/, e.message) +    assert_match(/HTTP_CLIENT_IP="2001:0db8:85a3:0000:0000:8a2e:0370:7334"/, e.message) + +    # Turn IP Spoofing detection off. +    # This is useful for sites that are aimed at non-IP clients.  The typical +    # example is WAP.  Since the cellular network is not IP based, it's a +    # leap of faith to assume that their proxies are ever going to set the +    # HTTP_CLIENT_IP/HTTP_X_FORWARDED_FOR headers properly. +    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', +                           'HTTP_CLIENT_IP'       => '2001:0db8:85a3:0000:0000:8a2e:0370:7334', +                           :ip_spoofing_check     => false +    assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip + +    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329, 2001:0db8:85a3:0000:0000:8a2e:0370:7334' +    assert_equal 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip +  end +    test "remote ip when the remote ip middleware returns nil" do      request = stub_request 'REMOTE_ADDR' => '127.0.0.1'      assert_equal '127.0.0.1', request.remote_ip @@ -97,29 +162,47 @@ class RequestTest < ActiveSupport::TestCase    test "remote ip with user specified trusted proxies String" do      @trusted_proxies = "67.205.106.73" -    request = stub_request 'REMOTE_ADDR' => '67.205.106.73', -                           'HTTP_X_FORWARDED_FOR' => '3.4.5.6' +    request = stub_request 'REMOTE_ADDR' => '3.4.5.6', +                           'HTTP_X_FORWARDED_FOR' => '67.205.106.73'      assert_equal '3.4.5.6', request.remote_ip      request = stub_request 'REMOTE_ADDR' => '172.16.0.1,67.205.106.73', -                           'HTTP_X_FORWARDED_FOR' => '3.4.5.6' -    assert_equal '3.4.5.6', request.remote_ip +                           'HTTP_X_FORWARDED_FOR' => '67.205.106.73' +    assert_equal '172.16.0.1', request.remote_ip -    request = stub_request 'REMOTE_ADDR' => '67.205.106.73,172.16.0.1', -                           'HTTP_X_FORWARDED_FOR' => '3.4.5.6' -    assert_equal '3.4.5.6', request.remote_ip - -    request = stub_request 'REMOTE_ADDR' => '67.205.106.74,172.16.0.1', -                           'HTTP_X_FORWARDED_FOR' => '3.4.5.6' +    request = stub_request 'REMOTE_ADDR' => '67.205.106.73,3.4.5.6', +                           'HTTP_X_FORWARDED_FOR' => '67.205.106.73'      assert_equal '3.4.5.6', request.remote_ip      request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,67.205.106.73' -    assert_equal 'unknown', request.remote_ip +    assert_equal nil, request.remote_ip      request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6, 9.9.9.9, 10.0.0.1, 67.205.106.73'      assert_equal '3.4.5.6', request.remote_ip    end +  test "remote ip v6 with user specified trusted proxies String" do +    @trusted_proxies = 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329' + +    request = stub_request 'REMOTE_ADDR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334', +                           'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329' +    assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip + +    request = stub_request 'REMOTE_ADDR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329,2001:0db8:85a3:0000:0000:8a2e:0370:7334', +                           'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329' +    assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip + +    request = stub_request 'REMOTE_ADDR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329,::1', +                           'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329' +    assert_equal 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip + +    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,fe80:0000:0000:0000:0202:b3ff:fe1e:8329' +    assert_equal nil, request.remote_ip + +    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329,2001:0db8:85a3:0000:0000:8a2e:0370:7334' +    assert_equal nil, request.remote_ip +  end +    test "remote ip with user specified trusted proxies Regexp" do      @trusted_proxies = /^67\.205\.106\.73$/i @@ -128,7 +211,18 @@ class RequestTest < ActiveSupport::TestCase      assert_equal '3.4.5.6', request.remote_ip      request = stub_request 'HTTP_X_FORWARDED_FOR' => '67.205.106.73, 10.0.0.1, 9.9.9.9, 3.4.5.6' -    assert_equal '10.0.0.1', request.remote_ip +    assert_equal nil, request.remote_ip +  end + +  test "remote ip v6 with user specified trusted proxies Regexp" do +    @trusted_proxies = /^fe80:0000:0000:0000:0202:b3ff:fe1e:8329$/i + +    request = stub_request 'REMOTE_ADDR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334', +                           'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329' +    assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip + +    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329, 2001:0db8:85a3:0000:0000:8a2e:0370:7334' +    assert_equal nil, request.remote_ip    end    test "domains" do diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index cc4279d9dd..4b8d308043 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -58,41 +58,46 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest          get  "remove", :action => :destroy, :as => :remove        end -      match 'account/logout' => redirect("/logout"), :as => :logout_redirect -      match 'account/login', :to => redirect("/login") -      match 'secure', :to => redirect("/secure/login") +      get 'account/logout' => redirect("/logout"), :as => :logout_redirect +      get 'account/login', :to => redirect("/login") +      get 'secure', :to => redirect("/secure/login") -      match 'mobile', :to => redirect(:subdomain => 'mobile') -      match 'super_new_documentation', :to => redirect(:host => 'super-docs.com') +      get 'mobile', :to => redirect(:subdomain => 'mobile') +      get 'documentation', :to => redirect(:domain => 'example-documentation.com', :path => '') +      get 'new_documentation', :to => redirect(:path => '/documentation/new') +      get 'super_new_documentation', :to => redirect(:host => 'super-docs.com') -      match 'youtube_favorites/:youtube_id/:name', :to => redirect(YoutubeFavoritesRedirector) +      get 'stores/:name',        :to => redirect(:subdomain => 'stores', :path => '/%{name}') +      get 'stores/:name(*rest)', :to => redirect(:subdomain => 'stores', :path => '/%{name}%{rest}') + +      get 'youtube_favorites/:youtube_id/:name', :to => redirect(YoutubeFavoritesRedirector)        constraints(lambda { |req| true }) do -        match 'account/overview' +        get 'account/overview'        end -      match '/account/nested/overview' -      match 'sign_in' => "sessions#new" +      get '/account/nested/overview' +      get 'sign_in' => "sessions#new" -      match 'account/modulo/:name', :to => redirect("/%{name}s") -      match 'account/proc/:name', :to => redirect {|params, req| "/#{params[:name].pluralize}" } -      match 'account/proc_req' => redirect {|params, req| "/#{req.method}" } +      get 'account/modulo/:name', :to => redirect("/%{name}s") +      get 'account/proc/:name', :to => redirect {|params, req| "/#{params[:name].pluralize}" } +      get 'account/proc_req' => redirect {|params, req| "/#{req.method}" } -      match 'account/google' => redirect('http://www.google.com/', :status => 302) +      get 'account/google' => redirect('http://www.google.com/', :status => 302)        match 'openid/login', :via => [:get, :post], :to => "openid#login"        controller(:global) do          get   'global/hide_notice' -        match 'global/export',      :to => :export, :as => :export_request -        match '/export/:id/:file',  :to => :export, :as => :export_download, :constraints => { :file => /.*/ } -        match 'global/:action' +        get 'global/export',      :to => :export, :as => :export_request +        get '/export/:id/:file',  :to => :export, :as => :export_download, :constraints => { :file => /.*/ } +        get 'global/:action'        end -      match "/local/:action", :controller => "local" +      get "/local/:action", :controller => "local" -      match "/projects/status(.:format)" -      match "/404", :to => lambda { |env| [404, {"Content-Type" => "text/plain"}, ["NOT FOUND"]] } +      get "/projects/status(.:format)" +      get "/404", :to => lambda { |env| [404, {"Content-Type" => "text/plain"}, ["NOT FOUND"]] }        constraints(:ip => /192\.168\.1\.\d\d\d/) do          get 'admin' => "queenbee#index" @@ -277,25 +282,25 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest          end        end -      match 'sprockets.js' => ::TestRoutingMapper::SprocketsApp +      get 'sprockets.js' => ::TestRoutingMapper::SprocketsApp -      match 'people/:id/update', :to => 'people#update', :as => :update_person -      match '/projects/:project_id/people/:id/update', :to => 'people#update', :as => :update_project_person +      get 'people/:id/update', :to => 'people#update', :as => :update_person +      get '/projects/:project_id/people/:id/update', :to => 'people#update', :as => :update_project_person        # misc -      match 'articles/:year/:month/:day/:title', :to => "articles#show", :as => :article +      get 'articles/:year/:month/:day/:title', :to => "articles#show", :as => :article        # default params -      match 'inline_pages/(:id)', :to => 'pages#show', :id => 'home' -      match 'default_pages/(:id)', :to => 'pages#show', :defaults => { :id => 'home' } +      get 'inline_pages/(:id)', :to => 'pages#show', :id => 'home' +      get 'default_pages/(:id)', :to => 'pages#show', :defaults => { :id => 'home' }        defaults :id => 'home' do -        match 'scoped_pages/(:id)', :to => 'pages#show' +        get 'scoped_pages/(:id)', :to => 'pages#show'        end        namespace :account do -        match 'shorthand' -        match 'description', :to => :description, :as => "description" -        match ':action/callback', :action => /twitter|github/, :to => "callbacks", :as => :callback +        get 'shorthand' +        get 'description', :to => :description, :as => "description" +        get ':action/callback', :action => /twitter|github/, :to => "callbacks", :as => :callback          resource :subscription, :credit, :credit_card          root :to => "account#index" @@ -318,7 +323,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest        controller :articles do          scope '/articles', :as => 'article' do            scope :path => '/:title', :title => /[a-z]+/, :as => :with_title do -            match '/:id', :to => :with_id, :as => "" +            get '/:id', :to => :with_id, :as => ""            end          end        end @@ -327,7 +332,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest          resources :rooms        end -      match '/info' => 'projects#info', :as => 'info' +      get '/info' => 'projects#info', :as => 'info'        namespace :admin do          scope '(:locale)', :locale => /en|pl/ do @@ -361,7 +366,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest        scope :path => 'api' do          resource :me -        match '/' => 'mes#index' +        get '/' => 'mes#index'        end        get "(/:username)/followers" => "followers#index" @@ -374,7 +379,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest          end        end -      match "whatever/:controller(/:action(/:id))", :id => /\d+/ +      get "whatever/:controller(/:action(/:id))", :id => /\d+/        resource :profile do          get :settings @@ -407,7 +412,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest        namespace :private do          root :to => redirect('/private/index') -        match "index", :to => 'private#index' +        get "index", :to => 'private#index'        end        scope :only => [:index, :show] do @@ -489,7 +494,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest          get "/forced_collision", :as => :forced_collision, :to => "forced_collision#show"        end -      match '/purchases/:token/:filename', +      get '/purchases/:token/:filename',          :to => 'purchases#fetch',          :token => /[[:alnum:]]{10}/,          :filename => /(.+)/, @@ -500,18 +505,18 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest        end        scope '/countries/:country', :constraints => lambda { |params, req| params[:country].in?(["all", "France"]) } do -        match '/',       :to => 'countries#index' -        match '/cities', :to => 'countries#cities' +        get '/',       :to => 'countries#index' +        get '/cities', :to => 'countries#cities'        end -      match '/countries/:country/(*other)', :to => redirect{ |params, req| params[:other] ? "/countries/all/#{params[:other]}" : '/countries/all' } +      get '/countries/:country/(*other)', :to => redirect{ |params, req| params[:other] ? "/countries/all/#{params[:other]}" : '/countries/all' } -      match '/:locale/*file.:format', :to => 'files#show', :file => /path\/to\/existing\/file/ +      get '/:locale/*file.:format', :to => 'files#show', :file => /path\/to\/existing\/file/        scope '/italians' do -        match '/writers', :to => 'italians#writers', :constraints => ::TestRoutingMapper::IpRestrictor -        match '/sculptors', :to => 'italians#sculptors' -        match '/painters/:painter', :to => 'italians#painters', :constraints => {:painter => /michelangelo/} +        get '/writers', :to => 'italians#writers', :constraints => ::TestRoutingMapper::IpRestrictor +        get '/sculptors', :to => 'italians#sculptors' +        get '/painters/:painter', :to => 'italians#painters', :constraints => {:painter => /michelangelo/}        end      end    end @@ -627,7 +632,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest        self.class.stub_controllers do |routes|          routes.draw do            namespace :admin do -            match '/:controller(/:action(/:id(.:format)))' +            get '/:controller(/:action(/:id(.:format)))'            end          end        end @@ -693,11 +698,31 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest      verify_redirect 'http://mobile.example.com/mobile'    end +  def test_redirect_hash_with_domain_and_path +    get '/documentation' +    verify_redirect 'http://www.example-documentation.com' +  end + +  def test_redirect_hash_with_path +    get '/new_documentation' +    verify_redirect 'http://www.example.com/documentation/new' +  end +    def test_redirect_hash_with_host      get '/super_new_documentation?section=top'      verify_redirect 'http://super-docs.com/super_new_documentation?section=top'    end +  def test_redirect_hash_path_substitution +    get '/stores/iernest' +    verify_redirect 'http://stores.example.com/iernest' +  end + +  def test_redirect_hash_path_substitution_with_catch_all +    get '/stores/iernest/products' +    verify_redirect 'http://stores.example.com/iernest/products' +  end +    def test_redirect_class      get '/youtube_favorites/oHg5SJYRHA0/rick-rolld'      verify_redirect 'http://www.youtube.com/watch?v=oHg5SJYRHA0' @@ -2231,12 +2256,12 @@ class TestAppendingRoutes < ActionDispatch::IntegrationTest      s = self      @app = ActionDispatch::Routing::RouteSet.new      @app.append do -      match '/hello'   => s.simple_app('fail') -      match '/goodbye' => s.simple_app('goodbye') +      get '/hello'   => s.simple_app('fail') +      get '/goodbye' => s.simple_app('goodbye')      end      @app.draw do -      match '/hello' => s.simple_app('hello') +      get '/hello' => s.simple_app('hello')      end    end @@ -2344,12 +2369,12 @@ end  class TestUriPathEscaping < ActionDispatch::IntegrationTest    Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|      app.draw do -      match '/:segment' => lambda { |env| +      get '/:segment' => lambda { |env|          path_params = env['action_dispatch.request.path_parameters']          [200, { 'Content-Type' => 'text/plain' }, [path_params[:segment]]]        }, :as => :segment -      match '/*splat' => lambda { |env| +      get '/*splat' => lambda { |env|          path_params = env['action_dispatch.request.path_parameters']          [200, { 'Content-Type' => 'text/plain' }, [path_params[:splat]]]        }, :as => :splat @@ -2381,7 +2406,7 @@ end  class TestUnicodePaths < ActionDispatch::IntegrationTest    Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|      app.draw do -      match "/#{Rack::Utils.escape("ほげ")}" => lambda { |env| +      get "/#{Rack::Utils.escape("ほげ")}" => lambda { |env|          [200, { 'Content-Type' => 'text/plain' }, []]        }, :as => :unicode_path      end @@ -2411,10 +2436,10 @@ class TestMultipleNestedController < ActionDispatch::IntegrationTest      app.draw do        namespace :foo do          namespace :bar do -          match "baz" => "baz#index" +          get "baz" => "baz#index"          end        end -      match "pooh" => "pooh#index" +      get "pooh" => "pooh#index"      end    end @@ -2433,8 +2458,8 @@ class TestTildeAndMinusPaths < ActionDispatch::IntegrationTest      app.draw do        ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] } -      match "/~user" => ok -      match "/young-and-fine" => ok +      get "/~user" => ok +      get "/young-and-fine" => ok      end    end @@ -2452,3 +2477,38 @@ class TestTildeAndMinusPaths < ActionDispatch::IntegrationTest    end  end + +class TestRedirectInterpolation < ActionDispatch::IntegrationTest +  Routes = ActionDispatch::Routing::RouteSet.new.tap do |app| +    app.draw do +      ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] } + +      get "/foo/:id" => redirect("/foo/bar/%{id}") +      get "/bar/:id" => redirect(:path => "/foo/bar/%{id}") +      get "/foo/bar/:id" => ok +    end +  end + +  def app; Routes end + +  test "redirect escapes interpolated parameters with redirect proc" do +    get "/foo/1%3E" +    verify_redirect "http://www.example.com/foo/bar/1%3E" +  end + +  test "redirect escapes interpolated parameters with option proc" do +    get "/bar/1%3E" +    verify_redirect "http://www.example.com/foo/bar/1%3E" +  end + +private +  def verify_redirect(url, status=301) +    assert_equal status, @response.status +    assert_equal url, @response.headers['Location'] +    assert_equal expected_redirect_body(url), @response.body +  end + +  def expected_redirect_body(url) +    %(<html><body>You are being <a href="#{ERB::Util.h(url)}">redirected</a>.</body></html>) +  end +end diff --git a/actionpack/test/dispatch/session/cache_store_test.rb b/actionpack/test/dispatch/session/cache_store_test.rb index 12405bf45d..a74e165826 100644 --- a/actionpack/test/dispatch/session/cache_store_test.rb +++ b/actionpack/test/dispatch/session/cache_store_test.rb @@ -164,7 +164,7 @@ class CacheStoreTest < ActionDispatch::IntegrationTest      def with_test_route_set        with_routing do |set|          set.draw do -          match ':action', :to => ::CacheStoreTest::TestController +          get ':action', :to => ::CacheStoreTest::TestController          end          @app = self.class.build_app(set) do |middleware| diff --git a/actionpack/test/dispatch/session/cookie_store_test.rb b/actionpack/test/dispatch/session/cookie_store_test.rb index 19969394cd..631974d6c4 100644 --- a/actionpack/test/dispatch/session/cookie_store_test.rb +++ b/actionpack/test/dispatch/session/cookie_store_test.rb @@ -317,7 +317,7 @@ class CookieStoreTest < ActionDispatch::IntegrationTest      def with_test_route_set(options = {})        with_routing do |set|          set.draw do -          match ':action', :to => ::CookieStoreTest::TestController +          get ':action', :to => ::CookieStoreTest::TestController          end          options = { :key => SessionKey }.merge!(options) diff --git a/actionpack/test/dispatch/session/mem_cache_store_test.rb b/actionpack/test/dispatch/session/mem_cache_store_test.rb index 5277c92b55..03234612ab 100644 --- a/actionpack/test/dispatch/session/mem_cache_store_test.rb +++ b/actionpack/test/dispatch/session/mem_cache_store_test.rb @@ -173,7 +173,7 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest      def with_test_route_set        with_routing do |set|          set.draw do -          match ':action', :to => ::MemCacheStoreTest::TestController +          get ':action', :to => ::MemCacheStoreTest::TestController          end          @app = self.class.build_app(set) do |middleware| diff --git a/actionpack/test/dispatch/url_generation_test.rb b/actionpack/test/dispatch/url_generation_test.rb index 2b54bc62b0..985ff2e81a 100644 --- a/actionpack/test/dispatch/url_generation_test.rb +++ b/actionpack/test/dispatch/url_generation_test.rb @@ -3,7 +3,7 @@ require 'abstract_unit'  module TestUrlGeneration    class WithMountPoint < ActionDispatch::IntegrationTest      Routes = ActionDispatch::Routing::RouteSet.new -    Routes.draw { match "/foo", :to => "my_route_generating#index", :as => :foo } +    Routes.draw { get "/foo", :to => "my_route_generating#index", :as => :foo }      class ::MyRouteGeneratingController < ActionController::Base        include Routes.url_helpers diff --git a/actionpack/test/fixtures/test/_b_layout_for_partial_with_object.html.erb b/actionpack/test/fixtures/test/_b_layout_for_partial_with_object.html.erb new file mode 100644 index 0000000000..bdd53014cd --- /dev/null +++ b/actionpack/test/fixtures/test/_b_layout_for_partial_with_object.html.erb @@ -0,0 +1 @@ +<b class="<%= customer.name.downcase %>"><%= yield %></b>
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/_b_layout_for_partial_with_object_counter.html.erb b/actionpack/test/fixtures/test/_b_layout_for_partial_with_object_counter.html.erb new file mode 100644 index 0000000000..44d6121297 --- /dev/null +++ b/actionpack/test/fixtures/test/_b_layout_for_partial_with_object_counter.html.erb @@ -0,0 +1 @@ +<b data-counter="<%= customer_counter %>"><%= yield %></b>
\ No newline at end of file diff --git a/actionpack/test/fixtures/translations/templates/default.erb b/actionpack/test/fixtures/translations/templates/default.erb new file mode 100644 index 0000000000..8b70031071 --- /dev/null +++ b/actionpack/test/fixtures/translations/templates/default.erb @@ -0,0 +1 @@ +<%= t('.missing', :default => :'.foo') %> diff --git a/actionpack/test/template/date_helper_i18n_test.rb b/actionpack/test/template/date_helper_i18n_test.rb index 82b62e64f3..63066d40cd 100644 --- a/actionpack/test/template/date_helper_i18n_test.rb +++ b/actionpack/test/template/date_helper_i18n_test.rb @@ -12,24 +12,24 @@ class DateHelperDistanceOfTimeInWordsI18nTests < ActiveSupport::TestCase    def test_distance_of_time_in_words_calls_i18n      { # with include_seconds -      [2.seconds,  true]  => [:'less_than_x_seconds', 5], -      [9.seconds,  true]  => [:'less_than_x_seconds', 10], -      [19.seconds, true]  => [:'less_than_x_seconds', 20], -      [30.seconds, true]  => [:'half_a_minute',       nil], -      [59.seconds, true]  => [:'less_than_x_minutes', 1], -      [60.seconds, true]  => [:'x_minutes',           1], +      [2.seconds,  { :include_seconds => true }]  => [:'less_than_x_seconds', 5], +      [9.seconds,  { :include_seconds => true }]  => [:'less_than_x_seconds', 10], +      [19.seconds, { :include_seconds => true }]  => [:'less_than_x_seconds', 20], +      [30.seconds, { :include_seconds => true }]  => [:'half_a_minute',       nil], +      [59.seconds, { :include_seconds => true }]  => [:'less_than_x_minutes', 1], +      [60.seconds, { :include_seconds => true }]  => [:'x_minutes',           1],        # without include_seconds -      [29.seconds,          false] => [:'less_than_x_minutes', 1], -      [60.seconds,          false] => [:'x_minutes',           1], -      [44.minutes,          false] => [:'x_minutes',           44], -      [61.minutes,          false] => [:'about_x_hours',       1], -      [24.hours,            false] => [:'x_days',              1], -      [30.days,             false] => [:'about_x_months',      1], -      [60.days,             false] => [:'x_months',            2], -      [1.year,              false] => [:'about_x_years',       1], -      [3.years + 6.months,  false] => [:'over_x_years',        3], -      [3.years + 10.months, false] => [:'almost_x_years',      4] +      [29.seconds,          { :include_seconds => false }] => [:'less_than_x_minutes', 1], +      [60.seconds,          { :include_seconds => false }] => [:'x_minutes',           1], +      [44.minutes,          { :include_seconds => false }] => [:'x_minutes',           44], +      [61.minutes,          { :include_seconds => false }] => [:'about_x_hours',       1], +      [24.hours,            { :include_seconds => false }] => [:'x_days',              1], +      [30.days,             { :include_seconds => false }] => [:'about_x_months',      1], +      [60.days,             { :include_seconds => false }] => [:'x_months',            2], +      [1.year,              { :include_seconds => false }] => [:'about_x_years',       1], +      [3.years + 6.months,  { :include_seconds => false }] => [:'over_x_years',        3], +      [3.years + 10.months, { :include_seconds => false }] => [:'almost_x_years',      4]        }.each do |passed, expected|        assert_distance_of_time_in_words_translates_key passed, expected @@ -37,7 +37,7 @@ class DateHelperDistanceOfTimeInWordsI18nTests < ActiveSupport::TestCase    end    def assert_distance_of_time_in_words_translates_key(passed, expected) -    diff, include_seconds = *passed +    diff, passed_options = *passed      key, count = *expected      to = @from + diff @@ -45,7 +45,12 @@ class DateHelperDistanceOfTimeInWordsI18nTests < ActiveSupport::TestCase      options[:count] = count if count      I18n.expects(:t).with(key, options) -    distance_of_time_in_words(@from, to, include_seconds, :locale => 'en') +    distance_of_time_in_words(@from, to, passed_options.merge(:locale => 'en')) +  end + +  def test_time_ago_in_words_passes_locale +    I18n.expects(:t).with(:less_than_x_minutes, :scope => :'datetime.distance_in_words', :count => 1, :locale => 'ru') +    time_ago_in_words(15.seconds.ago, :locale => 'ru')    end    def test_distance_of_time_pluralizations diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb index c9b8a5bb70..96c8cf25b1 100644 --- a/actionpack/test/template/date_helper_test.rb +++ b/actionpack/test/template/date_helper_test.rb @@ -21,20 +21,33 @@ class DateHelperTest < ActionView::TestCase    def assert_distance_of_time_in_words(from, to=nil)      to ||= from -    # 0..1 with include_seconds -    assert_equal "less than 5 seconds", distance_of_time_in_words(from, to + 0.seconds, true) -    assert_equal "less than 5 seconds", distance_of_time_in_words(from, to + 4.seconds, true) -    assert_equal "less than 10 seconds", distance_of_time_in_words(from, to + 5.seconds, true) -    assert_equal "less than 10 seconds", distance_of_time_in_words(from, to + 9.seconds, true) -    assert_equal "less than 20 seconds", distance_of_time_in_words(from, to + 10.seconds, true) -    assert_equal "less than 20 seconds", distance_of_time_in_words(from, to + 19.seconds, true) -    assert_equal "half a minute", distance_of_time_in_words(from, to + 20.seconds, true) -    assert_equal "half a minute", distance_of_time_in_words(from, to + 39.seconds, true) -    assert_equal "less than a minute", distance_of_time_in_words(from, to + 40.seconds, true) -    assert_equal "less than a minute", distance_of_time_in_words(from, to + 59.seconds, true) -    assert_equal "1 minute", distance_of_time_in_words(from, to + 60.seconds, true) -    assert_equal "1 minute", distance_of_time_in_words(from, to + 89.seconds, true) - +    # 0..1 with :include_seconds => true +    assert_equal "less than 5 seconds", distance_of_time_in_words(from, to + 0.seconds, :include_seconds => true) +    assert_equal "less than 5 seconds", distance_of_time_in_words(from, to + 4.seconds, :include_seconds => true) +    assert_equal "less than 10 seconds", distance_of_time_in_words(from, to + 5.seconds, :include_seconds => true) +    assert_equal "less than 10 seconds", distance_of_time_in_words(from, to + 9.seconds, :include_seconds => true) +    assert_equal "less than 20 seconds", distance_of_time_in_words(from, to + 10.seconds, :include_seconds => true) +    assert_equal "less than 20 seconds", distance_of_time_in_words(from, to + 19.seconds, :include_seconds => true) +    assert_equal "half a minute", distance_of_time_in_words(from, to + 20.seconds, :include_seconds => true) +    assert_equal "half a minute", distance_of_time_in_words(from, to + 39.seconds, :include_seconds => true) +    assert_equal "less than a minute", distance_of_time_in_words(from, to + 40.seconds, :include_seconds => true) +    assert_equal "less than a minute", distance_of_time_in_words(from, to + 59.seconds, :include_seconds => true) +    assert_equal "1 minute", distance_of_time_in_words(from, to + 60.seconds, :include_seconds => true) +    assert_equal "1 minute", distance_of_time_in_words(from, to + 89.seconds, :include_seconds => true) + +    # 0..1 with :include_seconds => false +    assert_equal "less than a minute", distance_of_time_in_words(from, to + 0.seconds, :include_seconds => false) +    assert_equal "less than a minute", distance_of_time_in_words(from, to + 4.seconds, :include_seconds => false) +    assert_equal "less than a minute", distance_of_time_in_words(from, to + 5.seconds, :include_seconds => false) +    assert_equal "less than a minute", distance_of_time_in_words(from, to + 9.seconds, :include_seconds => false) +    assert_equal "less than a minute", distance_of_time_in_words(from, to + 10.seconds, :include_seconds => false) +    assert_equal "less than a minute", distance_of_time_in_words(from, to + 19.seconds, :include_seconds => false) +    assert_equal "less than a minute", distance_of_time_in_words(from, to + 20.seconds, :include_seconds => false) +    assert_equal "1 minute", distance_of_time_in_words(from, to + 39.seconds, :include_seconds => false) +    assert_equal "1 minute", distance_of_time_in_words(from, to + 40.seconds, :include_seconds => false) +    assert_equal "1 minute", distance_of_time_in_words(from, to + 59.seconds, :include_seconds => false) +    assert_equal "1 minute", distance_of_time_in_words(from, to + 60.seconds, :include_seconds => false) +    assert_equal "1 minute", distance_of_time_in_words(from, to + 89.seconds, :include_seconds => false)      # First case 0..1      assert_equal "less than a minute", distance_of_time_in_words(from, to + 0.seconds)      assert_equal "less than a minute", distance_of_time_in_words(from, to + 29.seconds) @@ -95,7 +108,8 @@ class DateHelperTest < ActionView::TestCase      # test to < from      assert_equal "about 4 hours", distance_of_time_in_words(from + 4.hours, to) -    assert_equal "less than 20 seconds", distance_of_time_in_words(from + 19.seconds, to, true) +    assert_equal "less than 20 seconds", distance_of_time_in_words(from + 19.seconds, to, :include_seconds => true) +    assert_equal "less than a minute", distance_of_time_in_words(from + 19.seconds, to, :include_seconds => false)    end    def test_distance_in_words @@ -103,6 +117,11 @@ class DateHelperTest < ActionView::TestCase      assert_distance_of_time_in_words(from)    end +  def test_time_ago_in_words_passes_include_seconds +    assert_equal "less than 20 seconds", time_ago_in_words(15.seconds.ago, :include_seconds => true) +    assert_equal "less than a minute", time_ago_in_words(15.seconds.ago, :include_seconds => false) +  end +    def test_distance_in_words_with_time_zones      from = Time.mktime(2004, 6, 6, 21, 45, 0)      assert_distance_of_time_in_words(from.in_time_zone('Alaska')) @@ -125,13 +144,33 @@ class DateHelperTest < ActionView::TestCase      start_date = Date.new 1982, 12, 3      end_date = Date.new 2010, 11, 30      assert_equal("almost 28 years", distance_of_time_in_words(start_date, end_date)) +    assert_equal("almost 28 years", distance_of_time_in_words(end_date, start_date))    end    def test_distance_in_words_with_integers -    assert_equal "less than a minute", distance_of_time_in_words(59) +    assert_equal "1 minute", distance_of_time_in_words(59)      assert_equal "about 1 hour", distance_of_time_in_words(60*60) -    assert_equal "less than a minute", distance_of_time_in_words(0, 59) +    assert_equal "1 minute", distance_of_time_in_words(0, 59)      assert_equal "about 1 hour", distance_of_time_in_words(60*60, 0) +    assert_equal "about 3 years", distance_of_time_in_words(10**8) +    assert_equal "about 3 years", distance_of_time_in_words(0, 10**8) +  end + +  def test_distance_in_words_with_times +    assert_equal "1 minute", distance_of_time_in_words(30.seconds) +    assert_equal "1 minute", distance_of_time_in_words(59.seconds) +    assert_equal "2 minutes", distance_of_time_in_words(119.seconds) +    assert_equal "2 minutes", distance_of_time_in_words(1.minute + 59.seconds) +    assert_equal "3 minutes", distance_of_time_in_words(2.minute + 30.seconds) +    assert_equal "44 minutes", distance_of_time_in_words(44.minutes + 29.seconds) +    assert_equal "about 1 hour", distance_of_time_in_words(44.minutes + 30.seconds) +    assert_equal "about 1 hour", distance_of_time_in_words(60.minutes) + +    # include seconds +    assert_equal "half a minute", distance_of_time_in_words(39.seconds, 0, :include_seconds => true) +    assert_equal "less than a minute", distance_of_time_in_words(40.seconds, 0, :include_seconds => true) +    assert_equal "less than a minute", distance_of_time_in_words(59.seconds, 0, :include_seconds => true) +    assert_equal "1 minute", distance_of_time_in_words(60.seconds, 0, :include_seconds => true)    end    def test_time_ago_in_words @@ -567,7 +606,7 @@ class DateHelperTest < ActionView::TestCase    end    def test_select_minute_with_html_options -    expected = expected = %(<select id="date_minute" name="date[minute]" class="selector" accesskey="M">\n) +    expected = %(<select id="date_minute" name="date[minute]" class="selector" accesskey="M">\n)      expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n)      expected << "</select>\n" diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 3fa3898ec8..beb3ea752a 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -97,7 +97,7 @@ class FormHelperTest < ActionView::TestCase        end      end -    match "/foo", :to => "controller#action" +    get "/foo", :to => "controller#action"      root :to => "main#index"    end @@ -350,36 +350,52 @@ class FormHelperTest < ActionView::TestCase        text_field("user", "email", :type => "email")    end -  def test_check_box +  def test_check_box_is_html_safe      assert check_box("post", "secret").html_safe? +  end + +  def test_check_box_checked_if_object_value_is_same_that_check_value      assert_dom_equal(        '<input name="post[secret]" type="hidden" value="0" /><input checked="checked" id="post_secret" name="post[secret]" type="checkbox" value="1" />',        check_box("post", "secret")      ) +  end + +  def test_check_box_not_checked_if_object_value_is_same_that_unchecked_value      @post.secret = 0      assert_dom_equal(        '<input name="post[secret]" type="hidden" value="0" /><input id="post_secret" name="post[secret]" type="checkbox" value="1" />',        check_box("post", "secret")      ) +  end + +  def test_check_box_checked_if_option_checked_is_present      assert_dom_equal(        '<input name="post[secret]" type="hidden" value="0" /><input checked="checked" id="post_secret" name="post[secret]" type="checkbox" value="1" />',        check_box("post", "secret" ,{"checked"=>"checked"})      ) +  end + +  def test_check_box_checked_if_object_value_is_true      @post.secret = true      assert_dom_equal(        '<input name="post[secret]" type="hidden" value="0" /><input checked="checked" id="post_secret" name="post[secret]" type="checkbox" value="1" />',        check_box("post", "secret")      ) +      assert_dom_equal(        '<input name="post[secret]" type="hidden" value="0" /><input checked="checked" id="post_secret" name="post[secret]" type="checkbox" value="1" />',        check_box("post", "secret?")      ) +  end +  def test_check_box_checked_if_object_value_includes_checked_value      @post.secret = ['0']      assert_dom_equal(        '<input name="post[secret]" type="hidden" value="0" /><input id="post_secret" name="post[secret]" type="checkbox" value="1" />',        check_box("post", "secret")      ) +      @post.secret = ['1']      assert_dom_equal(        '<input name="post[secret]" type="hidden" value="0" /><input checked="checked" id="post_secret" name="post[secret]" type="checkbox" value="1" />', @@ -392,12 +408,92 @@ class FormHelperTest < ActionView::TestCase      assert_dom_equal('<input id="post_secret" name="post[secret]" type="checkbox" value="1" />', check_box("post", "secret", :include_hidden => false))    end -  def test_check_box_with_explicit_checked_and_unchecked_values +  def test_check_box_with_explicit_checked_and_unchecked_values_when_object_value_is_string      @post.secret = "on"      assert_dom_equal(        '<input name="post[secret]" type="hidden" value="off" /><input checked="checked" id="post_secret" name="post[secret]" type="checkbox" value="on" />',        check_box("post", "secret", {}, "on", "off")      ) + +    @post.secret = "off" +    assert_dom_equal( +      '<input name="post[secret]" type="hidden" value="off" /><input id="post_secret" name="post[secret]" type="checkbox" value="on" />', +      check_box("post", "secret", {}, "on", "off") +    ) +  end + +  def test_check_box_with_explicit_checked_and_unchecked_values_when_object_value_is_boolean +    @post.secret = false +    assert_dom_equal( +      '<input name="post[secret]" type="hidden" value="true" /><input checked="checked" id="post_secret" name="post[secret]" type="checkbox" value="false" />', +      check_box("post", "secret", {}, false, true) +    ) + +    @post.secret = true +    assert_dom_equal( +      '<input name="post[secret]" type="hidden" value="true" /><input id="post_secret" name="post[secret]" type="checkbox" value="false" />', +      check_box("post", "secret", {}, false, true) +    ) +  end + +  def test_check_box_with_explicit_checked_and_unchecked_values_when_object_value_is_integer +    @post.secret = 0 +    assert_dom_equal( +      '<input name="post[secret]" type="hidden" value="1" /><input checked="checked" id="post_secret" name="post[secret]" type="checkbox" value="0" />', +      check_box("post", "secret", {}, 0, 1) +    ) + +    @post.secret = 1 +    assert_dom_equal( +      '<input name="post[secret]" type="hidden" value="1" /><input id="post_secret" name="post[secret]" type="checkbox" value="0" />', +      check_box("post", "secret", {}, 0, 1) +    ) + +    @post.secret = 2 +    assert_dom_equal( +      '<input name="post[secret]" type="hidden" value="1" /><input id="post_secret" name="post[secret]" type="checkbox" value="0" />', +      check_box("post", "secret", {}, 0, 1) +    ) +  end + +  def test_check_box_with_explicit_checked_and_unchecked_values_when_object_value_is_float +    @post.secret = 0.0 +    assert_dom_equal( +      '<input name="post[secret]" type="hidden" value="1" /><input checked="checked" id="post_secret" name="post[secret]" type="checkbox" value="0" />', +      check_box("post", "secret", {}, 0, 1) +    ) + +    @post.secret = 1.1 +    assert_dom_equal( +      '<input name="post[secret]" type="hidden" value="1" /><input id="post_secret" name="post[secret]" type="checkbox" value="0" />', +      check_box("post", "secret", {}, 0, 1) +    ) + +    @post.secret = 2.2 +    assert_dom_equal( +      '<input name="post[secret]" type="hidden" value="1" /><input id="post_secret" name="post[secret]" type="checkbox" value="0" />', +      check_box("post", "secret", {}, 0, 1) +    ) +  end + +  def test_check_box_with_explicit_checked_and_unchecked_values_when_object_value_is_big_decimal +    @post.secret = BigDecimal.new(0) +    assert_dom_equal( +      '<input name="post[secret]" type="hidden" value="1" /><input checked="checked" id="post_secret" name="post[secret]" type="checkbox" value="0" />', +      check_box("post", "secret", {}, 0, 1) +    ) + +    @post.secret = BigDecimal.new(1) +    assert_dom_equal( +      '<input name="post[secret]" type="hidden" value="1" /><input id="post_secret" name="post[secret]" type="checkbox" value="0" />', +      check_box("post", "secret", {}, 0, 1) +    ) + +    @post.secret = BigDecimal.new(2.2, 1) +    assert_dom_equal( +      '<input name="post[secret]" type="hidden" value="1" /><input id="post_secret" name="post[secret]" type="checkbox" value="0" />', +      check_box("post", "secret", {}, 0, 1) +    )    end    def test_check_box_with_nil_unchecked_value @@ -2169,6 +2265,23 @@ class FormHelperTest < ActionView::TestCase      ActionView::Base.default_form_builder = old_default_form_builder    end +  def test_lazy_loading_default_form_builder +    old_default_form_builder, ActionView::Base.default_form_builder = +      ActionView::Base.default_form_builder, "FormHelperTest::LabelledFormBuilder" + +    form_for(@post) do |f| +      concat f.text_field(:title) +    end + +    expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', :method => 'patch') do +      "<label for='title'>Title:</label> <input name='post[title]' type='text' id='post_title' value='Hello World' /><br/>" +    end + +    assert_dom_equal expected, output_buffer +  ensure +    ActionView::Base.default_form_builder = old_default_form_builder +  end +    def test_fields_for_with_labelled_builder      output_buffer = fields_for(:post, @post, :builder => LabelledFormBuilder) do |f|        concat f.text_field(:title) diff --git a/actionpack/test/template/javascript_helper_test.rb b/actionpack/test/template/javascript_helper_test.rb index 0b96985002..fe7607ee26 100644 --- a/actionpack/test/template/javascript_helper_test.rb +++ b/actionpack/test/template/javascript_helper_test.rb @@ -42,36 +42,6 @@ class JavaScriptHelperTest < ActionView::TestCase      assert_instance_of ActiveSupport::SafeBuffer, escape_javascript(ActiveSupport::SafeBuffer.new(given))    end -  def test_button_to_function -    assert_dom_equal %(<input type="button" onclick="alert('Hello world!');" value="Greeting" />), -      button_to_function("Greeting", "alert('Hello world!')") -  end - -  def test_button_to_function_with_onclick -    assert_dom_equal "<input onclick=\"alert('Goodbye World :('); alert('Hello world!');\" type=\"button\" value=\"Greeting\" />", -      button_to_function("Greeting", "alert('Hello world!')", :onclick => "alert('Goodbye World :(')") -  end - -  def test_button_to_function_without_function -    assert_dom_equal "<input onclick=\";\" type=\"button\" value=\"Greeting\" />", -      button_to_function("Greeting") -  end - -  def test_link_to_function -    assert_dom_equal %(<a href="#" onclick="alert('Hello world!'); return false;">Greeting</a>), -      link_to_function("Greeting", "alert('Hello world!')") -  end - -  def test_link_to_function_with_existing_onclick -    assert_dom_equal %(<a href="#" onclick="confirm('Sanity!'); alert('Hello world!'); return false;">Greeting</a>), -      link_to_function("Greeting", "alert('Hello world!')", :onclick => "confirm('Sanity!')") -  end - -  def test_function_with_href -    assert_dom_equal %(<a href="http://example.com/" onclick="alert('Hello world!'); return false;">Greeting</a>), -      link_to_function("Greeting", "alert('Hello world!')", :href => 'http://example.com/') -  end -    def test_javascript_tag      self.output_buffer = 'foo' diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 122b07d348..cdaca56ef2 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -21,9 +21,7 @@ module RenderTestCases    end    def test_render_without_options -    @view.render() -    flunk "Render did not raise ArgumentError" -  rescue ArgumentError => e +    e = assert_raises(ArgumentError) { @view.render() }      assert_match "You invoked render but did not give any of :partial, :template, :inline, :file or :text option.", e.message    end @@ -153,25 +151,26 @@ module RenderTestCases    end    def test_render_partial_with_invalid_name -    @view.render(:partial => "test/200") -    flunk "Render did not raise ArgumentError" -  rescue ArgumentError => e +    e = assert_raises(ArgumentError) { @view.render(:partial => "test/200") }      assert_equal "The partial name (test/200) is not a valid Ruby identifier; " + -                                "make sure your partial name starts with a letter or underscore, " + -                                "and is followed by any combinations of letters, numbers, or underscores.", e.message +      "make sure your partial name starts with a letter or underscore, " + +      "and is followed by any combinations of letters, numbers, or underscores.", e.message +  end + +  def test_render_partial_with_missing_filename +    e = assert_raises(ArgumentError) { @view.render(:partial => "test/") } +    assert_equal "The partial name (test/) is not a valid Ruby identifier; " + +      "make sure your partial name starts with a letter or underscore, " + +      "and is followed by any combinations of letters, numbers, or underscores.", e.message    end    def test_render_partial_with_incompatible_object -    @view.render(:partial => nil) -    flunk "Render did not raise ArgumentError" -  rescue ArgumentError => e +    e = assert_raises(ArgumentError) { @view.render(:partial => nil) }      assert_equal "'#{nil.inspect}' is not an ActiveModel-compatible object. It must implement :to_partial_path.", e.message    end    def test_render_partial_with_errors -    @view.render(:partial => "test/raise") -    flunk "Render did not raise Template::Error" -  rescue ActionView::Template::Error => e +    e = assert_raises(ActionView::Template::Error) { @view.render(:partial => "test/raise") }      assert_match %r!method.*doesnt_exist!, e.message      assert_equal "", e.sub_template_message      assert_equal "1", e.line_number @@ -180,9 +179,7 @@ module RenderTestCases    end    def test_render_sub_template_with_errors -    @view.render(:template => "test/sub_template_raise") -    flunk "Render did not raise Template::Error" -  rescue ActionView::Template::Error => e +    e = assert_raises(ActionView::Template::Error) { @view.render(:template => "test/sub_template_raise") }      assert_match %r!method.*doesnt_exist!, e.message      assert_equal "Trace of template inclusion: #{File.expand_path("#{FIXTURE_LOAD_PATH}/test/sub_template_raise.html.erb")}", e.sub_template_message      assert_equal "1", e.line_number @@ -190,9 +187,7 @@ module RenderTestCases    end    def test_render_file_with_errors -    @view.render(:file => File.expand_path("test/_raise", FIXTURE_LOAD_PATH)) -    flunk "Render did not raise Template::Error" -  rescue ActionView::Template::Error => e +    e = assert_raises(ActionView::Template::Error) { @view.render(:file => File.expand_path("test/_raise", FIXTURE_LOAD_PATH)) }      assert_match %r!method.*doesnt_exist!, e.message      assert_equal "", e.sub_template_message      assert_equal "1", e.line_number @@ -238,11 +233,26 @@ module RenderTestCases    def test_render_partial_with_nil_values_in_collection      assert_equal "Hello: davidHello: Anonymous", @view.render(:partial => "test/customer", :collection => [ Customer.new("david"), nil ])    end -   +    def test_render_partial_with_layout_using_collection_and_template      assert_equal "<b>Hello: Amazon</b><b>Hello: Yahoo</b>", @view.render(:partial => "test/customer", :layout => 'test/b_layout_for_partial', :collection => [ Customer.new("Amazon"), Customer.new("Yahoo") ])    end +  def test_render_partial_with_layout_using_collection_and_template_makes_current_item_available_in_layout +    assert_equal '<b class="amazon">Hello: Amazon</b><b class="yahoo">Hello: Yahoo</b>', +      @view.render(:partial => "test/customer", :layout => 'test/b_layout_for_partial_with_object', :collection => [ Customer.new("Amazon"), Customer.new("Yahoo") ]) +  end + +  def test_render_partial_with_layout_using_collection_and_template_makes_current_item_counter_available_in_layout +    assert_equal '<b data-counter="0">Hello: Amazon</b><b data-counter="1">Hello: Yahoo</b>', +      @view.render(:partial => "test/customer", :layout => 'test/b_layout_for_partial_with_object_counter', :collection => [ Customer.new("Amazon"), Customer.new("Yahoo") ]) +  end + +  def test_render_partial_with_layout_using_object_and_template_makes_object_available_in_layout +    assert_equal '<b class="amazon">Hello: Amazon</b>', +      @view.render(:partial => "test/customer", :layout => 'test/b_layout_for_partial_with_object', :object => Customer.new("Amazon")) +  end +    def test_render_partial_with_empty_array_should_return_nil      assert_nil @view.render(:partial => [])    end @@ -274,7 +284,7 @@ module RenderTestCases    # TODO: The reason for this test is unclear, improve documentation    def test_render_missing_xml_partial_and_raise_missing_template      @view.formats = [:xml] -    assert_raise(ActionView::MissingTemplate) { @view.render(:partial => "test/layout_for_partial") } +    assert_raises(ActionView::MissingTemplate) { @view.render(:partial => "test/layout_for_partial") }    ensure      @view.formats = nil    end @@ -315,7 +325,7 @@ module RenderTestCases      ActionView::Template.register_template_handler :foo, CustomHandler      assert_equal 'source: "Hello, <%= name %>!"', @view.render(:inline => "Hello, <%= name %>!", :locals => { :name => "Josh" }, :type => :foo)    end -   +    def test_render_knows_about_types_registered_when_extensions_are_checked_earlier_in_initialization      ActionView::Template::Handlers.extensions      ActionView::Template.register_template_handler :foo, CustomHandler @@ -325,7 +335,7 @@ module RenderTestCases    def test_render_ignores_templates_with_malformed_template_handlers      ActiveSupport::Deprecation.silence do        %w(malformed malformed.erb malformed.html.erb malformed.en.html.erb).each do |name| -        assert_raise(ActionView::MissingTemplate) { @view.render(:file => "test/malformed/#{name}") } +        assert_raises(ActionView::MissingTemplate) { @view.render(:file => "test/malformed/#{name}") }        end      end    end @@ -450,23 +460,15 @@ class LazyViewRenderTest < ActiveSupport::TestCase    def test_render_utf8_template_with_incompatible_external_encoding      with_external_encoding Encoding::SHIFT_JIS do -      begin -        @view.render(:file => "test/utf8", :formats => [:html], :layouts => "layouts/yield") -        flunk 'Should have raised incompatible encoding error' -      rescue ActionView::Template::Error => error -        assert_match 'Your template was not saved as valid Shift_JIS', error.original_exception.message -      end +      e = assert_raises(ActionView::Template::Error) { @view.render(:file => "test/utf8", :formats => [:html], :layouts => "layouts/yield") } +      assert_match 'Your template was not saved as valid Shift_JIS', e.original_exception.message      end    end    def test_render_utf8_template_with_partial_with_incompatible_encoding      with_external_encoding Encoding::SHIFT_JIS do -      begin -        @view.render(:file => "test/utf8_magic_with_bare_partial", :formats => [:html], :layouts => "layouts/yield") -        flunk 'Should have raised incompatible encoding error' -      rescue ActionView::Template::Error => error -        assert_match 'Your template was not saved as valid Shift_JIS', error.original_exception.message -      end +      e = assert_raises(ActionView::Template::Error) { @view.render(:file => "test/utf8_magic_with_bare_partial", :formats => [:html], :layouts => "layouts/yield") } +      assert_match 'Your template was not saved as valid Shift_JIS', e.original_exception.message      end    end diff --git a/actionpack/test/template/test_test.rb b/actionpack/test/template/test_test.rb index adcbf1447f..108a674d95 100644 --- a/actionpack/test/template/test_test.rb +++ b/actionpack/test/template/test_test.rb @@ -48,7 +48,7 @@ class PeopleHelperTest < ActionView::TestCase      def with_test_route_set        with_routing do |set|          set.draw do -          match 'people', :to => 'people#index', :as => :people +          get 'people', :to => 'people#index', :as => :people          end          yield        end diff --git a/actionpack/test/template/translation_helper_test.rb b/actionpack/test/template/translation_helper_test.rb index 397de9c2ce..97777ccff0 100644 --- a/actionpack/test/template/translation_helper_test.rb +++ b/actionpack/test/template/translation_helper_test.rb @@ -11,7 +11,8 @@ class TranslationHelperTest < ActiveSupport::TestCase        :translations => {          :templates => {            :found => { :foo => 'Foo' }, -          :array => { :foo => { :bar => 'Foo Bar' } } +          :array => { :foo => { :bar => 'Foo Bar' } }, +          :default => { :foo => 'Foo' }          },          :foo => 'Foo',          :hello => '<a>Hello World</a>', @@ -71,6 +72,10 @@ class TranslationHelperTest < ActiveSupport::TestCase      assert_equal 'Foo Bar', @view.render(:file => 'translations/templates/array').strip    end +  def test_default_lookup_scoped_by_partial +    assert_equal 'Foo', view.render(:file => 'translations/templates/default').strip +  end +    def test_missing_translation_scoped_by_partial      expected = '<span class="translation_missing" title="translation missing: en.translations.templates.missing.missing">Missing</span>'      assert_equal expected, view.render(:file => 'translations/templates/missing').strip @@ -102,4 +107,22 @@ class TranslationHelperTest < ActiveSupport::TestCase    def test_translation_returning_an_array_ignores_html_suffix      assert_equal ["foo", "bar"], translate(:'translations.array_html')    end + +  def test_translate_with_default_named_html +    translation = translate(:'translations.missing', :default => :'translations.hello_html') +    assert_equal '<a>Hello World</a>', translation +    assert translation.html_safe? +  end + +  def test_translate_with_two_defaults_named_html +    translation = translate(:'translations.missing', :default => [:'translations.missing_html', :'translations.hello_html']) +    assert_equal '<a>Hello World</a>', translation +    assert translation.html_safe? +  end + +  def test_translate_with_last_default_named_html +    translation = translate(:'translations.missing', :default => [:'translations.missing', :'translations.hello_html']) +    assert_equal '<a>Hello World</a>', translation +    assert translation.html_safe? +  end  end diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index 88f506b217..eaa8bdbd26 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -15,9 +15,9 @@ class UrlHelperTest < ActiveSupport::TestCase    routes = ActionDispatch::Routing::RouteSet.new    routes.draw do -    match "/" => "foo#bar" -    match "/other" => "foo#other" -    match "/article/:id" => "foo#article", :as => :article +    get "/" => "foo#bar" +    get "/other" => "foo#other" +    get "/article/:id" => "foo#article", :as => :article    end    include routes.url_helpers @@ -471,25 +471,25 @@ end  class UrlHelperControllerTest < ActionController::TestCase    class UrlHelperController < ActionController::Base      test_routes do -      match 'url_helper_controller_test/url_helper/show/:id', +      get 'url_helper_controller_test/url_helper/show/:id',          :to => 'url_helper_controller_test/url_helper#show',          :as => :show -      match 'url_helper_controller_test/url_helper/profile/:name', +      get 'url_helper_controller_test/url_helper/profile/:name',          :to => 'url_helper_controller_test/url_helper#show',          :as => :profile -      match 'url_helper_controller_test/url_helper/show_named_route', +      get 'url_helper_controller_test/url_helper/show_named_route',          :to => 'url_helper_controller_test/url_helper#show_named_route',          :as => :show_named_route -      match "/:controller(/:action(/:id))" +      get "/:controller(/:action(/:id))" -      match 'url_helper_controller_test/url_helper/normalize_recall_params', +      get 'url_helper_controller_test/url_helper/normalize_recall_params',          :to => UrlHelperController.action(:normalize_recall),          :as => :normalize_recall_params -      match '/url_helper_controller_test/url_helper/override_url_helper/default', +      get '/url_helper_controller_test/url_helper/override_url_helper/default',          :to => 'url_helper_controller_test/url_helper#override_url_helper',          :as => :override_url_helper      end  | 
