diff options
Diffstat (limited to 'actionpack/lib')
24 files changed, 194 insertions, 166 deletions
diff --git a/actionpack/lib/abstract_controller/callbacks.rb b/actionpack/lib/abstract_controller/callbacks.rb index 146d17cf40..42bab411d2 100644 --- a/actionpack/lib/abstract_controller/callbacks.rb +++ b/actionpack/lib/abstract_controller/callbacks.rb @@ -103,6 +103,10 @@ module AbstractController # :call-seq: before_action(names, block) # # Append a callback before actions. See _insert_callbacks for parameter details. + # + # If the callback renders or redirects, the action will not run. If there + # are additional callbacks scheduled to run after that callback, they are + # also cancelled. ## # :method: prepend_before_action @@ -110,6 +114,10 @@ module AbstractController # :call-seq: prepend_before_action(names, block) # # Prepend a callback before actions. See _insert_callbacks for parameter details. + # + # If the callback renders or redirects, the action will not run. If there + # are additional callbacks scheduled to run after that callback, they are + # also cancelled. ## # :method: skip_before_action @@ -124,6 +132,10 @@ module AbstractController # :call-seq: append_before_action(names, block) # # Append a callback before actions. See _insert_callbacks for parameter details. + # + # If the callback renders or redirects, the action will not run. If there + # are additional callbacks scheduled to run after that callback, they are + # also cancelled. ## # :method: after_action diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index f43784f9f2..29d61c3ceb 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -25,6 +25,7 @@ module ActionController autoload :ContentSecurityPolicy autoload :Cookies autoload :DataStreaming + autoload :DefaultHeaders autoload :EtagWithTemplateDigest autoload :EtagWithFlash autoload :Flash diff --git a/actionpack/lib/action_controller/api.rb b/actionpack/lib/action_controller/api.rb index b192e496de..93ffff1bd6 100644 --- a/actionpack/lib/action_controller/api.rb +++ b/actionpack/lib/action_controller/api.rb @@ -122,6 +122,7 @@ module ActionController ForceSSL, DataStreaming, + DefaultHeaders, # Before callbacks should also be executed as early as possible, so # also include them at the bottom. diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 204a3d400c..3378d6db0f 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -232,6 +232,7 @@ module ActionController HttpAuthentication::Basic::ControllerMethods, HttpAuthentication::Digest::ControllerMethods, HttpAuthentication::Token::ControllerMethods, + DefaultHeaders, # Before callbacks should also be executed as early as possible, so # also include them at the bottom. @@ -264,12 +265,6 @@ module ActionController PROTECTED_IVARS end - def self.make_response!(request) - ActionDispatch::Response.create.tap do |res| - res.request = request - end - end - ActiveSupport.run_load_hooks(:action_controller_base, self) ActiveSupport.run_load_hooks(:action_controller, self) end diff --git a/actionpack/lib/action_controller/metal/content_security_policy.rb b/actionpack/lib/action_controller/metal/content_security_policy.rb index 95f2f3242d..b8fab4ebe3 100644 --- a/actionpack/lib/action_controller/metal/content_security_policy.rb +++ b/actionpack/lib/action_controller/metal/content_security_policy.rb @@ -14,13 +14,17 @@ module ActionController #:nodoc: end module ClassMethods - def content_security_policy(**options, &block) + def content_security_policy(enabled = true, **options, &block) before_action(options) do if block_given? - policy = request.content_security_policy.clone + policy = current_content_security_policy yield policy request.content_security_policy = policy end + + unless enabled + request.content_security_policy = nil + end end end @@ -40,5 +44,9 @@ module ActionController #:nodoc: def content_security_policy_nonce request.content_security_policy_nonce end + + def current_content_security_policy + request.content_security_policy.try(:clone) || ActionDispatch::ContentSecurityPolicy.new + end end end diff --git a/actionpack/lib/action_controller/metal/default_headers.rb b/actionpack/lib/action_controller/metal/default_headers.rb new file mode 100644 index 0000000000..eef0602fcd --- /dev/null +++ b/actionpack/lib/action_controller/metal/default_headers.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module ActionController + # Allows configuring default headers that will be automatically merged into + # each response. + module DefaultHeaders + extend ActiveSupport::Concern + + module ClassMethods + def make_response!(request) + ActionDispatch::Response.create.tap do |res| + res.request = request + end + end + end + end +end diff --git a/actionpack/lib/action_controller/metal/exceptions.rb b/actionpack/lib/action_controller/metal/exceptions.rb index a65857d6ef..58db4a1458 100644 --- a/actionpack/lib/action_controller/metal/exceptions.rb +++ b/actionpack/lib/action_controller/metal/exceptions.rb @@ -22,7 +22,7 @@ module ActionController end end - class ActionController::UrlGenerationError < ActionControllerError #:nodoc: + class UrlGenerationError < ActionControllerError #:nodoc: end class MethodNotAllowed < ActionControllerError #:nodoc: diff --git a/actionpack/lib/action_controller/metal/force_ssl.rb b/actionpack/lib/action_controller/metal/force_ssl.rb index 7de500d119..8d53a30e93 100644 --- a/actionpack/lib/action_controller/metal/force_ssl.rb +++ b/actionpack/lib/action_controller/metal/force_ssl.rb @@ -4,18 +4,10 @@ require "active_support/core_ext/hash/except" require "active_support/core_ext/hash/slice" module ActionController - # This module provides a method which will redirect the browser to use the secured HTTPS - # protocol. This will ensure that users' sensitive information will be - # transferred safely over the internet. You _should_ always force the browser - # to use HTTPS when you're transferring sensitive information such as - # user authentication, account information, or credit card information. - # - # Note that if you are really concerned about your application security, - # you might consider using +config.force_ssl+ in your config file instead. - # That will ensure all the data is transferred via HTTPS, and will - # prevent the user from getting their session hijacked when accessing the - # site over unsecured HTTP protocol. - module ForceSSL + # This module is deprecated in favor of +config.force_ssl+ in your environment + # config file. This will ensure all communication to non-whitelisted endpoints + # served by your application occurs over HTTPS. + module ForceSSL # :nodoc: extend ActiveSupport::Concern include AbstractController::Callbacks @@ -23,45 +15,17 @@ module ActionController URL_OPTIONS = [:protocol, :host, :domain, :subdomain, :port, :path] REDIRECT_OPTIONS = [:status, :flash, :alert, :notice] - module ClassMethods - # Force the request to this particular controller or specified actions to be - # through the HTTPS protocol. - # - # If you need to disable this for any reason (e.g. development) then you can use - # an +:if+ or +:unless+ condition. - # - # class AccountsController < ApplicationController - # force_ssl if: :ssl_configured? - # - # def ssl_configured? - # !Rails.env.development? - # end - # end - # - # ==== URL Options - # You can pass any of the following options to affect the redirect URL - # * <tt>host</tt> - Redirect to a different host name - # * <tt>subdomain</tt> - Redirect to a different subdomain - # * <tt>domain</tt> - Redirect to a different domain - # * <tt>port</tt> - Redirect to a non-standard port - # * <tt>path</tt> - Redirect to a different path - # - # ==== Redirect Options - # You can pass any of the following options to affect the redirect status and response - # * <tt>status</tt> - Redirect with a custom status (default is 301 Moved Permanently) - # * <tt>flash</tt> - Set a flash message when redirecting - # * <tt>alert</tt> - Set an alert message when redirecting - # * <tt>notice</tt> - Set a notice message when redirecting - # - # ==== Action Options - # You can pass any of the following options to affect the before_action callback - # * <tt>only</tt> - The callback should be run only for this action - # * <tt>except</tt> - The callback should be run for all actions except this action - # * <tt>if</tt> - A symbol naming an instance method or a proc; the - # callback will be called only when it returns a true value. - # * <tt>unless</tt> - A symbol naming an instance method or a proc; the - # callback will be called only when it returns a false value. + module ClassMethods # :nodoc: def force_ssl(options = {}) + ActiveSupport::Deprecation.warn(<<-MESSAGE.squish) + Controller-level `force_ssl` is deprecated and will be removed from + Rails 6.1. Please enable `config.force_ssl` in your environment + configuration to enable the ActionDispatch::SSL middleware to more + fully enforce that your application communicate over HTTPS. If needed, + you can use `config.ssl_options` to exempt matching endpoints from + being redirected to HTTPS. + MESSAGE + action_options = options.slice(*ACTION_OPTIONS) redirect_options = options.except(*ACTION_OPTIONS) before_action(action_options) do @@ -70,11 +34,6 @@ module ActionController end end - # Redirect the existing request to use the HTTPS protocol. - # - # ==== Parameters - # * <tt>host_or_options</tt> - Either a host name or any of the URL and - # redirect options available to the <tt>force_ssl</tt> method. def force_ssl_redirect(host_or_options = nil) unless request.ssl? options = { diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb index 94092de96c..fc9cf8aaff 100644 --- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb @@ -417,7 +417,7 @@ module ActionController #:nodoc: NULL_ORIGIN_MESSAGE = <<~MSG The browser returned a 'null' origin for a request with origin-based forgery protection turned on. This usually - means you have the 'no-referrer' Referrer-Policy header enabled, or that you the request came from a site that + means you have the 'no-referrer' Referrer-Policy header enabled, or that the request came from a site that refused to give its origin. This makes it impossible for Rails to verify the source of the requests. Likely the best solution is to change your referrer policy to something less strict like same-origin or strict-same-origin. If you cannot change the referrer policy, you can disable origin checking with the diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb index 615c90c496..5a06bf86e3 100644 --- a/actionpack/lib/action_controller/metal/strong_parameters.rb +++ b/actionpack/lib/action_controller/metal/strong_parameters.rb @@ -374,7 +374,7 @@ module ActionController # Person.new(params) # => #<Person id: nil, name: "Francesco"> def permit! each_pair do |key, value| - Array.wrap(value).each do |v| + Array.wrap(value).flatten.each do |v| v.permit! if v.respond_to? :permit! end end @@ -580,19 +580,18 @@ module ActionController ) end - if Hash.method_defined?(:dig) - # Extracts the nested parameter from the given +keys+ by calling +dig+ - # at each step. Returns +nil+ if any intermediate step is +nil+. - # - # params = ActionController::Parameters.new(foo: { bar: { baz: 1 } }) - # params.dig(:foo, :bar, :baz) # => 1 - # params.dig(:foo, :zot, :xyz) # => nil - # - # params2 = ActionController::Parameters.new(foo: [10, 11, 12]) - # params2.dig(:foo, 1) # => 11 - def dig(*keys) - convert_value_to_parameters(@parameters.dig(*keys)) - end + # Extracts the nested parameter from the given +keys+ by calling +dig+ + # at each step. Returns +nil+ if any intermediate step is +nil+. + # + # params = ActionController::Parameters.new(foo: { bar: { baz: 1 } }) + # params.dig(:foo, :bar, :baz) # => 1 + # params.dig(:foo, :zot, :xyz) # => nil + # + # params2 = ActionController::Parameters.new(foo: [10, 11, 12]) + # params2.dig(:foo, 1) # => 11 + def dig(*keys) + convert_hashes_to_parameters(keys.first, @parameters[keys.first]) + @parameters.dig(*keys) end # Returns a new <tt>ActionController::Parameters</tt> instance that diff --git a/actionpack/lib/action_dispatch/http/content_security_policy.rb b/actionpack/lib/action_dispatch/http/content_security_policy.rb index a3407c9698..17e72b46ff 100644 --- a/actionpack/lib/action_dispatch/http/content_security_policy.rb +++ b/actionpack/lib/action_dispatch/http/content_security_policy.rb @@ -21,13 +21,8 @@ module ActionDispatch #:nodoc: return response if policy_present?(headers) if policy = request.content_security_policy - if policy.directives["script-src"] - if nonce = request.content_security_policy_nonce - policy.directives["script-src"] << "'nonce-#{nonce}'" - end - end - - headers[header_name(request)] = policy.build(request.controller_instance) + nonce = request.content_security_policy_nonce + headers[header_name(request)] = policy.build(request.controller_instance, nonce) end response @@ -113,7 +108,9 @@ module ActionDispatch #:nodoc: blob: "blob:", filesystem: "filesystem:", report_sample: "'report-sample'", - strict_dynamic: "'strict-dynamic'" + strict_dynamic: "'strict-dynamic'", + ws: "ws:", + wss: "wss:" }.freeze DIRECTIVES = { @@ -134,7 +131,9 @@ module ActionDispatch #:nodoc: worker_src: "worker-src" }.freeze - private_constant :MAPPINGS, :DIRECTIVES + NONCE_DIRECTIVES = %w[script-src].freeze + + private_constant :MAPPINGS, :DIRECTIVES, :NONCE_DIRECTIVES attr_reader :directives @@ -203,8 +202,8 @@ module ActionDispatch #:nodoc: end end - def build(context = nil) - build_directives(context).compact.join("; ") + def build(context = nil, nonce = nil) + build_directives(context, nonce).compact.join("; ") end private @@ -227,10 +226,14 @@ module ActionDispatch #:nodoc: end end - def build_directives(context) + def build_directives(context, nonce) @directives.map do |directive, sources| if sources.is_a?(Array) - "#{directive} #{build_directive(sources, context).join(' ')}" + if nonce && nonce_directive?(directive) + "#{directive} #{build_directive(sources, context).join(' ')} 'nonce-#{nonce}'" + else + "#{directive} #{build_directive(sources, context).join(' ')}" + end elsif sources directive else @@ -259,5 +262,9 @@ module ActionDispatch #:nodoc: raise RuntimeError, "Unexpected content security policy source: #{source.inspect}" end end + + def nonce_directive?(directive) + NONCE_DIRECTIVES.include?(directive) + end end end diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb index 3e11846778..fd05eec172 100644 --- a/actionpack/lib/action_dispatch/middleware/flash.rb +++ b/actionpack/lib/action_dispatch/middleware/flash.rb @@ -73,7 +73,7 @@ module ActionDispatch end end - def reset_session # :nodoc + def reset_session # :nodoc: super self.flash = nil end diff --git a/actionpack/lib/action_dispatch/middleware/ssl.rb b/actionpack/lib/action_dispatch/middleware/ssl.rb index 6d9f36ad75..240269d1c7 100644 --- a/actionpack/lib/action_dispatch/middleware/ssl.rb +++ b/actionpack/lib/action_dispatch/middleware/ssl.rb @@ -15,6 +15,8 @@ module ActionDispatch # # config.ssl_options = { redirect: { exclude: -> request { request.path =~ /healthcheck/ } } } # + # Cookies will not be flagged as secure for excluded requests. + # # 2. <b>Secure cookies</b>: Sets the +secure+ flag on cookies to tell browsers they # must not be sent along with +http://+ requests. Enabled by default. Set # +config.ssl_options+ with <tt>secure_cookies: false</tt> to disable this feature. @@ -71,7 +73,7 @@ module ActionDispatch if request.ssl? @app.call(env).tap do |status, headers, body| set_hsts_header! headers - flag_cookies_as_secure! headers if @secure_cookies + flag_cookies_as_secure! headers if @secure_cookies && !@exclude.call(request) end else return redirect_to_https request unless @exclude.call(request) diff --git a/actionpack/lib/action_dispatch/middleware/static.rb b/actionpack/lib/action_dispatch/middleware/static.rb index 23492e14eb..acd999444a 100644 --- a/actionpack/lib/action_dispatch/middleware/static.rb +++ b/actionpack/lib/action_dispatch/middleware/static.rb @@ -16,7 +16,7 @@ module ActionDispatch # does not exist, a 404 "File not Found" response will be returned. class FileHandler def initialize(root, index: "index", headers: {}) - @root = root.chomp("/") + @root = root.chomp("/").b @file_server = ::Rack::File.new(@root, headers) @index = index end @@ -35,7 +35,7 @@ module ActionDispatch paths = [path, "#{path}#{ext}", "#{path}/#{@index}#{ext}"] if match = paths.detect { |p| - path = File.join(@root, p.dup.force_encoding(Encoding::UTF_8)) + path = File.join(@root, p.b) begin File.file?(path) && File.readable?(path) rescue SystemCallError @@ -43,7 +43,7 @@ module ActionDispatch end } - return ::Rack::Utils.escape_path(match) + return ::Rack::Utils.escape_path(match).b end end diff --git a/actionpack/lib/action_dispatch/request/session.rb b/actionpack/lib/action_dispatch/request/session.rb index 000847e193..bc5e0670e0 100644 --- a/actionpack/lib/action_dispatch/request/session.rb +++ b/actionpack/lib/action_dispatch/request/session.rb @@ -93,6 +93,14 @@ module ActionDispatch @delegate[key.to_s] end + # Returns the nested value specified by the sequence of keys, returning + # +nil+ if any intermediate step is +nil+. + def dig(*keys) + load_for_read! + keys = keys.map.with_index { |key, i| i.zero? ? key.to_s : key } + @delegate.dig(*keys) + end + # Returns true if the session has the given key or false. def has_key?(key) load_for_read! diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb index 776058d98e..5cde677051 100644 --- a/actionpack/lib/action_dispatch/routing.rb +++ b/actionpack/lib/action_dispatch/routing.rb @@ -243,9 +243,9 @@ module ActionDispatch # # rails routes # - # Target specific controllers by prefixing the command with <tt>-c</tt> option. Use - # <tt>--expanded</tt> to turn on the expanded table formatting mode. - # + # Target a specific controller with <tt>-c</tt>, or grep routes + # using <tt>-g</tt>. Useful in conjunction with <tt>--expanded</tt> + # which displays routes vertically. module Routing extend ActiveSupport::Autoload diff --git a/actionpack/lib/action_dispatch/routing/endpoint.rb b/actionpack/lib/action_dispatch/routing/endpoint.rb index 24dced1efd..28bb20d688 100644 --- a/actionpack/lib/action_dispatch/routing/endpoint.rb +++ b/actionpack/lib/action_dispatch/routing/endpoint.rb @@ -3,12 +3,15 @@ module ActionDispatch module Routing class Endpoint # :nodoc: - def dispatcher?; false; end - def redirect?; false; end - def engine?; rack_app.respond_to?(:routes); end - def matches?(req); true; end - def app; self; end - def rack_app; app; end + def dispatcher?; false; end + def redirect?; false; end + def matches?(req); true; end + def app; self; end + def rack_app; app; end + + def engine? + rack_app.is_a?(Class) && rack_app < Rails::Engine + end end end end diff --git a/actionpack/lib/action_dispatch/routing/inspector.rb b/actionpack/lib/action_dispatch/routing/inspector.rb index de200fada0..bae50f6a43 100644 --- a/actionpack/lib/action_dispatch/routing/inspector.rb +++ b/actionpack/lib/action_dispatch/routing/inspector.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require "delegate" +require "io/console/size" module ActionDispatch module Routing @@ -60,11 +61,11 @@ module ActionDispatch @routes = routes end - def format(formatter, filter = nil) + def format(formatter, filter = {}) routes_to_display = filter_routes(normalize_filter(filter)) routes = collect_routes(routes_to_display) if routes.none? - formatter.no_routes(collect_routes(@routes)) + formatter.no_routes(collect_routes(@routes), filter) return formatter.result end @@ -80,12 +81,12 @@ module ActionDispatch end private - def normalize_filter(filter) - if filter.is_a?(Hash) && filter[:controller] + if filter[:controller] { controller: /#{filter[:controller].downcase.sub(/_?controller\z/, '').sub('::', '/')}/ } - elsif filter - { controller: /#{filter}/, action: /#{filter}/, verb: /#{filter}/, name: /#{filter}/, path: /#{filter}/ } + elsif filter[:grep] + { controller: /#{filter[:grep]}/, action: /#{filter[:grep]}/, + verb: /#{filter[:grep]}/, name: /#{filter[:grep]}/, path: /#{filter[:grep]}/ } end end @@ -126,7 +127,7 @@ module ActionDispatch end module ConsoleFormatter - class Sheet + class Base def initialize @buffer = [] end @@ -136,30 +137,44 @@ module ActionDispatch end def section_title(title) - @buffer << "\n#{title}:" end def section(routes) - @buffer << draw_section(routes) end def header(routes) - @buffer << draw_header(routes) end - def no_routes(routes) + def no_routes(routes, filter) @buffer << - if routes.none? - <<~MESSAGE - You don't have any routes defined! + if routes.none? + <<~MESSAGE + You don't have any routes defined! + + Please add some routes in config/routes.rb. + MESSAGE + elsif filter.key?(:controller) + "No routes were found for this controller." + elsif filter.key?(:grep) + "No routes were found for this grep pattern." + end - Please add some routes in config/routes.rb. - MESSAGE - else - "No routes were found for this controller" - end @buffer << "For more information about routes, see the Rails guide: http://guides.rubyonrails.org/routing.html." end + end + + class Sheet < Base + def section_title(title) + @buffer << "\n#{title}:" + end + + def section(routes) + @buffer << draw_section(routes) + end + + def header(routes) + @buffer << draw_header(routes) + end private @@ -185,54 +200,36 @@ module ActionDispatch end end - class Expanded - def initialize - @buffer = [] - end - - def result - @buffer.join("") - end - + class Expanded < Base def section_title(title) - @buffer << "\n#{"[ #{title} ]"}\n" + @buffer << "\n#{"[ #{title} ]"}" end def section(routes) @buffer << draw_expanded_section(routes) end - def header(routes) - @buffer - end - - def no_routes(routes) - @buffer << - if routes.none? - <<~MESSAGE - You don't have any routes defined! - - Please add some routes in config/routes.rb.\n - MESSAGE - else - "No routes were found for this controller\n" - end - @buffer << "For more information about routes, see the Rails guide: http://guides.rubyonrails.org/routing.html." - end - private def draw_expanded_section(routes) routes.map.each_with_index do |r, i| - <<~MESSAGE - --[ Route #{i + 1} ]#{'-' * 60} - Prefix | #{r[:name]} - Verb | #{r[:verb]} - URI | #{r[:path]} - Controller#Action | #{r[:reqs]} + <<~MESSAGE.chomp + #{route_header(index: i + 1)} + Prefix | #{r[:name]} + Verb | #{r[:verb]} + URI | #{r[:path]} + Controller#Action | #{r[:reqs]} MESSAGE end end + + def route_header(index:) + console_width = IO.console_size.second + header_prefix = "--[ Route #{index} ]" + dash_remainder = [console_width - header_prefix.size, 0].max + + "#{header_prefix}#{'-' * dash_remainder}" + end end end @@ -264,7 +261,7 @@ module ActionDispatch <a href="http://guides.rubyonrails.org/routing.html">Rails Routing from the Outside In</a>. </li> </ul> - MESSAGE + MESSAGE end def result diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index f3970d5445..d9dd24935b 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -664,6 +664,7 @@ module ActionDispatch def define_generate_prefix(app, name) _route = @set.named_routes.get name _routes = @set + _url_helpers = @set.url_helpers script_namer = ->(options) do prefix_options = options.slice(*_route.segment_keys) @@ -675,7 +676,7 @@ module ActionDispatch # 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) + _url_helpers.send("#{name}_path", prefix_options) end app.routes.define_mounted_helper(name, script_namer) diff --git a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb index 6da869c0c2..e17ccaf986 100644 --- a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb +++ b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb @@ -120,8 +120,7 @@ module ActionDispatch opts end - # Returns the path component of a URL for the given record. It uses - # <tt>polymorphic_url</tt> with <tt>routing_type: :path</tt>. + # Returns the path component of a URL for the given record. def polymorphic_path(record_or_hash_or_array, options = {}) if Hash === record_or_hash_or_array options = record_or_hash_or_array.merge(options) diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb index fa345dccdf..1a31c7dbb8 100644 --- a/actionpack/lib/action_dispatch/routing/url_for.rb +++ b/actionpack/lib/action_dispatch/routing/url_for.rb @@ -191,7 +191,25 @@ module ActionDispatch end end - def route_for(name, *args) # :nodoc: + # Allows calling direct or regular named route. + # + # resources :buckets + # + # direct :recordable do |recording| + # route_for(:bucket, recording.bucket) + # end + # + # direct :threadable do |threadable| + # route_for(:recordable, threadable.parent) + # end + # + # This maintains the context of the original caller on + # whether to return a path or full URL, e.g: + # + # threadable_path(threadable) # => "/buckets/1" + # threadable_url(threadable) # => "http://example.com/buckets/1" + # + def route_for(name, *args) public_send(:"#{name}_url", *args) end diff --git a/actionpack/lib/action_dispatch/system_test_case.rb b/actionpack/lib/action_dispatch/system_test_case.rb index f85f816bb9..c74c0ccced 100644 --- a/actionpack/lib/action_dispatch/system_test_case.rb +++ b/actionpack/lib/action_dispatch/system_test_case.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -gem "capybara", "~> 2.15" +gem "capybara", ">= 2.15" require "capybara/dsl" require "capybara/minitest" diff --git a/actionpack/lib/action_dispatch/system_testing/browser.rb b/actionpack/lib/action_dispatch/system_testing/browser.rb index 10e6888ab3..1b0bce6b9e 100644 --- a/actionpack/lib/action_dispatch/system_testing/browser.rb +++ b/actionpack/lib/action_dispatch/system_testing/browser.rb @@ -33,7 +33,7 @@ module ActionDispatch def headless_chrome_browser_options options = Selenium::WebDriver::Chrome::Options.new options.args << "--headless" - options.args << "--disable-gpu" + options.args << "--disable-gpu" if Gem.win_platform? options 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 index ffa85f4e14..e47d5020f4 100644 --- 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 @@ -19,6 +19,7 @@ module ActionDispatch def after_teardown take_failed_screenshot Capybara.reset_sessions! + ensure super end end |