diff options
-rw-r--r-- | actionpack/CHANGELOG.md | 8 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/routing/mapper.rb | 1 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/routing/route_set.rb | 8 | ||||
-rw-r--r-- | activejob/lib/active_job/test_helper.rb | 24 | ||||
-rw-r--r-- | activejob/test/cases/test_helper_test.rb | 21 | ||||
-rw-r--r-- | activerecord/CHANGELOG.md | 4 | ||||
-rw-r--r-- | activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb | 7 | ||||
-rw-r--r-- | activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb | 24 | ||||
-rw-r--r-- | activerecord/test/cases/helper.rb | 4 | ||||
-rw-r--r-- | activesupport/lib/active_support/inflector/transliterate.rb | 7 | ||||
-rw-r--r-- | guides/source/asset_pipeline.md | 2 | ||||
-rw-r--r-- | guides/source/security.md | 7 | ||||
-rw-r--r-- | railties/lib/rails/generators/testing/assertions.rb | 2 | ||||
-rw-r--r-- | railties/lib/rails/test_unit/minitest_plugin.rb | 14 | ||||
-rw-r--r-- | railties/lib/rails/test_unit/reporter.rb | 2 | ||||
-rw-r--r-- | railties/test/application/test_runner_test.rb | 31 | ||||
-rw-r--r-- | railties/test/railties/engine_test.rb | 49 | ||||
-rw-r--r-- | railties/test/test_unit/reporter_test.rb | 4 |
18 files changed, 137 insertions, 82 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index a0a12f1b0e..a50b81b439 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,3 +1,11 @@ +* Fix regression in mounted engine named routes generation for app deployed to + a subdirectory. `relative_url_root` was prepended to the path twice (e.g. + "/subdir/subdir/engine_path" instead of "/subdir/engine_path") + + Fixes #20920. Fixes #21459. + + *Matthew Erhard* + * ActionDispatch::Response#new no longer applies default headers. If you want default headers applied to the response object, then call `ActionDispatch::Response.create`. This change only impacts people who are diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index cfd50f616d..2f1c2afb91 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -665,6 +665,7 @@ module ActionDispatch super(options) 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 _route.segment_keys.each { |k| options.delete(k) } _routes.url_helpers.send("#{name}_path", prefix_options) diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index e4b8d5993e..339e2b7c4a 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -656,14 +656,18 @@ module ActionDispatch RESERVED_OPTIONS = [:host, :protocol, :port, :subdomain, :domain, :tld_length, :trailing_slash, :anchor, :params, :only_path, :script_name, - :original_script_name] + :original_script_name, :relative_url_root] def optimize_routes_generation? default_url_options.empty? end def find_script_name(options) - options.delete(:script_name) || relative_url_root || '' + options.delete(:script_name) || find_relative_url_root(options) || '' + end + + def find_relative_url_root(options) + options.delete(:relative_url_root) || relative_url_root end def path_for(options, route_name = nil) diff --git a/activejob/lib/active_job/test_helper.rb b/activejob/lib/active_job/test_helper.rb index de79de59f8..44ddfa5f69 100644 --- a/activejob/lib/active_job/test_helper.rb +++ b/activejob/lib/active_job/test_helper.rb @@ -231,19 +231,17 @@ module ActiveJob # MyJob.set(wait_until: Date.tomorrow.noon).perform_later # end # end - def assert_enqueued_with(args = {}, &_block) - original_enqueued_jobs = enqueued_jobs.dup - clear_enqueued_jobs + def assert_enqueued_with(args = {}) + original_enqueued_jobs_count = enqueued_jobs.count args.assert_valid_keys(:job, :args, :at, :queue) serialized_args = serialize_args_for_assertion(args) yield - matching_job = enqueued_jobs.find do |job| + in_block_jobs = enqueued_jobs.drop(original_enqueued_jobs_count) + matching_job = in_block_jobs.find do |job| serialized_args.all? { |key, value| value == job[key] } end assert matching_job, "No enqueued job found with #{args}" instantiate_job(matching_job) - ensure - queue_adapter.enqueued_jobs = original_enqueued_jobs + enqueued_jobs end # Asserts that the job passed in the block has been performed with the given arguments. @@ -257,19 +255,17 @@ module ActiveJob # MyJob.set(wait_until: Date.tomorrow.noon).perform_later # end # end - def assert_performed_with(args = {}, &_block) - original_performed_jobs = performed_jobs.dup - clear_performed_jobs + def assert_performed_with(args = {}) + original_performed_jobs_count = performed_jobs.count args.assert_valid_keys(:job, :args, :at, :queue) serialized_args = serialize_args_for_assertion(args) perform_enqueued_jobs { yield } - matching_job = performed_jobs.find do |job| + in_block_jobs = performed_jobs.drop(original_performed_jobs_count) + matching_job = in_block_jobs.find do |job| serialized_args.all? { |key, value| value == job[key] } end assert matching_job, "No performed job found with #{args}" instantiate_job(matching_job) - ensure - queue_adapter.performed_jobs = original_performed_jobs + performed_jobs end def perform_enqueued_jobs(only: nil) @@ -308,9 +304,9 @@ module ActiveJob def enqueued_jobs_size(only: nil) # :nodoc: if only - enqueued_jobs.select { |job| Array(only).include?(job.fetch(:job)) }.size + enqueued_jobs.count { |job| Array(only).include?(job.fetch(:job)) } else - enqueued_jobs.size + enqueued_jobs.count end end diff --git a/activejob/test/cases/test_helper_test.rb b/activejob/test/cases/test_helper_test.rb index a66f5d762c..f7ee763e8a 100644 --- a/activejob/test/cases/test_helper_test.rb +++ b/activejob/test/cases/test_helper_test.rb @@ -242,6 +242,15 @@ class EnqueuedJobsTest < ActiveJob::TestCase assert_equal "No enqueued job found with {:job=>HelloJob, :args=>[#{wilma.inspect}]}", error.message end + + def test_assert_enqueued_job_does_not_change_jobs_count + HelloJob.perform_later + assert_enqueued_with(job: HelloJob) do + HelloJob.perform_later + end + + assert_equal 2, ActiveJob::Base.queue_adapter.enqueued_jobs.count + end end class PerformedJobsTest < ActiveJob::TestCase @@ -487,4 +496,16 @@ class PerformedJobsTest < ActiveJob::TestCase assert_equal "No performed job found with {:job=>HelloJob, :args=>[#{wilma.inspect}]}", error.message end + + def test_assert_performed_job_does_not_change_jobs_count + assert_performed_with(job: HelloJob) do + HelloJob.perform_later + end + + assert_performed_with(job: HelloJob) do + HelloJob.perform_later + end + + assert_equal 2, ActiveJob::Base.queue_adapter.performed_jobs.count + end end diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 6a40d32ef9..15c0674596 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,7 @@ +* Remove unused `pk_and_sequence_for` in AbstractMysqlAdapter. + + *Ryuta Kamizono* + * Allow fixtures files to set the model class in the YAML file itself. To load the fixtures file `accounts.yml` as the `User` model, use: diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index cd8097d1b3..24408d6bb6 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -850,13 +850,6 @@ module ActiveRecord nil end - # Returns a table's primary key and belonging sequence. - def pk_and_sequence_for(table) - if pk = primary_key(table) - [ pk, nil ] - end - end - def primary_keys(table_name) # :nodoc: raise ArgumentError unless table_name.present? diff --git a/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb b/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb index 29573d8e0d..d2ce48fc00 100644 --- a/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb +++ b/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb @@ -65,30 +65,6 @@ module ActiveRecord end end - def test_pk_and_sequence_for - with_example_table do - pk, seq = @conn.pk_and_sequence_for('ex') - assert_equal 'id', pk - assert_equal @conn.default_sequence_name('ex', 'id'), seq - end - end - - def test_pk_and_sequence_for_with_non_standard_primary_key - with_example_table '`code` INT auto_increment, PRIMARY KEY (`code`)' do - pk, seq = @conn.pk_and_sequence_for('ex') - assert_equal 'code', pk - assert_equal @conn.default_sequence_name('ex', 'code'), seq - end - end - - def test_pk_and_sequence_for_with_custom_index_type_pk - with_example_table '`id` INT auto_increment, PRIMARY KEY USING BTREE (`id`)' do - pk, seq = @conn.pk_and_sequence_for('ex') - assert_equal 'id', pk - assert_equal @conn.default_sequence_name('ex', 'id'), seq - end - end - def test_composite_primary_key with_example_table '`id` INT, `number` INT, foo INT, PRIMARY KEY (`id`, `number`)' do assert_nil @conn.primary_key('ex') diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb index 8773986882..89bd3f888e 100644 --- a/activerecord/test/cases/helper.rb +++ b/activerecord/test/cases/helper.rb @@ -47,9 +47,7 @@ def in_memory_db? end def subsecond_precision_supported? - !current_adapter?(:MysqlAdapter, :Mysql2Adapter) || - (ActiveRecord::Base.connection.send(:version) >= '5.6.0' && - ActiveRecord::Base.connection.send(:version) < '5.7.0') + !current_adapter?(:MysqlAdapter, :Mysql2Adapter) || ActiveRecord::Base.connection.send(:version) >= '5.6.4' end def mysql_enforcing_gtid_consistency? diff --git a/activesupport/lib/active_support/inflector/transliterate.rb b/activesupport/lib/active_support/inflector/transliterate.rb index 7472d4386a..103207fb63 100644 --- a/activesupport/lib/active_support/inflector/transliterate.rb +++ b/activesupport/lib/active_support/inflector/transliterate.rb @@ -69,10 +69,12 @@ module ActiveSupport # parameterize("Donald E. Knuth") # => "donald-e-knuth" # parameterize("^trés|Jolie-- ") # => "tres-jolie" def parameterize(string, sep = '-') - # replace accented chars with their ascii equivalents + # Replace accented chars with their ASCII equivalents. parameterized_string = transliterate(string) - # Turn unwanted chars into the separator + + # Turn unwanted chars into the separator. parameterized_string.gsub!(/[^a-z0-9\-_]+/i, sep) + unless sep.nil? || sep.empty? if sep == "-".freeze re_duplicate_separator = /-{2,}/ @@ -87,6 +89,7 @@ module ActiveSupport # Remove leading/trailing separator. parameterized_string.gsub!(re_leading_trailing_separator, ''.freeze) end + parameterized_string.downcase! parameterized_string end diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md index cc090e27e2..7b8d2d3aef 100644 --- a/guides/source/asset_pipeline.md +++ b/guides/source/asset_pipeline.md @@ -169,7 +169,7 @@ directory. Files in this directory are served by the Sprockets middleware. Assets can still be placed in the `public` hierarchy. Any assets under `public` will be served as static files by the application or web server when -`config.assets.serve_static_files` is set to true. You should use `app/assets` for +`config.serve_static_files` is set to true. You should use `app/assets` for files that must undergo some pre-processing before they are served. In production, Rails precompiles these files to `public/assets` by default. The diff --git a/guides/source/security.md b/guides/source/security.md index 0e4520843c..fb9ee7b412 100644 --- a/guides/source/security.md +++ b/guides/source/security.md @@ -196,7 +196,7 @@ This attack method works by including malicious code or a link in a page that ac ![](images/csrf.png) -In the [session chapter](#sessions) you have learned that most Rails applications use cookie-based sessions. Either they store the session id in the cookie and have a server-side session hash, or the entire session hash is on the client-side. In either case the browser will automatically send along the cookie on every request to a domain, if it can find a cookie for that domain. The controversial point is, that it will also send the cookie, if the request comes from a site of a different domain. Let's start with an example: +In the [session chapter](#sessions) you have learned that most Rails applications use cookie-based sessions. Either they store the session id in the cookie and have a server-side session hash, or the entire session hash is on the client-side. In either case the browser will automatically send along the cookie on every request to a domain, if it can find a cookie for that domain. The controversial point is that if the request comes from a site of a different domain, it will also send the cookie. Let's start with an example: * Bob browses a message board and views a post from a hacker where there is a crafted HTML image element. The element references a command in Bob's project management application, rather than an image file: `<img src="http://www.webapp.com/project/1/destroy">` * Bob's session at `www.webapp.com` is still alive, because he didn't log out a few minutes ago. @@ -224,9 +224,9 @@ The HTTP protocol basically provides two main types of requests - GET and POST ( * The interaction _changes the state_ of the resource in a way that the user would perceive (e.g., a subscription to a service), or * The user is _held accountable for the results_ of the interaction. -If your web application is RESTful, you might be used to additional HTTP verbs, such as PATCH, PUT or DELETE. Most of today's web browsers, however do not support them - only GET and POST. Rails uses a hidden `_method` field to handle this barrier. +If your web application is RESTful, you might be used to additional HTTP verbs, such as PATCH, PUT or DELETE. Most of today's web browsers, however, do not support them - only GET and POST. Rails uses a hidden `_method` field to handle this barrier. -_POST requests can be sent automatically, too_. Here is an example for a link which displays `www.harmless.com` as destination in the browser's status bar. In fact it dynamically creates a new form that sends a POST request. +_POST requests can be sent automatically, too_. In this example, the link www.harmless.com is shown as the destination in the browser's status bar. But it has actually dynamically created a new form that sends a POST request. ```html <a href="http://www.harmless.com/" onclick=" @@ -1057,4 +1057,3 @@ The security landscape shifts and it is important to keep up to date, because mi * Subscribe to the Rails security [mailing list](http://groups.google.com/group/rubyonrails-security) * [Keep up to date on the other application layers](http://secunia.com/) (they have a weekly newsletter, too) * A [good security blog](https://www.owasp.org) including the [Cross-Site scripting Cheat Sheet](https://www.owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet) - diff --git a/railties/lib/rails/generators/testing/assertions.rb b/railties/lib/rails/generators/testing/assertions.rb index 17af6eddfa..76758df86d 100644 --- a/railties/lib/rails/generators/testing/assertions.rb +++ b/railties/lib/rails/generators/testing/assertions.rb @@ -1,5 +1,3 @@ -require 'shellwords' - module Rails module Generators module Testing diff --git a/railties/lib/rails/test_unit/minitest_plugin.rb b/railties/lib/rails/test_unit/minitest_plugin.rb index 3a0a58df88..d1ba35a5ec 100644 --- a/railties/lib/rails/test_unit/minitest_plugin.rb +++ b/railties/lib/rails/test_unit/minitest_plugin.rb @@ -3,6 +3,16 @@ require "rails/test_unit/reporter" require "rails/test_unit/test_requirer" module Minitest + mattr_accessor(:hide_aggregated_results) { false } + + module AggregatedResultSuppresion + def aggregated_results + super unless Minitest.hide_aggregated_results + end + end + + SummaryReporter.prepend AggregatedResultSuppresion + def self.plugin_rails_options(opts, options) opts.separator "" opts.separator "Usage: bin/rails test [options] [files or directories]" @@ -38,6 +48,7 @@ module Minitest options[:fail_fast] = true end + options[:output_inline] = true options[:patterns] = opts.order! end @@ -63,6 +74,9 @@ module Minitest Minitest.backtrace_filter = ::Rails.backtrace_cleaner if ::Rails.respond_to?(:backtrace_cleaner) end + # Disable the extra failure output after a run, unless output is deferred. + self.hide_aggregated_results = options[:output_inline] + self.reporter << ::Rails::TestUnitReporter.new(options[:io], options) end diff --git a/railties/lib/rails/test_unit/reporter.rb b/railties/lib/rails/test_unit/reporter.rb index 8f1116b6af..e1fe92a11b 100644 --- a/railties/lib/rails/test_unit/reporter.rb +++ b/railties/lib/rails/test_unit/reporter.rb @@ -49,7 +49,7 @@ module Rails private def output_inline? - options.fetch(:output_inline, true) + options[:output_inline] end def fail_fast? diff --git a/railties/test/application/test_runner_test.rb b/railties/test/application/test_runner_test.rb index acfba21f1c..0aa6ce2252 100644 --- a/railties/test/application/test_runner_test.rb +++ b/railties/test/application/test_runner_test.rb @@ -341,30 +341,21 @@ module ApplicationTests end def test_output_inline_by_default - app_file 'test/models/post_test.rb', <<-RUBY - require 'test_helper' + create_test_file :models, 'post', pass: false - class PostTest < ActiveSupport::TestCase - def test_post - assert false, 'wups!' - end - end - RUBY + output = run_test_command('test/models/post_test.rb') + assert_match %r{Running:\n\nPostTest\nF\n\nwups!\n\nbin/rails test test/models/post_test.rb:4}, output + end + + def test_only_inline_failure_output + create_test_file :models, 'post', pass: false output = run_test_command('test/models/post_test.rb') - assert_match %r{Running:\n\nF\n\nwups!\n\nbin/rails test test/models/post_test.rb:4}, output + assert_match %r{Finished in.*\n\n1 runs, 1 assertions}, output end def test_fail_fast - app_file 'test/models/post_test.rb', <<-RUBY - require 'test_helper' - - class PostTest < ActiveSupport::TestCase - def test_post - assert false, 'wups!' - end - end - RUBY + create_test_file :models, 'post', pass: false assert_match(/Interrupt/, capture(:stderr) { run_test_command('test/models/post_test.rb --fail-fast') }) @@ -426,14 +417,14 @@ module ApplicationTests app_file 'db/schema.rb', '' end - def create_test_file(path = :unit, name = 'test') + def create_test_file(path = :unit, name = 'test', pass: true) app_file "test/#{path}/#{name}_test.rb", <<-RUBY require 'test_helper' class #{name.camelize}Test < ActiveSupport::TestCase def test_truth puts "#{name.camelize}Test" - assert true + assert #{pass}, 'wups!' end end RUBY diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index 79bd7a8241..2c82f728ee 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -1304,6 +1304,55 @@ YAML assert_equal '/foo/bukkits/bukkit', last_response.body end + test "paths are properly generated when application is mounted at sub-path and relative_url_root is set" do + add_to_config "config.relative_url_root = '/foo'" + + @plugin.write "lib/bukkits.rb", <<-RUBY + module Bukkits + class Engine < ::Rails::Engine + isolate_namespace Bukkits + end + end + RUBY + + app_file "app/controllers/bar_controller.rb", <<-RUBY + class BarController < ApplicationController + def index + render text: bukkits.bukkit_path + end + end + RUBY + + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + get '/bar' => 'bar#index', :as => 'bar' + mount Bukkits::Engine => "/bukkits", :as => "bukkits" + end + RUBY + + @plugin.write "config/routes.rb", <<-RUBY + Bukkits::Engine.routes.draw do + get '/bukkit' => 'bukkit#index' + end + RUBY + + @plugin.write "app/controllers/bukkits/bukkit_controller.rb", <<-RUBY + class Bukkits::BukkitController < ActionController::Base + def index + render text: main_app.bar_path + end + end + RUBY + + boot_rails + + get("/bukkits/bukkit", {}, {'SCRIPT_NAME' => '/foo'}) + assert_equal '/foo/bar', last_response.body + + get("/bar", {}, {'SCRIPT_NAME' => '/foo'}) + assert_equal '/foo/bukkits/bukkit', last_response.body + end + private def app Rails.application diff --git a/railties/test/test_unit/reporter_test.rb b/railties/test/test_unit/reporter_test.rb index 59fdf4bc36..fa6bb71c64 100644 --- a/railties/test/test_unit/reporter_test.rb +++ b/railties/test/test_unit/reporter_test.rb @@ -8,7 +8,7 @@ class TestUnitReporterTest < ActiveSupport::TestCase setup do @output = StringIO.new - @reporter = Rails::TestUnitReporter.new @output + @reporter = Rails::TestUnitReporter.new @output, output_inline: true end test "prints rerun snippet to run a single failed test" do @@ -72,7 +72,7 @@ class TestUnitReporterTest < ActiveSupport::TestCase end test "outputs skipped tests inline if verbose" do - verbose = Rails::TestUnitReporter.new @output, verbose: true + verbose = Rails::TestUnitReporter.new @output, verbose: true, output_inline: true verbose.record(skipped_test) verbose.report |