diff options
Diffstat (limited to 'actionpack/lib/action_dispatch')
35 files changed, 675 insertions, 106 deletions
diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index c4fe3a5c09..19f89edbc1 100644 --- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb +++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb @@ -135,9 +135,7 @@ module ActionDispatch } end - # Receives an array of mimes and return the first user sent mime that - # matches the order array. - # + # Returns the first MIME type that matches the provided array of MIME types. def negotiate_mime(order) formats.each do |priority| if priority == Mime::ALL diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index 1583a8f87f..0cf010f59e 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -46,7 +46,7 @@ module Mime end end - # Encapsulates the notion of a mime type. Can be used at render time, for example, with: + # Encapsulates the notion of a MIME type. Can be used at render time, for example, with: # # class PostsController < ActionController::Base # def show @@ -64,7 +64,7 @@ module Mime @register_callbacks = [] - # A simple helper class used in parsing the accept header + # A simple helper class used in parsing the accept header. class AcceptItem #:nodoc: attr_accessor :index, :name, :q alias :to_s :name @@ -72,7 +72,7 @@ module Mime def initialize(index, name, q = nil) @index = index @name = name - q ||= 0.0 if @name == "*/*".freeze # default wildcard match to end of list + q ||= 0.0 if @name == "*/*".freeze # Default wildcard match to end of list. @q = ((q || 1.0).to_f * 100).to_i end @@ -90,22 +90,22 @@ module Mime text_xml_idx = find_item_by_name list, "text/xml" app_xml_idx = find_item_by_name list, Mime[:xml].to_s - # Take care of the broken text/xml entry by renaming or deleting it + # Take care of the broken text/xml entry by renaming or deleting it. if text_xml_idx && app_xml_idx app_xml = list[app_xml_idx] text_xml = list[text_xml_idx] - app_xml.q = [text_xml.q, app_xml.q].max # set the q value to the max of the two - if app_xml_idx > text_xml_idx # make sure app_xml is ahead of text_xml in the list + app_xml.q = [text_xml.q, app_xml.q].max # Set the q value to the max of the two. + if app_xml_idx > text_xml_idx # Make sure app_xml is ahead of text_xml in the list. list[app_xml_idx], list[text_xml_idx] = text_xml, app_xml app_xml_idx, text_xml_idx = text_xml_idx, app_xml_idx end - list.delete_at(text_xml_idx) # delete text_xml from the list + list.delete_at(text_xml_idx) # Delete text_xml from the list. elsif text_xml_idx list[text_xml_idx].name = Mime[:xml].to_s end - # Look for more specific XML-based types and sort them ahead of app/xml + # Look for more specific XML-based types and sort them ahead of app/xml. if app_xml_idx app_xml = list[app_xml_idx] idx = app_xml_idx @@ -147,7 +147,7 @@ module Mime EXTENSION_LOOKUP[extension.to_s] end - # Registers an alias that's not used on mime type lookup, but can be referenced directly. Especially useful for + # Registers an alias that's not used on MIME type lookup, but can be referenced directly. Especially useful for # rendering different HTML versions depending on the user agent, like an iPhone. def register_alias(string, symbol, extension_synonyms = []) register(string, symbol, [], extension_synonyms, true) diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb index 8f21eca440..79a2ef965b 100644 --- a/actionpack/lib/action_dispatch/http/parameters.rb +++ b/actionpack/lib/action_dispatch/http/parameters.rb @@ -13,7 +13,7 @@ module ActionDispatch } # Raised when raw data from the request cannot be parsed by the parser - # defined for request's content mime type. + # defined for request's content MIME type. class ParseError < StandardError def initialize super($!.message) @@ -30,9 +30,9 @@ module ActionDispatch end module ClassMethods - # Configure the parameter parser for a given mime type. + # Configure the parameter parser for a given MIME type. # - # It accepts a hash where the key is the symbol of the mime type + # It accepts a hash where the key is the symbol of the MIME type # and the value is a proc. # # original_parsers = ActionDispatch::Request.parameter_parsers @@ -100,7 +100,7 @@ module ActionDispatch begin strategy.call(raw_post) - rescue # JSON or Ruby code block errors + rescue # JSON or Ruby code block errors. my_logger = logger || ActiveSupport::Logger.new($stderr) my_logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{raw_post}" @@ -115,6 +115,7 @@ module ActionDispatch end module ParamsParser - ParseError = ActiveSupport::Deprecation::DeprecatedConstantProxy.new("ActionDispatch::ParamsParser::ParseError", "ActionDispatch::Http::Parameters::ParseError") + include ActiveSupport::Deprecation::DeprecatedConstantAccessor + deprecate_constant "ParseError", "ActionDispatch::Http::Parameters::ParseError" end end diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index 19fa42ce12..6d42404a98 100644 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -114,7 +114,7 @@ module ActionDispatch HTTP_METHOD_LOOKUP = {} - # Populate the HTTP method lookup cache + # Populate the HTTP method lookup cache. HTTP_METHODS.each { |method| HTTP_METHOD_LOOKUP[method] = method.underscore.to_sym } @@ -165,12 +165,12 @@ module ActionDispatch def show_exceptions? # :nodoc: # We're treating `nil` as "unset", and we want the default setting to be - # `true`. This logic should be extracted to `env_config` and calculated + # `true`. This logic should be extracted to `env_config` and calculated # once. !(get_header("action_dispatch.show_exceptions".freeze) == false) end - # Returns a symbol form of the #request_method + # Returns a symbol form of the #request_method. def request_method_symbol HTTP_METHOD_LOOKUP[request_method] end @@ -182,7 +182,7 @@ module ActionDispatch @method ||= check_method(get_header("rack.methodoverride.original_method") || get_header("REQUEST_METHOD")) end - # Returns a symbol form of the #method + # Returns a symbol form of the #method. def method_symbol HTTP_METHOD_LOOKUP[method] end @@ -267,7 +267,7 @@ module ActionDispatch # (which sets the action_dispatch.request_id environment variable). # # This unique ID is useful for tracing a request from end-to-end as part of logging or debugging. - # This relies on the rack variable set by the ActionDispatch::RequestId middleware. + # This relies on the Rack variable set by the ActionDispatch::RequestId middleware. def request_id get_header ACTION_DISPATCH_REQUEST_ID end @@ -339,7 +339,7 @@ module ActionDispatch Session::Options.set self, options end - # Override Rack's GET method to support indifferent access + # Override Rack's GET method to support indifferent access. def GET fetch_header("action_dispatch.request.query_parameters") do |k| rack_query_params = super || {} @@ -352,7 +352,7 @@ module ActionDispatch end alias :query_parameters :GET - # Override Rack's POST method to support indifferent access + # Override Rack's POST method to support indifferent access. def POST fetch_header("action_dispatch.request.request_parameters") do pr = parse_formatted_parameters(params_parsers) do |params| diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index dc159596c4..2ee52eeb48 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -85,7 +85,7 @@ module ActionDispatch # :nodoc: cattr_accessor(:default_headers) include Rack::Response::Helpers - # Aliasing these off because AD::Http::Cache::Response defines them + # Aliasing these off because AD::Http::Cache::Response defines them. alias :_cache_control :cache_control alias :_cache_control= :cache_control= @@ -142,7 +142,7 @@ module ActionDispatch # :nodoc: private def each_chunk(&block) - @buf.each(&block) # extract into own method + @buf.each(&block) end end diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb index a6937d54ff..b6be48a48b 100644 --- a/actionpack/lib/action_dispatch/http/url.rb +++ b/actionpack/lib/action_dispatch/http/url.rb @@ -101,10 +101,8 @@ module ActionDispatch end def add_trailing_slash(path) - # includes querysting if path.include?("?") path.sub!(/\?/, '/\&') - # does not have a .format elsif !path.include?(".") path.sub!(/[^\/]\z|\A\z/, '\&/') end diff --git a/actionpack/lib/action_dispatch/journey/formatter.rb b/actionpack/lib/action_dispatch/journey/formatter.rb index f3b8e82d32..326f4e52f9 100644 --- a/actionpack/lib/action_dispatch/journey/formatter.rb +++ b/actionpack/lib/action_dispatch/journey/formatter.rb @@ -15,7 +15,7 @@ module ActionDispatch def generate(name, options, path_parameters, parameterize = nil) constraints = path_parameters.merge(options) - missing_keys = nil # need for variable scope + missing_keys = nil match_route(name, constraints) do |route| parameterized_parts = extract_parameterized_parts(route, options, path_parameters, parameterize) diff --git a/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb index beb9f1ef3b..e1ac2c873e 100644 --- a/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb +++ b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb @@ -109,7 +109,6 @@ module ActionDispatch svg = to_svg javascripts = [states, fsm_js] - # Annoying hack warnings fun_routes = fun_routes stylesheets = stylesheets svg = svg diff --git a/actionpack/lib/action_dispatch/journey/route.rb b/actionpack/lib/action_dispatch/journey/route.rb index 927fd369c4..7bc15aa6b3 100644 --- a/actionpack/lib/action_dispatch/journey/route.rb +++ b/actionpack/lib/action_dispatch/journey/route.rb @@ -89,8 +89,15 @@ module ActionDispatch end end + # Needed for `rails routes`. Picks up succinctly defined requirements + # for a route, for example route + # + # get 'photo/:id', :controller => 'photos', :action => 'show', + # :id => /[A-Z]\d{5}/ + # + # will have {:controller=>"photos", :action=>"show", :id=>/[A-Z]\d{5}/} + # as requirements. def requirements - # needed for rails `rails routes` @defaults.merge(path.requirements).delete_if { |_, v| /.+?/ == v } diff --git a/actionpack/lib/action_dispatch/journey/router/utils.rb b/actionpack/lib/action_dispatch/journey/router/utils.rb index d641642338..ffcd875b4d 100644 --- a/actionpack/lib/action_dispatch/journey/router/utils.rb +++ b/actionpack/lib/action_dispatch/journey/router/utils.rb @@ -5,7 +5,7 @@ module ActionDispatch # Normalizes URI path. # # Strips off trailing slash and ensures there is a leading slash. - # Also converts downcase url encoded string to uppercase. + # Also converts downcase URL encoded string to uppercase. # # normalize_path("/foo") # => "/foo" # normalize_path("/foo/") # => "/foo" diff --git a/actionpack/lib/action_dispatch/journey/visitors.rb b/actionpack/lib/action_dispatch/journey/visitors.rb index 1c50192867..335797f4b9 100644 --- a/actionpack/lib/action_dispatch/journey/visitors.rb +++ b/actionpack/lib/action_dispatch/journey/visitors.rb @@ -154,7 +154,7 @@ module ActionDispatch end end - # Loop through the requirements AST + # Loop through the requirements AST. class Each < FunctionalVisitor # :nodoc: def visit(node, block) block.call(node) diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb index c61cb3fd68..e565c03a8a 100644 --- a/actionpack/lib/action_dispatch/middleware/cookies.rb +++ b/actionpack/lib/action_dispatch/middleware/cookies.rb @@ -160,7 +160,7 @@ module ActionDispatch # Raised when storing more than 4K of session data. CookieOverflow = Class.new StandardError - # Include in a cookie jar to allow chaining, e.g. cookies.permanent.signed + # Include in a cookie jar to allow chaining, e.g. cookies.permanent.signed. module ChainedCookieJars # Returns a jar that'll automatically set the assigned cookies to have an expiration date 20 years from now. Example: # @@ -345,16 +345,16 @@ module ActionDispatch options[:path] ||= "/" if options[:domain] == :all || options[:domain] == "all" - # if there is a provided tld length then we use it otherwise default domain regexp + # If there is a provided tld length then we use it otherwise default domain regexp. domain_regexp = options[:tld_length] ? /([^.]+\.?){#{options[:tld_length]}}$/ : DOMAIN_REGEXP - # if host is not ip and matches domain regexp + # If host is not ip and matches domain regexp. # (ip confirms to domain regexp so we explicitly check for ip) options[:domain] = if (request.host !~ /^[\d.]+$/) && (request.host =~ domain_regexp) ".#{$&}" end elsif options[:domain].is_a? Array - # if host matches one of the supplied domains without a dot in front of it + # If host matches one of the supplied domains without a dot in front of it. options[:domain] = options[:domain].find { |domain| request.host.include? domain.sub(/^\./, "") } end end @@ -404,7 +404,7 @@ module ActionDispatch @delete_cookies[name.to_s] == options end - # Removes all cookies on the client machine by calling <tt>delete</tt> for each cookie + # Removes all cookies on the client machine by calling <tt>delete</tt> for each cookie. def clear(options = {}) @cookies.each_key { |k| delete(k, options) } end diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb index cbe2f4be4d..6b29ce63ba 100644 --- a/actionpack/lib/action_dispatch/middleware/flash.rb +++ b/actionpack/lib/action_dispatch/middleware/flash.rb @@ -65,7 +65,7 @@ module ActionDispatch self.flash = flash_hash.dup end - if (!session.respond_to?(:loaded?) || session.loaded?) && # (reset_session uses {}, which doesn't implement #loaded?) + if (!session.respond_to?(:loaded?) || session.loaded?) && # reset_session uses {}, which doesn't implement #loaded? session.key?("flash") && session["flash"].nil? session.delete("flash") end diff --git a/actionpack/lib/action_dispatch/middleware/remote_ip.rb b/actionpack/lib/action_dispatch/middleware/remote_ip.rb index 8bae5bfeff..53d5a4918c 100644 --- a/actionpack/lib/action_dispatch/middleware/remote_ip.rb +++ b/actionpack/lib/action_dispatch/middleware/remote_ip.rb @@ -157,13 +157,13 @@ module ActionDispatch def ips_from(header) # :doc: return [] unless header - # Split the comma-separated list into an array of strings + # Split the comma-separated list into an array of strings. ips = header.strip.split(/[,\s]+/) ips.select do |ip| begin - # Only return IPs that are valid according to the IPAddr#new method + # Only return IPs that are valid according to the IPAddr#new method. range = IPAddr.new(ip).to_range - # we want to make sure nobody is sneaking a netmask in + # We want to make sure nobody is sneaking a netmask in. range.begin == range.end rescue ArgumentError nil diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb index d9f018c8ac..21ccf5a097 100644 --- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb @@ -53,7 +53,7 @@ module ActionDispatch rescue ArgumentError => argument_error if argument_error.message =~ %r{undefined class/module ([\w:]*\w)} begin - # Note that the regexp does not allow $1 to end with a ':' + # Note that the regexp does not allow $1 to end with a ':'. $1.constantize rescue LoadError, NameError raise ActionDispatch::Session::SessionRestoreError diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb index 90f26a1c33..5a99714ec2 100644 --- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb @@ -8,7 +8,7 @@ module ActionDispatch # The exceptions app should be passed as parameter on initialization # of ShowExceptions. Every time there is an exception, ShowExceptions will # store the exception in env["action_dispatch.exception"], rewrite the - # PATH_INFO to the exception status code and call the rack app. + # PATH_INFO to the exception status code and call the Rack app. # # If the application returns a "X-Cascade" pass response, this middleware # will send an empty response as result with the correct status code. diff --git a/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb b/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb index 429ea7057c..2d21ae63f5 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb @@ -60,7 +60,7 @@ <%= link_to "Path", "#", 'data-route-helper' => '_path', title: "Returns a relative path (without the http or domain)" %> / <%= link_to "Url", "#", 'data-route-helper' => '_url', - title: "Returns an absolute url (with the http and domain)" %> + title: "Returns an absolute URL (with the http and domain)" %> </th> <th><%# HTTP Verb %> </th> @@ -93,7 +93,7 @@ } } - // get JSON from url and invoke callback with result + // get JSON from URL and invoke callback with result function getJSON(url, success) { var xhr = new XMLHttpRequest(); xhr.open('GET', url); diff --git a/actionpack/lib/action_dispatch/request/session.rb b/actionpack/lib/action_dispatch/request/session.rb index a2a80f39fc..74ba6466cf 100644 --- a/actionpack/lib/action_dispatch/request/session.rb +++ b/actionpack/lib/action_dispatch/request/session.rb @@ -7,10 +7,10 @@ module ActionDispatch ENV_SESSION_KEY = Rack::RACK_SESSION # :nodoc: ENV_SESSION_OPTIONS_KEY = Rack::RACK_SESSION_OPTIONS # :nodoc: - # Singleton object used to determine if an optional param wasn't specified + # Singleton object used to determine if an optional param wasn't specified. Unspecified = Object.new - # Creates a session hash, merging the properties of the previous session if any + # Creates a session hash, merging the properties of the previous session if any. def self.create(store, req, default_options) session_was = find req session = Request::Session.new(store, req) @@ -63,7 +63,7 @@ module ActionDispatch @req = req @delegate = {} @loaded = false - @exists = nil # we haven't checked yet + @exists = nil # We haven't checked yet. end def id @@ -79,7 +79,7 @@ module ActionDispatch options = self.options || {} @by.send(:delete_session, @req, options.id(@req), options) - # Load the new sid to be written with the response + # Load the new sid to be written with the response. @loaded = false load_for_write! end diff --git a/actionpack/lib/action_dispatch/request/utils.rb b/actionpack/lib/action_dispatch/request/utils.rb index 01bc871e5f..3615e4b1d8 100644 --- a/actionpack/lib/action_dispatch/request/utils.rb +++ b/actionpack/lib/action_dispatch/request/utils.rb @@ -40,7 +40,6 @@ module ActionDispatch class ParamEncoder # :nodoc: # Convert nested Hash to HashWithIndifferentAccess. - # def self.normalize_encode_params(params) case params when Array @@ -63,7 +62,7 @@ module ActionDispatch end end - # Remove nils from the params hash + # Remove nils from the params hash. class NoNilParamEncoder < ParamEncoder # :nodoc: def self.handle_array(params) list = super diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb index c554ce98bc..60d4789a63 100644 --- a/actionpack/lib/action_dispatch/routing.rb +++ b/actionpack/lib/action_dispatch/routing.rb @@ -120,7 +120,7 @@ module ActionDispatch # controller :blog do # get 'blog/show' => :list # get 'blog/delete' => :delete - # get 'blog/edit' => :edit + # get 'blog/edit' => :edit # end # # # provides named routes for show, delete, and edit diff --git a/actionpack/lib/action_dispatch/routing/inspector.rb b/actionpack/lib/action_dispatch/routing/inspector.rb index b91ffb8419..9aa4b92df2 100644 --- a/actionpack/lib/action_dispatch/routing/inspector.rb +++ b/actionpack/lib/action_dispatch/routing/inspector.rb @@ -196,7 +196,7 @@ module ActionDispatch @buffer << @view.render(partial: "routes/route", collection: routes) end - # the header is part of the HTML page, so we don't construct it here. + # The header is part of the HTML page, so we don't construct it here. def header(routes) end diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 8d9f70e3c6..8ad17504ae 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -17,9 +17,9 @@ module ActionDispatch CALL = ->(app, req) { app.call req.env } def initialize(app, constraints, strategy) - # Unwrap Constraints objects. I don't actually think it's possible + # Unwrap Constraints objects. I don't actually think it's possible # to pass a Constraints object to this constructor, but there were - # multiple places that kept testing children of this object. I + # multiple places that kept testing children of this object. I # *think* they were just being defensive, but I have no idea. if app.is_a?(self.class) constraints += app.constraints @@ -218,7 +218,7 @@ module ActionDispatch private def add_wildcard_options(options, formatted, path_ast) # Add a constraint for wildcard route to make it non-greedy and match the - # optional format part of the route by default + # optional format part of the route by default. if formatted != false path_ast.grep(Journey::Nodes::Star).each_with_object({}) { |node, hash| hash[node.name.to_sym] ||= /.+?/ @@ -396,7 +396,7 @@ module ActionDispatch end module Base - # Matches a url pattern to one or more routes. + # Matches a URL pattern to one or more routes. # # You should not use the +match+ method in your router # without specifying an HTTP method. @@ -406,7 +406,7 @@ module ActionDispatch # # sets :controller, :action and :id in params # match ':controller/:action/:id', via: [:get, :post] # - # Note that +:controller+, +:action+ and +:id+ are interpreted as url + # Note that +:controller+, +:action+ and +:id+ are interpreted as URL # query parameters and thus available through +params+ in an action. # # If you want to expose your action to GET, use +get+ in the router: @@ -455,7 +455,7 @@ module ActionDispatch # # === Options # - # Any options not seen here are passed on as params with the url. + # Any options not seen here are passed on as params with the URL. # # [:controller] # The route's controller. @@ -660,7 +660,7 @@ module ActionDispatch else prefix_options = options.slice(*_route.segment_keys) prefix_options[:relative_url_root] = "".freeze - # we must actually delete prefix segment keys to avoid passing them to next url_for + # We must actually delete prefix segment keys to avoid passing them to next url_for. _route.segment_keys.each { |k| options.delete(k) } _routes.url_helpers.send("#{name}_path", prefix_options) end @@ -1238,7 +1238,7 @@ module ActionDispatch # # resource :profile # - # creates six different routes in your application, all mapping to + # This creates six different routes in your application, all mapping to # the +Profiles+ controller (note that the controller is named after # the plural): # @@ -1323,14 +1323,14 @@ module ActionDispatch # # resources :posts, path_names: { new: "brand_new" } # - # The above example will now change /posts/new to /posts/brand_new + # The above example will now change /posts/new to /posts/brand_new. # # [:path] # Allows you to change the path prefix for the resource. # # resources :posts, path: 'postings' # - # The resource and all segments will now route to /postings instead of /posts + # The resource and all segments will now route to /postings instead of /posts. # # [:only] # Only generate routes for the given actions. @@ -1525,7 +1525,7 @@ module ActionDispatch end end - # See ActionDispatch::Routing::Mapper::Scoping#namespace + # See ActionDispatch::Routing::Mapper::Scoping#namespace. def namespace(path, options = {}) if resource_scope? nested { super } @@ -1545,7 +1545,7 @@ module ActionDispatch !parent_resource.singleton? && @scope[:shallow] end - # Matches a url pattern to one or more routes. + # Matches a URL pattern to one or more routes. # For more information, see match[rdoc-ref:Base#match]. # # match 'path' => 'controller#action', via: patch @@ -1904,7 +1904,7 @@ module ActionDispatch ast = Journey::Parser.parse path mapping = Mapping.build(@scope, @set, ast, controller, default_action, to, via, formatted, options_constraints, anchor, options) - @set.add_route(mapping, ast, as, anchor) + @set.add_route(mapping, as) end def match_root_route(options) @@ -2003,7 +2003,7 @@ module ActionDispatch # concerns :commentable # end # - # concerns also work in any routes helper that you want to use: + # Concerns also work in any routes helper that you want to use: # # namespace :posts do # concerns :commentable @@ -2020,6 +2020,120 @@ module ActionDispatch end end + module CustomUrls + # Define custom url helpers that will be added to the application's + # routes. This allows you to override and/or replace the default behavior + # of routing helpers, e.g: + # + # direct :homepage do + # "http://www.rubyonrails.org" + # end + # + # direct :commentable do |model| + # [ model, anchor: model.dom_id ] + # end + # + # direct :main do + # { controller: "pages", action: "index", subdomain: "www" } + # end + # + # The return value from the block passed to `direct` must be a valid set of + # arguments for `url_for` which will actually build the URL string. This can + # be one of the following: + # + # * A string, which is treated as a generated URL + # * A hash, e.g. { controller: "pages", action: "index" } + # * An array, which is passed to `polymorphic_url` + # * An Active Model instance + # * An Active Model class + # + # NOTE: Other URL helpers can be called in the block but be careful not to invoke + # your custom URL helper again otherwise it will result in a stack overflow error. + # + # You can also specify default options that will be passed through to + # your URL helper definition, e.g: + # + # direct :browse, page: 1, size: 10 do |options| + # [ :products, options.merge(params.permit(:page, :size).to_h.symbolize_keys) ] + # end + # + # In this instance the `params` object comes from the context in which the the + # block is executed, e.g. generating a URL inside a controller action or a view. + # If the block is executed where there isn't a params object such as this: + # + # Rails.application.routes.url_helpers.browse_path + # + # then it will raise a `NameError`. Because of this you need to be aware of the + # context in which you will use your custom URL helper when defining it. + # + # NOTE: The `direct` method can't be used inside of a scope block such as + # `namespace` or `scope` and will raise an error if it detects that it is. + def direct(name, options = {}, &block) + unless @scope.root? + raise RuntimeError, "The direct method can't be used inside a routes scope block" + end + + @set.add_url_helper(name, options, &block) + end + + # Define custom polymorphic mappings of models to URLs. This alters the + # behavior of `polymorphic_url` and consequently the behavior of + # `link_to` and `form_for` when passed a model instance, e.g: + # + # resource :basket + # + # resolve "Basket" do + # [:basket] + # end + # + # This will now generate "/basket" when a `Basket` instance is passed to + # `link_to` or `form_for` instead of the standard "/baskets/:id". + # + # NOTE: This custom behavior only applies to simple polymorphic URLs where + # a single model instance is passed and not more complicated forms, e.g: + # + # # config/routes.rb + # resource :profile + # namespace :admin do + # resources :users + # end + # + # resolve("User") { [:profile] } + # + # # app/views/application/_menu.html.erb + # link_to "Profile", @current_user + # link_to "Profile", [:admin, @current_user] + # + # The first `link_to` will generate "/profile" but the second will generate + # the standard polymorphic URL of "/admin/users/1". + # + # You can pass options to a polymorphic mapping - the arity for the block + # needs to be two as the instance is passed as the first argument, e.g: + # + # resolve "Basket", anchor: "items" do |basket, options| + # [:basket, options] + # end + # + # This generates the URL "/basket#items" because when the last item in an + # array passed to `polymorphic_url` is a hash then it's treated as options + # to the URL helper that gets called. + # + # NOTE: The `resolve` method can't be used inside of a scope block such as + # `namespace` or `scope` and will raise an error if it detects that it is. + def resolve(*args, &block) + unless @scope.root? + raise RuntimeError, "The resolve method can't be used inside a routes scope block" + end + + options = args.extract_options! + args = args.flatten(1) + + args.each do |klass| + @set.add_polymorphic_mapping(klass, options, &block) + end + end + end + class Scope # :nodoc: OPTIONS = [:path, :shallow_path, :as, :shallow_prefix, :module, :controller, :action, :path_names, :constraints, @@ -2040,6 +2154,14 @@ module ActionDispatch scope_level == :nested end + def null? + @hash.nil? && @parent.nil? + end + + def root? + @parent.null? + end + def resources? scope_level == :resources end @@ -2113,6 +2235,7 @@ module ActionDispatch include Scoping include Concerns include Resources + include CustomUrls end end end diff --git a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb index 432b9bf4c1..e89ea8b21d 100644 --- a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb +++ b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb @@ -40,7 +40,7 @@ module ActionDispatch # # Example usage: # - # edit_polymorphic_path(@post) # => "/posts/1/edit" + # edit_polymorphic_path(@post) # => "/posts/1/edit" # polymorphic_path(@post, format: :pdf) # => "/posts/1.pdf" # # == Usage with mounted engines @@ -103,6 +103,10 @@ module ActionDispatch return polymorphic_url record, options end + if mapping = polymorphic_mapping(record_or_hash_or_array) + return mapping.call(self, [record_or_hash_or_array, options], false) + end + opts = options.dup action = opts.delete :action type = opts.delete(:routing_type) || :url @@ -123,6 +127,10 @@ module ActionDispatch return polymorphic_path record, options end + if mapping = polymorphic_mapping(record_or_hash_or_array) + return mapping.call(self, [record_or_hash_or_array, options], true) + end + opts = options.dup action = opts.delete :action type = :path @@ -156,6 +164,14 @@ module ActionDispatch polymorphic_path(record_or_hash, options.merge(action: action)) end + def polymorphic_mapping(record) + if record.respond_to?(:to_model) + _routes.polymorphic_mappings[record.to_model.model_name.name] + else + _routes.polymorphic_mappings[record.class.name] + end + end + class HelperMethodBuilder # :nodoc: CACHE = { "path" => {}, "url" => {} } @@ -255,9 +271,13 @@ module ActionDispatch [named_route, args] end - def handle_model_call(target, model) - method, args = handle_model model - target.send(method, *args) + def handle_model_call(target, record) + if mapping = polymorphic_mapping(target, record) + mapping.call(target, [record], suffix == "path") + else + method, args = handle_model(record) + target.send(method, *args) + end end def handle_list(list) @@ -303,6 +323,14 @@ module ActionDispatch private + def polymorphic_mapping(target, record) + if record.respond_to?(:to_model) + target._routes.polymorphic_mappings[record.to_model.model_name.name] + else + target._routes.polymorphic_mappings[record.class.name] + end + end + def get_method_for_class(klass) name = @key_strategy.call klass.model_name get_method_for_string name diff --git a/actionpack/lib/action_dispatch/routing/redirection.rb b/actionpack/lib/action_dispatch/routing/redirection.rb index dabc045007..3bcb341758 100644 --- a/actionpack/lib/action_dispatch/routing/redirection.rb +++ b/actionpack/lib/action_dispatch/routing/redirection.rb @@ -36,6 +36,8 @@ module ActionDispatch uri.host ||= req.host uri.port ||= req.port unless req.standard_port? + req.commit_flash + body = %(<html><body>You are being <a href="#{ERB::Util.unwrapped_html_escape(uri.to_s)}">redirected</a>.</body></html>) headers = { @@ -144,7 +146,7 @@ module ActionDispatch # # get 'docs/:article', to: redirect('/wiki/%{article}') # - # Note that if you return a path without a leading slash then the url is prefixed with the + # Note that if you return a path without a leading slash then the URL is prefixed with the # current SCRIPT_NAME environment variable. This is typically '/' but may be different in # a mounted engine or where the application is deployed to a subdirectory of a website. # @@ -163,7 +165,7 @@ module ActionDispatch # Note that the +do end+ syntax for the redirect block wouldn't work, as Ruby would pass # the block to +get+ instead of +redirect+. Use <tt>{ ... }</tt> instead. # - # The options version of redirect allows you to supply only the parts of the url which need + # 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. # # get 'stores/:name', to: redirect(subdomain: 'stores', path: '/%{name}') diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 5b873aeab7..129e90037e 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -73,6 +73,7 @@ module ActionDispatch @routes = {} @path_helpers = Set.new @url_helpers = Set.new + @custom_helpers = Set.new @url_helpers_module = Module.new @path_helpers_module = Module.new end @@ -88,16 +89,30 @@ module ActionDispatch def clear! @path_helpers.each do |helper| - @path_helpers_module.send :undef_method, helper + @path_helpers_module.send :remove_method, helper end @url_helpers.each do |helper| - @url_helpers_module.send :undef_method, helper + @url_helpers_module.send :remove_method, helper + end + + @custom_helpers.each do |helper| + path_name = :"#{helper}_path" + url_name = :"#{helper}_url" + + if @path_helpers_module.method_defined?(path_name) + @path_helpers_module.send :remove_method, path_name + end + + if @url_helpers_module.method_defined?(url_name) + @url_helpers_module.send :remove_method, url_name + end end @routes.clear @path_helpers.clear @url_helpers.clear + @custom_helpers.clear end def add(name, route) @@ -143,6 +158,23 @@ module ActionDispatch routes.length end + def add_url_helper(name, defaults, &block) + @custom_helpers << name + helper = CustomUrlHelper.new(name, defaults, &block) + + @path_helpers_module.module_eval do + define_method(:"#{name}_path") do |*args| + helper.call(self, args, true) + end + end + + @url_helpers_module.module_eval do + define_method(:"#{name}_url") do |*args| + helper.call(self, args, false) + end + end + end + class UrlHelper def self.create(route, options, route_name, url_strategy) if optimize_helper?(route) @@ -263,7 +295,7 @@ module ActionDispatch end private - # Create a url helper allowing ordered parameters to be associated + # Create a URL helper allowing ordered parameters to be associated # with corresponding dynamic segments, so you can do: # # foo_url(bar, baz, bang) @@ -305,7 +337,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 - attr_reader :env_key + attr_reader :env_key, :polymorphic_mappings alias :routes :set @@ -347,6 +379,7 @@ module ActionDispatch @set = Journey::Routes.new @router = Journey::Router.new @set @formatter = Journey::Formatter.new self + @polymorphic_mappings = {} end def eager_load! @@ -408,6 +441,7 @@ module ActionDispatch named_routes.clear set.clear formatter.clear + @polymorphic_mappings.clear @prepend.each { |blk| eval_block(blk) } end @@ -452,17 +486,50 @@ module ActionDispatch # Define url_for in the singleton level so one can do: # Rails.application.routes.url_helpers.url_for(args) - @_routes = routes + proxy_class = Class.new do + include UrlFor + include routes.named_routes.path_helpers_module + include routes.named_routes.url_helpers_module + + attr_reader :_routes + + def initialize(routes) + @_routes = routes + end + + def optimize_routes_generation? + @_routes.optimize_routes_generation? + end + end + + @_proxy = proxy_class.new(routes) + class << self def url_for(options) - @_routes.url_for(options) + @_proxy.url_for(options) + end + + def full_url_for(options) + @_proxy.full_url_for(options) + end + + def route_for(name, *args) + @_proxy.route_for(name, *args) end def optimize_routes_generation? - @_routes.optimize_routes_generation? + @_proxy.optimize_routes_generation? end - attr_reader :_routes + def polymorphic_url(record_or_hash_or_array, options = {}) + @_proxy.polymorphic_url(record_or_hash_or_array, options) + end + + def polymorphic_path(record_or_hash_or_array, options = {}) + @_proxy.polymorphic_path(record_or_hash_or_array, options) + end + + def _routes; @_proxy._routes; end def url_options; {}; end end @@ -506,7 +573,7 @@ module ActionDispatch routes.empty? end - def add_route(mapping, path_ast, name, anchor) + def add_route(mapping, name) raise ArgumentError, "Invalid route name: '#{name}'" unless name.blank? || name.to_s.match(/^[_a-z]\w*$/i) if name && named_routes[name] @@ -523,20 +590,58 @@ module ActionDispatch if route.segment_keys.include?(:controller) ActiveSupport::Deprecation.warn(<<-MSG.squish) Using a dynamic :controller segment in a route is deprecated and - will be removed in Rails 5.1. + will be removed in Rails 5.2. MSG end if route.segment_keys.include?(:action) ActiveSupport::Deprecation.warn(<<-MSG.squish) Using a dynamic :action segment in a route is deprecated and - will be removed in Rails 5.1. + will be removed in Rails 5.2. MSG end route end + def add_polymorphic_mapping(klass, options, &block) + @polymorphic_mappings[klass] = CustomUrlHelper.new(klass, options, &block) + end + + def add_url_helper(name, options, &block) + named_routes.add_url_helper(name, options, &block) + end + + class CustomUrlHelper + attr_reader :name, :defaults, :block + + def initialize(name, defaults, &block) + @name = name + @defaults = defaults + @block = block + end + + def call(t, args, only_path = false) + options = args.extract_options! + url = t.full_url_for(eval_block(t, args, options)) + + if only_path + "/" + url.partition(%r{(?<!/)/(?!/)}).last + else + url + end + end + + private + def eval_block(t, args, options) + t.instance_exec(*args, merge_defaults(options), &block) + end + + def merge_defaults(options) + defaults ? defaults.merge(options) : options + end + end + class Generator PARAMETERIZE = lambda do |name, value| if name == :controller @@ -751,8 +856,7 @@ module ActionDispatch params[key] = URI.parser.unescape(value) end end - old_params = req.path_parameters - req.path_parameters = old_params.merge params + req.path_parameters = params app = route.app if app.matches?(req) && app.dispatcher? begin diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb index 3e564f13d8..008216cc80 100644 --- a/actionpack/lib/action_dispatch/routing/url_for.rb +++ b/actionpack/lib/action_dispatch/routing/url_for.rb @@ -113,10 +113,10 @@ module ActionDispatch default_url_options end - # Generate a url based on the options provided, default_url_options and the + # Generate a URL based on the options provided, default_url_options and the # routes defined in routes.rb. The following options are supported: # - # * <tt>:only_path</tt> - If true, the relative url is returned. Defaults to +false+. + # * <tt>:only_path</tt> - If true, the relative URL is returned. Defaults to +false+. # * <tt>:protocol</tt> - The protocol to connect to. Defaults to 'http'. # * <tt>:host</tt> - Specifies the host the link should be targeted at. # If <tt>:only_path</tt> is false, this option must be @@ -164,6 +164,10 @@ module ActionDispatch # implicitly used by +url_for+ can always be overwritten like shown on the # last +url_for+ calls. def url_for(options = nil) + full_url_for(options) + end + + def full_url_for(options = nil) # :nodoc: case options when nil _routes.url_for(url_options.symbolize_keys) @@ -192,6 +196,10 @@ module ActionDispatch end end + def route_for(name, *args) # :nodoc: + public_send(:"#{name}_url", *args) + end + protected def optimize_routes_generation? diff --git a/actionpack/lib/action_dispatch/system_test_case.rb b/actionpack/lib/action_dispatch/system_test_case.rb new file mode 100644 index 0000000000..98fdb36c91 --- /dev/null +++ b/actionpack/lib/action_dispatch/system_test_case.rb @@ -0,0 +1,125 @@ +require "capybara/dsl" +require "capybara/minitest" +require "action_controller" +require "action_dispatch/system_testing/driver" +require "action_dispatch/system_testing/server" +require "action_dispatch/system_testing/test_helpers/screenshot_helper" +require "action_dispatch/system_testing/test_helpers/setup_and_teardown" + +module ActionDispatch + # = System Testing + # + # System tests let you test applications in the browser. Because system + # tests use a real browser experience, you can test all of your JavaScript + # easily from your test suite. + # + # To create a system test in your application, extend your test class + # from <tt>ApplicationSystemTestCase</tt>. System tests use Capybara as a + # base and allow you to configure the settings through your + # <tt>application_system_test_case.rb</tt> file that is generated with a new + # application or scaffold. + # + # Here is an example system test: + # + # require 'application_system_test_case' + # + # class Users::CreateTest < ApplicationSystemTestCase + # test "adding a new user" do + # visit users_path + # click_on 'New User' + # + # fill_in 'Name', with: 'Arya' + # click_on 'Create User' + # + # assert_text 'Arya' + # end + # end + # + # When generating an application or scaffold, an +application_system_test_case.rb+ + # file will also be generated containing the base class for system testing. + # This is where you can change the driver, add Capybara settings, and other + # configuration for your system tests. + # + # require "test_helper" + # + # class ApplicationSystemTestCase < ActionDispatch::SystemTestCase + # driven_by :selenium, using: :chrome, screen_size: [1400, 1400] + # end + # + # By default, <tt>ActionDispatch::SystemTestCase</tt> is driven by the + # Selenium driver, with the Chrome browser, and a browser size of 1400x1400. + # + # Changing the driver configuration options is easy. Let's say you want to use + # the Firefox browser instead of Chrome. In your +application_system_test_case.rb+ + # file add the following: + # + # require "test_helper" + # + # class ApplicationSystemTestCase < ActionDispatch::SystemTestCase + # driven_by :selenium, using: :firefox + # end + # + # +driven_by+ has a required argument for the driver name. The keyword + # arguments are +:using+ for the browser and +:screen_size+ to change the + # size of the browser screen. These two options are not applicable for + # headless drivers and will be silently ignored if passed. + # + # To use a headless driver, like Poltergeist, update your Gemfile to use + # Poltergeist instead of Selenium and then declare the driver name in the + # +application_system_test_case.rb+ file. In this case you would leave out the +:using+ + # option because the driver is headless. + # + # require "test_helper" + # require "capybara/poltergeist" + # + # class ApplicationSystemTestCase < ActionDispatch::SystemTestCase + # driven_by :poltergeist + # end + # + # Because <tt>ActionDispatch::SystemTestCase</tt> is a shim between Capybara + # and Rails, any driver that is supported by Capybara is supported by system + # tests as long as you include the required gems and files. + class SystemTestCase < IntegrationTest + include Capybara::DSL + include Capybara::Minitest::Assertions + include SystemTesting::TestHelpers::SetupAndTeardown + include SystemTesting::TestHelpers::ScreenshotHelper + + def initialize(*) # :nodoc: + super + self.class.driver.use + end + + def self.start_application # :nodoc: + Capybara.app = Rack::Builder.new do + map "/" do + run Rails.application + end + end + + SystemTesting::Server.new.run + end + + class_attribute :driver, instance_accessor: false + + # System Test configuration options + # + # The default settings are Selenium, using Chrome, with a screen size + # of 1400x1400. + # + # Examples: + # + # driven_by :poltergeist + # + # driven_by :selenium, using: :firefox + # + # driven_by :selenium, screen_size: [800, 800] + def self.driven_by(driver, using: :chrome, screen_size: [1400, 1400], options: {}) + self.driver = SystemTesting::Driver.new(driver, using: using, screen_size: screen_size, options: options) + end + + driven_by :selenium + end + + SystemTestCase.start_application +end diff --git a/actionpack/lib/action_dispatch/system_testing/driver.rb b/actionpack/lib/action_dispatch/system_testing/driver.rb new file mode 100644 index 0000000000..5cf17883f7 --- /dev/null +++ b/actionpack/lib/action_dispatch/system_testing/driver.rb @@ -0,0 +1,34 @@ +module ActionDispatch + module SystemTesting + class Driver # :nodoc: + def initialize(name, **options) + @name = name + @browser = options[:using] + @screen_size = options[:screen_size] + @options = options[:options] + end + + def use + register if selenium? + setup + end + + private + def selenium? + @name == :selenium + end + + def register + Capybara.register_driver @name do |app| + Capybara::Selenium::Driver.new(app, { browser: @browser }.merge(@options)).tap do |driver| + driver.browser.manage.window.size = Selenium::WebDriver::Dimension.new(*@screen_size) + end + end + end + + def setup + Capybara.current_driver = @name + end + end + end +end diff --git a/actionpack/lib/action_dispatch/system_testing/server.rb b/actionpack/lib/action_dispatch/system_testing/server.rb new file mode 100644 index 0000000000..4a214ef713 --- /dev/null +++ b/actionpack/lib/action_dispatch/system_testing/server.rb @@ -0,0 +1,32 @@ +require "rack/handler/puma" + +module ActionDispatch + module SystemTesting + class Server # :nodoc: + def run + register + setup + end + + private + def register + Capybara.register_server :rails_puma do |app, port, host| + Rack::Handler::Puma.run(app, Port: port, Threads: "0:1") + end + end + + def setup + set_server + set_port + end + + def set_server + Capybara.server = :rails_puma + end + + def set_port + Capybara.always_include_port = true + end + end + end +end diff --git a/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb b/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb new file mode 100644 index 0000000000..859d68e475 --- /dev/null +++ b/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb @@ -0,0 +1,94 @@ +module ActionDispatch + module SystemTesting + module TestHelpers + # Screenshot helper for system testing. + module ScreenshotHelper + # Takes a screenshot of the current page in the browser. + # + # +take_screenshot+ can be used at any point in your system tests to take + # a screenshot of the current state. This can be useful for debugging or + # automating visual testing. + # + # The screenshot will be displayed in your console, if supported. + # + # You can set the +RAILS_SYSTEM_TESTING_SCREENSHOT+ environment variable to + # control the output. Possible values are: + # * [+inline+ (default)] display the screenshot in the terminal using the + # iTerm image protocol (http://iterm2.com/documentation-images.html). + # * [+simple+] only display the screenshot path. + # This is the default value if the +CI+ environment variables + # is defined. + # * [+artifact+] display the screenshot in the terminal, using the terminal + # artifact format (http://buildkite.github.io/terminal/inline-images/). + def take_screenshot + save_image + puts display_image + end + + # Takes a screenshot of the current page in the browser if the test + # failed. + # + # +take_failed_screenshot+ is included in <tt>application_system_test_case.rb</tt> + # that is generated with the application. To take screenshots when a test + # fails add +take_failed_screenshot+ to the teardown block before clearing + # sessions. + def take_failed_screenshot + take_screenshot if failed? && supports_screenshot? + end + + private + def image_name + failed? ? "failures_#{method_name}" : method_name + end + + def image_path + "tmp/screenshots/#{image_name}.png" + end + + def save_image + page.save_screenshot(Rails.root.join(image_path)) + end + + def output_type + # Environment variables have priority + output_type = ENV["RAILS_SYSTEM_TESTING_SCREENSHOT"] || ENV["CAPYBARA_INLINE_SCREENSHOT"] + + # If running in a CI environment, default to simple + output_type ||= "simple" if ENV["CI"] + + # Default + output_type ||= "inline" + + output_type + end + + def display_image + message = "[Screenshot]: #{image_path}\n" + + case output_type + when "artifact" + message << "\e]1338;url=artifact://#{image_path}\a\n" + when "inline" + name = inline_base64(File.basename(image_path)) + image = inline_base64(File.read(image_path)) + message << "\e]1337;File=name=#{name};height=400px;inline=1:#{image}\a\n" + end + + message + end + + def inline_base64(path) + Base64.encode64(path).gsub("\n", "") + end + + def failed? + !passed? && !skipped? + end + + def supports_screenshot? + Capybara.current_driver != :rack_test + end + end + end + end +end diff --git a/actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb b/actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb new file mode 100644 index 0000000000..187ba2cc5f --- /dev/null +++ b/actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb @@ -0,0 +1,20 @@ +module ActionDispatch + module SystemTesting + module TestHelpers + module SetupAndTeardown # :nodoc: + DEFAULT_HOST = "127.0.0.1" + + def before_setup + host! DEFAULT_HOST + super + end + + def after_teardown + take_failed_screenshot + Capybara.reset_sessions! + super + end + end + end + end +end diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb index 817737341c..1baf979ac9 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/response.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb @@ -45,7 +45,7 @@ module ActionDispatch # # Asserts that the redirection was to the named route login_url # assert_redirected_to login_url # - # # Asserts that the redirection was to the url for @customer + # # Asserts that the redirection was to the URL for @customer # assert_redirected_to @customer # # # Asserts that the redirection matches the regular expression diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb index 37c1ca02b6..8645df4370 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb @@ -18,8 +18,8 @@ module ActionDispatch # assert_recognizes({controller: 'items', action: 'create'}, {path: 'items', method: :post}) # # You can also pass in +extras+ with a hash containing URL parameters that would normally be in the query string. This can be used - # to assert that values in the query string will end up in the params hash correctly. To test query strings you must use the - # extras argument, appending the query string on the path directly will not work. For example: + # to assert that values in the query string will end up in the params hash correctly. To test query strings you must use the extras + # argument because appending the query string on the path directly will not work. For example: # # # Asserts that a path of '/items/list/1?view=print' returns the correct options # assert_recognizes({controller: 'items', action: 'list', id: '1', view: 'print'}, 'items/list/1', { view: "print" }) @@ -132,8 +132,7 @@ module ActionDispatch end # A helper to make it easier to test different route configurations. - # This method temporarily replaces @routes - # with a new RouteSet instance. + # This method temporarily replaces @routes with a new RouteSet instance. # # The new instance is yielded to the passed block. Typically the block # will create some routes using <tt>set.draw { match ... }</tt>: @@ -186,7 +185,6 @@ module ActionDispatch method = :get end - # Assume given controller request = ActionController::TestRequest.create @controller.class if path =~ %r{://} diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index 5fa0b727ab..2e2db98ad6 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -192,11 +192,10 @@ module ActionDispatch # HTTP methods in integration tests. +#process+ is only required when using a # request method that doesn't have a method defined in the integration tests. # - # This method returns a Response object, which one can use to - # inspect the details of the response. Furthermore, if this method was - # called from an ActionDispatch::IntegrationTest object, then that - # object's <tt>@response</tt> instance variable will point to the same - # response object. + # This method returns the response status, after performing the request. + # Furthermore, if this method was called from an ActionDispatch::IntegrationTest object, + # then that object's <tt>@response</tt> instance variable will point to a Response object + # which one can use to inspect the details of the response. # # Example: # process :get, '/author', params: { since: 201501011400 } @@ -247,7 +246,7 @@ module ActionDispatch wrapped_headers["HTTP_ACCEPT"] ||= [Mime[:js], Mime[:html], Mime[:xml], "text/xml", "*/*"].join(", ") end - # this modifies the passed request_env directly + # This modifies the passed request_env directly. if wrapped_headers.present? Http::Headers.from_hash(request_env).merge!(wrapped_headers) end @@ -258,7 +257,7 @@ module ActionDispatch session = Rack::Test::Session.new(_mock_session) # NOTE: rack-test v0.5 doesn't build a default uri correctly - # Make sure requested path is always a full uri + # Make sure requested path is always a full URI. session.request(build_full_uri(path, request_env), request_env) @request_count += 1 @@ -325,8 +324,8 @@ module ActionDispatch def create_session(app) klass = APP_SESSIONS[app] ||= Class.new(Integration::Session) { - # If the app is a Rails app, make url_helpers available on the session - # This makes app.url_for and app.foo_path available in the console + # If the app is a Rails app, make url_helpers available on the session. + # This makes app.url_for and app.foo_path available in the console. if app.respond_to?(:routes) include app.routes.url_helpers include app.routes.mounted_helpers @@ -572,7 +571,7 @@ module ActionDispatch # end # # assert_response :success - # assert_equal({ id: Arcticle.last.id, title: "Ahoy!" }, response.parsed_body) + # assert_equal({ id: Article.last.id, title: "Ahoy!" }, response.parsed_body) # end # end # diff --git a/actionpack/lib/action_dispatch/testing/test_request.rb b/actionpack/lib/action_dispatch/testing/test_request.rb index 91b25ec155..ec949c869b 100644 --- a/actionpack/lib/action_dispatch/testing/test_request.rb +++ b/actionpack/lib/action_dispatch/testing/test_request.rb @@ -9,7 +9,7 @@ module ActionDispatch "HTTP_USER_AGENT" => "Rails Testing", ) - # Create a new test request with default `env` values + # Create a new test request with default `env` values. def self.create(env = {}) env = Rails.application.env_config.merge(env) if defined?(Rails.application) && Rails.application env["rack.request.cookie_hash"] ||= {}.with_indifferent_access |