aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml11
-rw-r--r--Gemfile4
-rw-r--r--Gemfile.lock30
-rw-r--r--actioncable/CHANGELOG.md3
-rw-r--r--actionmailer/lib/action_mailer.rb1
-rw-r--r--actionmailer/lib/action_mailer/preview.rb10
-rw-r--r--actionmailer/test/base_test.rb16
-rw-r--r--actionmailer/test/log_subscriber_test.rb2
-rw-r--r--actionpack/CHANGELOG.md1
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb4
-rw-r--r--actionpack/lib/action_dispatch/http/mime_type.rb8
-rw-r--r--actionpack/lib/action_dispatch/http/parameters.rb8
-rw-r--r--actionpack/lib/action_dispatch/http/upload.rb8
-rw-r--r--actionpack/lib/action_dispatch/journey/router/utils.rb10
-rw-r--r--actionpack/lib/action_dispatch/routing/routes_proxy.rb5
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb11
-rw-r--r--actionpack/test/controller/parameters/mutators_test.rb21
-rw-r--r--actionpack/test/dispatch/request_test.rb4
-rw-r--r--actionpack/test/dispatch/routing_test.rb12
-rw-r--r--actionpack/test/dispatch/uploaded_file_test.rb6
-rw-r--r--actionpack/test/journey/router/utils_test.rb5
-rw-r--r--actionview/CHANGELOG.md6
-rw-r--r--actionview/lib/action_view/helpers/date_helper.rb44
-rw-r--r--actionview/lib/action_view/helpers/tags/base.rb2
-rw-r--r--actionview/lib/action_view/helpers/url_helper.rb2
-rw-r--r--actionview/test/activerecord/controller_runtime_test.rb2
-rw-r--r--actionview/test/fixtures/comments/empty.html+grid.erb1
-rw-r--r--actionview/test/fixtures/test/_partial_with_variants.html+grid.erb1
-rw-r--r--actionview/test/template/asset_tag_helper_test.rb6
-rw-r--r--actionview/test/template/atom_feed_helper_test.rb8
-rw-r--r--actionview/test/template/date_helper_test.rb10
-rw-r--r--actionview/test/template/form_helper/form_with_test.rb2
-rw-r--r--actionview/test/template/render_test.rb12
-rw-r--r--actionview/test/template/url_helper_test.rb25
-rw-r--r--activejob/CHANGELOG.md1
-rw-r--r--activemodel/CHANGELOG.md42
-rw-r--r--activemodel/lib/active_model/validations/validates.rb5
-rw-r--r--activemodel/lib/active_model/validator.rb6
-rw-r--r--activemodel/test/cases/validations/format_validation_test.rb6
-rw-r--r--activerecord/CHANGELOG.md16
-rw-r--r--activerecord/lib/active_record/associations.rb11
-rw-r--r--activerecord/lib/active_record/associations/belongs_to_association.rb2
-rw-r--r--activerecord/lib/active_record/associations/collection_proxy.rb28
-rw-r--r--activerecord/lib/active_record/associations/preloader/through_association.rb14
-rw-r--r--activerecord/lib/active_record/autosave_association.rb2
-rw-r--r--activerecord/lib/active_record/collection_cache_key.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb14
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb5
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/quoting.rb9
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb16
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/referential_integrity.rb47
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb14
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb6
-rw-r--r--activerecord/lib/active_record/dynamic_matchers.rb17
-rw-r--r--activerecord/lib/active_record/migration/command_recorder.rb12
-rw-r--r--activerecord/lib/active_record/railties/databases.rake4
-rw-r--r--activerecord/lib/active_record/reflection.rb4
-rw-r--r--activerecord/lib/active_record/relation.rb3
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb3
-rw-r--r--activerecord/lib/active_record/relation/delegation.rb10
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb6
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb2
-rw-r--r--activerecord/lib/active_record/schema_dumper.rb4
-rw-r--r--activerecord/lib/active_record/tasks/database_tasks.rb14
-rw-r--r--activerecord/lib/active_record/tasks/mysql_database_tasks.rb6
-rw-r--r--activerecord/lib/active_record/tasks/postgresql_database_tasks.rb6
-rw-r--r--activerecord/lib/active_record/tasks/sqlite_database_tasks.rb26
-rw-r--r--activerecord/test/cases/adapter_test.rb2
-rw-r--r--activerecord/test/cases/adapters/mysql2/charset_collation_test.rb4
-rw-r--r--activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb8
-rw-r--r--activerecord/test/cases/adapters/postgresql/collation_test.rb4
-rw-r--r--activerecord/test/cases/adapters/postgresql/connection_test.rb4
-rw-r--r--activerecord/test/cases/adapters/postgresql/explain_test.rb4
-rw-r--r--activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb10
-rw-r--r--activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb175
-rw-r--r--activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb6
-rw-r--r--activerecord/test/cases/adapters/postgresql/schema_test.rb10
-rw-r--r--activerecord/test/cases/adapters/sqlite3/collation_test.rb4
-rw-r--r--activerecord/test/cases/adapters/sqlite3/explain_test.rb4
-rw-r--r--activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb10
-rw-r--r--activerecord/test/cases/associations/belongs_to_associations_test.rb18
-rw-r--r--activerecord/test/cases/associations/eager_test.rb1
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb6
-rw-r--r--activerecord/test/cases/associations/left_outer_join_association_test.rb2
-rw-r--r--activerecord/test/cases/batches_test.rb28
-rw-r--r--activerecord/test/cases/bind_parameter_test.rb14
-rw-r--r--activerecord/test/cases/collection_cache_key_test.rb24
-rw-r--r--activerecord/test/cases/defaults_test.rb9
-rw-r--r--activerecord/test/cases/enum_test.rb5
-rw-r--r--activerecord/test/cases/explain_test.rb6
-rw-r--r--activerecord/test/cases/inheritance_test.rb2
-rw-r--r--activerecord/test/cases/log_subscriber_test.rb56
-rw-r--r--activerecord/test/cases/migrator_test.rb2
-rw-r--r--activerecord/test/cases/persistence_test.rb2
-rw-r--r--activerecord/test/cases/quoting_test.rb15
-rw-r--r--activerecord/test/cases/relation/delegation_test.rb34
-rw-r--r--activerecord/test/cases/relation/merging_test.rb2
-rw-r--r--activerecord/test/cases/relation/where_chain_test.rb2
-rw-r--r--activerecord/test/cases/relation/where_clause_test.rb26
-rw-r--r--activerecord/test/cases/relations_test.rb35
-rw-r--r--activerecord/test/cases/result_test.rb6
-rw-r--r--activerecord/test/cases/tasks/database_tasks_test.rb20
-rw-r--r--activerecord/test/cases/tasks/mysql_rake_test.rb16
-rw-r--r--activerecord/test/cases/tasks/postgresql_rake_test.rb8
-rw-r--r--activerecord/test/cases/tasks/sqlite_rake_test.rb20
-rw-r--r--activerecord/test/cases/test_case.rb8
-rw-r--r--activerecord/test/models/author.rb1
-rw-r--r--activerecord/test/models/book.rb2
-rw-r--r--activerecord/test/models/comment.rb5
-rw-r--r--activerecord/test/models/company.rb8
-rw-r--r--activesupport/CHANGELOG.md1
-rw-r--r--activesupport/lib/active_support/cache/strategy/local_cache.rb7
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/compatibility.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/module/delegation.rb39
-rw-r--r--activesupport/lib/active_support/duration.rb10
-rw-r--r--activesupport/lib/active_support/i18n_railtie.rb4
-rw-r--r--activesupport/lib/active_support/message_encryptor.rb2
-rw-r--r--activesupport/lib/active_support/rescuable.rb10
-rw-r--r--activesupport/test/caching_test.rb8
-rw-r--r--activesupport/test/core_ext/enumerable_test.rb6
-rw-r--r--activesupport/test/core_ext/module_test.rb12
-rw-r--r--activesupport/test/message_encryptor_test.rb26
-rw-r--r--activesupport/test/rescuable_test.rb34
-rw-r--r--activesupport/test/testing/file_fixtures_test.rb4
-rw-r--r--activesupport/test/time_travel_test.rb2
-rw-r--r--guides/bug_report_templates/action_controller_gem.rb2
-rw-r--r--guides/bug_report_templates/active_job_gem.rb2
-rw-r--r--guides/bug_report_templates/active_record_gem.rb2
-rw-r--r--guides/bug_report_templates/active_record_migrations_gem.rb2
-rw-r--r--guides/bug_report_templates/generic_gem.rb2
-rw-r--r--guides/rails_guides/generator.rb2
-rw-r--r--guides/rails_guides/helpers.rb2
-rw-r--r--guides/rails_guides/markdown/renderer.rb2
-rw-r--r--guides/source/5_1_release_notes.md255
-rw-r--r--guides/source/autoloading_and_reloading_constants.md17
-rw-r--r--guides/source/contributing_to_ruby_on_rails.md7
-rw-r--r--guides/source/documents.yaml1
-rw-r--r--guides/source/testing.md20
-rw-r--r--guides/source/upgrading_ruby_on_rails.md6
-rw-r--r--guides/source/working_with_javascript_in_rails.md182
-rw-r--r--railties/CHANGELOG.md15
-rw-r--r--railties/lib/rails/application/configuration.rb9
-rw-r--r--railties/lib/rails/commands/console/console_command.rb16
-rw-r--r--railties/lib/rails/commands/help/USAGE17
-rw-r--r--railties/lib/rails/commands/server/server_command.rb5
-rw-r--r--railties/lib/rails/generators/rails/app/app_generator.rb13
-rw-r--r--railties/lib/rails/generators/rails/app/templates/Gemfile2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/bin/yarn5
-rw-r--r--railties/lib/rails/mailers_controller.rb8
-rw-r--r--railties/lib/rails/railtie.rb8
-rw-r--r--railties/lib/rails/templates/rails/mailers/email.html.erb6
-rw-r--r--railties/lib/rails/test_help.rb7
-rw-r--r--railties/lib/rails/test_unit/minitest_plugin.rb2
-rw-r--r--railties/lib/rails/test_unit/railtie.rb2
-rw-r--r--railties/lib/rails/test_unit/testing.rake1
-rw-r--r--railties/test/application/configuration_test.rb34
-rw-r--r--railties/test/application/console_test.rb16
-rw-r--r--railties/test/application/mailer_previews_test.rb51
-rw-r--r--railties/test/application/middleware/exceptions_test.rb14
-rw-r--r--railties/test/application/rake/migrations_test.rb6
-rw-r--r--railties/test/commands/server_test.rb12
-rw-r--r--railties/test/generators/app_generator_test.rb14
-rw-r--r--railties/test/generators/channel_generator_test.rb4
-rw-r--r--railties/test/generators/create_migration_test.rb20
-rw-r--r--railties/test/generators/mailer_generator_test.rb12
-rw-r--r--railties/test/generators/migration_generator_test.rb8
-rw-r--r--railties/test/generators/model_generator_test.rb12
-rw-r--r--railties/test/generators/plugin_generator_test.rb46
-rw-r--r--railties/test/generators/shared_generator_tests.rb4
-rw-r--r--railties/test/generators/test_runner_in_engine_test.rb2
-rw-r--r--railties/test/isolation/abstract_unit.rb6
-rw-r--r--railties/test/railties/engine_test.rb18
-rw-r--r--railties/test/test_unit/reporter_test.rb10
174 files changed, 1495 insertions, 874 deletions
diff --git a/.travis.yml b/.travis.yml
index 5b8cfa9dbf..9d63fd4b13 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -15,14 +15,11 @@ services:
addons:
postgresql: "9.4"
- apt:
- packages:
- - postgresql-9.4
bundler_args: --without test --jobs 3 --retry 3
before_install:
- "rm ${BUNDLE_GEMFILE}.lock"
- - "gem update --system"
+ - "gem update --system 2.6.11"
- "gem update bundler"
- "[ -f /tmp/beanstalkd-1.10/Makefile ] || (curl -L https://github.com/kr/beanstalkd/archive/v1.10.tar.gz | tar xz -C /tmp)"
- "pushd /tmp/beanstalkd-1.10 && make && (./beanstalkd &); popd"
@@ -101,17 +98,17 @@ matrix:
- "GEM=ar:postgresql POSTGRES=9.2"
addons:
postgresql: "9.2"
- - rvm: jruby-9.1.8.0
+ - rvm: jruby-9.1.9.0
jdk: oraclejdk8
env:
- "GEM=ap"
- - rvm: jruby-9.1.8.0
+ - rvm: jruby-9.1.9.0
jdk: oraclejdk8
env:
- "GEM=am,amo,aj"
allow_failures:
- rvm: ruby-head
- - rvm: jruby-9.1.8.0
+ - rvm: jruby-9.1.9.0
- env: "GEM=ac:integration"
fast_finish: true
diff --git a/Gemfile b/Gemfile
index 5077c257d9..df25abe65b 100644
--- a/Gemfile
+++ b/Gemfile
@@ -16,7 +16,7 @@ gem "rake", ">= 11.1"
# be loaded after loading the test library.
gem "mocha", "~> 0.14", require: false
-gem "capybara", "~> 2.13.0"
+gem "capybara", "~> 2.13"
gem "rack-cache", "~> 1.2"
gem "jquery-rails"
@@ -42,7 +42,7 @@ gem "json", ">= 2.0.0"
gem "rubocop", ">= 0.47", require: false
group :doc do
- gem "sdoc", "1.0.0.rc1"
+ gem "sdoc", "> 1.0.0.rc1", "< 2.0"
gem "redcarpet", "~> 3.2.3", platforms: :ruby
gem "w3c_validators"
gem "kindlerb", "~> 1.2.0"
diff --git a/Gemfile.lock b/Gemfile.lock
index da7e5a8cab..26a7fa8b0e 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -25,7 +25,7 @@ GIT
GIT
remote: https://github.com/rails/arel.git
- revision: 437aa3a4bb8ad4f3f4eba299dbb1112852f9c7ac
+ revision: 5db56a513286814991c27000af2c0243cc19d1e2
specs:
arel (8.0.0)
@@ -91,7 +91,7 @@ PATH
GEM
remote: https://rubygems.org/
specs:
- addressable (2.5.0)
+ addressable (2.5.1)
public_suffix (~> 2.0, >= 2.0.2)
amq-protocol (2.1.0)
ast (2.3.0)
@@ -125,7 +125,7 @@ GEM
bunny (2.6.2)
amq-protocol (>= 2.0.1)
byebug (9.0.6)
- capybara (2.13.0)
+ capybara (2.14.0)
addressable
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
@@ -222,15 +222,15 @@ GEM
multi_json (1.12.1)
multipart-post (2.0.0)
mustache (1.0.3)
- mysql2 (0.4.5)
- mysql2 (0.4.5-x64-mingw32)
- mysql2 (0.4.5-x86-mingw32)
+ mysql2 (0.4.6)
+ mysql2 (0.4.6-x64-mingw32)
+ mysql2 (0.4.6-x86-mingw32)
nio4r (2.0.0)
- nokogiri (1.7.0.1)
+ nokogiri (1.7.1)
mini_portile2 (~> 2.1.0)
- nokogiri (1.7.0.1-x64-mingw32)
+ nokogiri (1.7.1-x64-mingw32)
mini_portile2 (~> 2.1.0)
- nokogiri (1.7.0.1-x86-mingw32)
+ nokogiri (1.7.1-x86-mingw32)
mini_portile2 (~> 2.1.0)
parser (2.4.0.0)
ast (~> 2.2)
@@ -249,7 +249,7 @@ GEM
simple_uuid
que (0.12.0)
racc (1.4.14)
- rack (2.0.1)
+ rack (2.0.3)
rack-cache (1.6.1)
rack (>= 0.4)
rack-protection (1.5.3)
@@ -264,7 +264,7 @@ GEM
rainbow (2.2.1)
rake (12.0.0)
rb-fsevent (0.9.8)
- rdoc (5.0.0)
+ rdoc (5.1.0)
redcarpet (3.2.3)
redis (3.3.2)
redis-namespace (1.5.2)
@@ -298,8 +298,8 @@ GEM
sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3)
- sdoc (1.0.0.rc1)
- rdoc (= 5.0.0)
+ sdoc (1.0.0.rc2)
+ rdoc (~> 5.0)
selenium-webdriver (3.0.5)
childprocess (~> 0.5)
rubyzip (~> 1.0)
@@ -383,7 +383,7 @@ DEPENDENCIES
blade
blade-sauce_labs_plugin
byebug
- capybara (~> 2.13.0)
+ capybara (~> 2.13)
coffee-rails
dalli (>= 2.2.1)
delayed_job
@@ -417,7 +417,7 @@ DEPENDENCIES
resque-scheduler
rubocop (>= 0.47)
sass-rails
- sdoc (= 1.0.0.rc1)
+ sdoc (> 1.0.0.rc1, < 2.0)
sequel
sidekiq
sneakers
diff --git a/actioncable/CHANGELOG.md b/actioncable/CHANGELOG.md
index f0502c06ff..2bf11da463 100644
--- a/actioncable/CHANGELOG.md
+++ b/actioncable/CHANGELOG.md
@@ -3,5 +3,6 @@
Previously any socket errors were ignored and this made it hard to diagnose socket issues (e.g. as discussed in #28362).
*Edward Poot*
-
+
+
Please check [5-1-stable](https://github.com/rails/rails/blob/5-1-stable/actioncable/CHANGELOG.md) for previous changes.
diff --git a/actionmailer/lib/action_mailer.rb b/actionmailer/lib/action_mailer.rb
index 211190560a..8e59f033d0 100644
--- a/actionmailer/lib/action_mailer.rb
+++ b/actionmailer/lib/action_mailer.rb
@@ -25,6 +25,7 @@ require "abstract_controller"
require "action_mailer/version"
# Common Active Support usage in Action Mailer
+require "active_support"
require "active_support/rails"
require "active_support/core_ext/class"
require "active_support/core_ext/module/attr_internal"
diff --git a/actionmailer/lib/action_mailer/preview.rb b/actionmailer/lib/action_mailer/preview.rb
index b0152aff03..87ba743f3d 100644
--- a/actionmailer/lib/action_mailer/preview.rb
+++ b/actionmailer/lib/action_mailer/preview.rb
@@ -52,6 +52,12 @@ module ActionMailer
class Preview
extend ActiveSupport::DescendantsTracker
+ attr_reader :params
+
+ def initialize(params = {})
+ @params = params
+ end
+
class << self
# Returns all mailer preview classes.
def all
@@ -62,8 +68,8 @@ module ActionMailer
# Returns the mail object for the given email name. The registered preview
# interceptors will be informed so that they can transform the message
# as they would if the mail was actually being delivered.
- def call(email)
- preview = new
+ def call(email, params = {})
+ preview = new(params)
message = preview.public_send(email)
inform_preview_interceptors(message)
message
diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb
index 61960d411d..ebb97078e6 100644
--- a/actionmailer/test/base_test.rb
+++ b/actionmailer/test/base_test.rb
@@ -968,3 +968,19 @@ class BasePreviewInterceptorsTest < ActiveSupport::TestCase
end
end
end
+
+class BasePreviewTest < ActiveSupport::TestCase
+ class BaseMailerPreview < ActionMailer::Preview
+ def welcome
+ BaseMailer.welcome(params)
+ end
+ end
+
+ test "has access to params" do
+ params = { name: "World" }
+
+ assert_called_with(BaseMailer, :welcome, [params]) do
+ BaseMailerPreview.call(:welcome, params)
+ end
+ end
+end
diff --git a/actionmailer/test/log_subscriber_test.rb b/actionmailer/test/log_subscriber_test.rb
index d864c3acca..7969782e07 100644
--- a/actionmailer/test/log_subscriber_test.rb
+++ b/actionmailer/test/log_subscriber_test.rb
@@ -26,7 +26,7 @@ class AMLogSubscriberTest < ActionMailer::TestCase
wait
assert_equal(1, @logger.logged(:info).size)
- assert_match(/Sent mail to system@test.lindsaar.net/, @logger.logged(:info).first)
+ assert_match(/Sent mail to system@test\.lindsaar\.net/, @logger.logged(:info).first)
assert_equal(2, @logger.logged(:debug).size)
assert_match(/BaseMailer#welcome: processed outbound mail in [\d.]+ms/, @logger.logged(:debug).first)
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 51cec82801..cc908dcc43 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -10,4 +10,5 @@
*Julian Nadeau*
+
Please check [5-1-stable](https://github.com/rails/rails/blob/5-1-stable/actionpack/CHANGELOG.md) for previous changes.
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index 7864f9decd..20330b5091 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -666,8 +666,8 @@ module ActionController
# to key. If the key is not found, returns the default value. If the
# optional code block is given and the key is not found, pass in the key
# and return the result of block.
- def delete(key)
- convert_value_to_parameters(@parameters.delete(key))
+ def delete(key, &block)
+ convert_value_to_parameters(@parameters.delete(key, &block))
end
# Returns a new instance of <tt>ActionController::Parameters</tt> with only
diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb
index 0cf010f59e..74a3afab44 100644
--- a/actionpack/lib/action_dispatch/http/mime_type.rb
+++ b/actionpack/lib/action_dispatch/http/mime_type.rb
@@ -326,11 +326,11 @@ module Mime
def ref; end
- def respond_to_missing?(method, include_private = false)
- method.to_s.ends_with? "?"
- end
-
private
+ def respond_to_missing?(method, _)
+ method.to_s.ends_with? "?"
+ end
+
def method_missing(method, *args)
false if method.to_s.ends_with? "?"
end
diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb
index 79a2ef965b..7c585dbe68 100644
--- a/actionpack/lib/action_dispatch/http/parameters.rb
+++ b/actionpack/lib/action_dispatch/http/parameters.rb
@@ -85,7 +85,7 @@ module ActionDispatch
def set_binary_encoding(params)
action = params[:action]
- if controller_class.binary_params_for?(action)
+ if binary_params_for?(action)
ActionDispatch::Request::Utils.each_param_value(params) do |param|
param.force_encoding ::Encoding::ASCII_8BIT
end
@@ -93,6 +93,12 @@ module ActionDispatch
params
end
+ def binary_params_for?(action)
+ controller_class.binary_params_for?(action)
+ rescue NameError
+ false
+ end
+
def parse_formatted_parameters(parsers)
return yield if content_length.zero? || content_mime_type.nil?
diff --git a/actionpack/lib/action_dispatch/http/upload.rb b/actionpack/lib/action_dispatch/http/upload.rb
index 61ba052e45..225272d66e 100644
--- a/actionpack/lib/action_dispatch/http/upload.rb
+++ b/actionpack/lib/action_dispatch/http/upload.rb
@@ -27,14 +27,18 @@ module ActionDispatch
@tempfile = hash[:tempfile]
raise(ArgumentError, ":tempfile is required") unless @tempfile
- @original_filename = hash[:filename]
- if @original_filename
+ if hash[:filename]
+ @original_filename = hash[:filename].dup
+
begin
@original_filename.encode!(Encoding::UTF_8)
rescue EncodingError
@original_filename.force_encoding(Encoding::UTF_8)
end
+ else
+ @original_filename = nil
end
+
@content_type = hash[:type]
@headers = hash[:head]
end
diff --git a/actionpack/lib/action_dispatch/journey/router/utils.rb b/actionpack/lib/action_dispatch/journey/router/utils.rb
index ffcd875b4d..6d400f3364 100644
--- a/actionpack/lib/action_dispatch/journey/router/utils.rb
+++ b/actionpack/lib/action_dispatch/journey/router/utils.rb
@@ -13,11 +13,13 @@ module ActionDispatch
# normalize_path("") # => "/"
# normalize_path("/%ab") # => "/%AB"
def self.normalize_path(path)
+ encoding = path.encoding
path = "/#{path}"
path.squeeze!("/".freeze)
path.sub!(%r{/+\Z}, "".freeze)
path.gsub!(/(%[a-f0-9]{2})/) { $1.upcase }
path = "/" if path == "".freeze
+ path.force_encoding(encoding)
path
end
@@ -59,11 +61,11 @@ module ActionDispatch
end
private
- def escape(component, pattern) # :doc:
+ def escape(component, pattern)
component.gsub(pattern) { |unsafe| percent_encode(unsafe) }.force_encoding(US_ASCII)
end
- def percent_encode(unsafe) # :doc:
+ def percent_encode(unsafe)
safe = EMPTY.dup
unsafe.each_byte { |b| safe << DEC2HEX[b] }
safe
@@ -84,6 +86,10 @@ module ActionDispatch
ENCODER.escape_fragment(fragment.to_s)
end
+ # Replaces any escaped sequences with their unescaped representations.
+ #
+ # uri = "/topics?title=Ruby%20on%20Rails"
+ # unescape_uri(uri) #=> "/topics?title=Ruby on Rails"
def self.unescape_uri(uri)
ENCODER.unescape_uri(uri)
end
diff --git a/actionpack/lib/action_dispatch/routing/routes_proxy.rb b/actionpack/lib/action_dispatch/routing/routes_proxy.rb
index ee847eaeed..c1423f770f 100644
--- a/actionpack/lib/action_dispatch/routing/routes_proxy.rb
+++ b/actionpack/lib/action_dispatch/routing/routes_proxy.rb
@@ -19,7 +19,8 @@ module ActionDispatch
end
end
- def respond_to_missing?(method, include_private = false)
+ private
+ def respond_to_missing?(method, _)
super || @helpers.respond_to?(method)
end
@@ -32,7 +33,7 @@ module ActionDispatch
@helpers.#{method}(*args)
end
RUBY
- send(method, *args)
+ public_send(method, *args)
else
super
end
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index 2e2db98ad6..2416c58817 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -385,14 +385,15 @@ module ActionDispatch
integration_session.default_url_options = options
end
- def respond_to_missing?(method, include_private = false)
- integration_session.respond_to?(method, include_private) || super
+ private
+ def respond_to_missing?(method, _)
+ integration_session.respond_to?(method) || super
end
# Delegate unhandled messages to the current session instance.
- def method_missing(sym, *args, &block)
- if integration_session.respond_to?(sym)
- integration_session.__send__(sym, *args, &block).tap do
+ def method_missing(method, *args, &block)
+ if integration_session.respond_to?(method)
+ integration_session.public_send(method, *args, &block).tap do
copy_session_variables!
end
else
diff --git a/actionpack/test/controller/parameters/mutators_test.rb b/actionpack/test/controller/parameters/mutators_test.rb
index e61bbdbe13..2c36f488c6 100644
--- a/actionpack/test/controller/parameters/mutators_test.rb
+++ b/actionpack/test/controller/parameters/mutators_test.rb
@@ -25,6 +25,27 @@ class ParametersMutatorsTest < ActiveSupport::TestCase
assert_not @params.delete(:person).permitted?
end
+ test "delete returns the value when the key is present" do
+ assert_equal "32", @params[:person].delete(:age)
+ end
+
+ test "delete removes the entry when the key present" do
+ @params[:person].delete(:age)
+ assert_not @params[:person].key?(:age)
+ end
+
+ test "delete returns nil when the key is not present" do
+ assert_equal nil, @params[:person].delete(:first_name)
+ end
+
+ test "delete returns the value of the given block when the key is not present" do
+ assert_equal "David", @params[:person].delete(:first_name) { "David" }
+ end
+
+ test "delete yields the key to the given block when the key is not present" do
+ assert_equal "first_name: David", @params[:person].delete(:first_name) { |k| "#{k}: David" }
+ end
+
test "delete_if retains permitted status" do
@params.permit!
assert @params.delete_if { |k| k == "person" }.permitted?
diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb
index 7e194c5d8b..899b27b962 100644
--- a/actionpack/test/dispatch/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -110,8 +110,8 @@ class RequestIP < BaseRequestTest
request.remote_ip
}
assert_match(/IP spoofing attack/, e.message)
- assert_match(/HTTP_X_FORWARDED_FOR="1.1.1.1"/, e.message)
- assert_match(/HTTP_CLIENT_IP="2.2.2.2"/, e.message)
+ assert_match(/HTTP_X_FORWARDED_FOR="1\.1\.1\.1"/, e.message)
+ assert_match(/HTTP_CLIENT_IP="2\.2\.2\.2"/, e.message)
end
test "remote ip with spoof detection disabled" do
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index d64917e0d3..32cd78e492 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -4419,7 +4419,7 @@ class TestInvalidUrls < ActionDispatch::IntegrationTest
end
end
- test "invalid UTF-8 encoding returns a 400 Bad Request" do
+ test "invalid UTF-8 encoding is treated as ASCII 8BIT encode" do
with_routing do |set|
set.draw do
get "/bar/:id", to: redirect("/foo/show/%{id}")
@@ -4435,19 +4435,19 @@ class TestInvalidUrls < ActionDispatch::IntegrationTest
end
get "/%E2%EF%BF%BD%A6"
- assert_response :bad_request
+ assert_response :not_found
get "/foo/%E2%EF%BF%BD%A6"
- assert_response :bad_request
+ assert_response :not_found
get "/foo/show/%E2%EF%BF%BD%A6"
- assert_response :bad_request
+ assert_response :ok
get "/bar/%E2%EF%BF%BD%A6"
- assert_response :bad_request
+ assert_response :redirect
get "/foobar/%E2%EF%BF%BD%A6"
- assert_response :bad_request
+ assert_response :ok
end
end
end
diff --git a/actionpack/test/dispatch/uploaded_file_test.rb b/actionpack/test/dispatch/uploaded_file_test.rb
index 51680216e4..0074d2a314 100644
--- a/actionpack/test/dispatch/uploaded_file_test.rb
+++ b/actionpack/test/dispatch/uploaded_file_test.rb
@@ -13,6 +13,12 @@ module ActionDispatch
assert_equal "foo", uf.original_filename
end
+ def test_filename_is_different_object
+ file_str = "foo"
+ uf = Http::UploadedFile.new(filename: file_str, tempfile: Object.new)
+ assert_not_equal file_str.object_id , uf.original_filename.object_id
+ end
+
def test_filename_should_be_in_utf_8
uf = Http::UploadedFile.new(filename: "foo", tempfile: Object.new)
assert_equal "UTF-8", uf.original_filename.encoding.to_s
diff --git a/actionpack/test/journey/router/utils_test.rb b/actionpack/test/journey/router/utils_test.rb
index b77bf6628a..74277a4325 100644
--- a/actionpack/test/journey/router/utils_test.rb
+++ b/actionpack/test/journey/router/utils_test.rb
@@ -31,6 +31,11 @@ module ActionDispatch
def test_normalize_path_uppercase
assert_equal "/foo%AAbar%AAbaz", Utils.normalize_path("/foo%aabar%aabaz")
end
+
+ def test_normalize_path_maintains_string_encoding
+ path = "/foo%AAbar%AAbaz".b
+ assert_equal Encoding::ASCII_8BIT, Utils.normalize_path(path).encoding
+ end
end
end
end
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index c514e757c8..d478f4c437 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -1 +1,7 @@
+* Update `distance_of_time_in_words` helper to display better error messages
+ for bad input.
+
+ *Jay Hayes*
+
+
Please check [5-1-stable](https://github.com/rails/rails/blob/5-1-stable/actionview/CHANGELOG.md) for previous changes.
diff --git a/actionview/lib/action_view/helpers/date_helper.rb b/actionview/lib/action_view/helpers/date_helper.rb
index 09dc6ef6bd..3f43465aa4 100644
--- a/actionview/lib/action_view/helpers/date_helper.rb
+++ b/actionview/lib/action_view/helpers/date_helper.rb
@@ -95,8 +95,8 @@ module ActionView
scope: :'datetime.distance_in_words'
}.merge!(options)
- from_time = from_time.to_time if from_time.respond_to?(:to_time)
- to_time = to_time.to_time if to_time.respond_to?(:to_time)
+ from_time = normalize_distance_of_time_argument_to_time(from_time)
+ to_time = normalize_distance_of_time_argument_to_time(to_time)
from_time, to_time = to_time, from_time if from_time > to_time
distance_in_minutes = ((to_time - from_time) / 60.0).round
distance_in_seconds = (to_time - from_time).round
@@ -130,22 +130,18 @@ module ActionView
# 60 days up to 365 days
when 86400...525600 then locale.t :x_months, count: (distance_in_minutes.to_f / 43200.0).round
else
- if from_time.acts_like?(:time) && to_time.acts_like?(:time)
- fyear = from_time.year
- fyear += 1 if from_time.month >= 3
- tyear = to_time.year
- tyear -= 1 if to_time.month < 3
- leap_years = (fyear > tyear) ? 0 : (fyear..tyear).count { |x| Date.leap?(x) }
- minute_offset_for_leap_year = leap_years * 1440
- # Discount the leap year days when calculating year distance.
- # e.g. if there are 20 leap year days between 2 dates having the same day
- # and month then the based on 365 days calculation
- # the distance in years will come out to over 80 years when in written
- # English it would read better as about 80 years.
- minutes_with_offset = distance_in_minutes - minute_offset_for_leap_year
- else
- minutes_with_offset = distance_in_minutes
- end
+ from_year = from_time.year
+ from_year += 1 if from_time.month >= 3
+ to_year = to_time.year
+ to_year -= 1 if to_time.month < 3
+ leap_years = (from_year > to_year) ? 0 : (from_year..to_year).count { |x| Date.leap?(x) }
+ minute_offset_for_leap_year = leap_years * 1440
+ # Discount the leap year days when calculating year distance.
+ # e.g. if there are 20 leap year days between 2 dates having the same day
+ # and month then the based on 365 days calculation
+ # the distance in years will come out to over 80 years when in written
+ # English it would read better as about 80 years.
+ minutes_with_offset = distance_in_minutes - minute_offset_for_leap_year
remainder = (minutes_with_offset % MINUTES_IN_YEAR)
distance_in_years = (minutes_with_offset.div MINUTES_IN_YEAR)
if remainder < MINUTES_IN_QUARTER_YEAR
@@ -687,6 +683,18 @@ module ActionView
content_tag("time".freeze, content, options.reverse_merge(datetime: datetime), &block)
end
+
+ private
+
+ def normalize_distance_of_time_argument_to_time(value)
+ if value.is_a?(Numeric)
+ Time.at(value)
+ elsif value.respond_to?(:to_time)
+ value.to_time
+ else
+ raise ArgumentError, "#{value.inspect} can't be converted to a Time value"
+ end
+ end
end
class DateTimeSelector #:nodoc:
diff --git a/actionview/lib/action_view/helpers/tags/base.rb b/actionview/lib/action_view/helpers/tags/base.rb
index 0895533a60..aa420c4b66 100644
--- a/actionview/lib/action_view/helpers/tags/base.rb
+++ b/actionview/lib/action_view/helpers/tags/base.rb
@@ -149,7 +149,7 @@ module ActionView
end
value = options.fetch(:selected) { value(object) }
- select = content_tag("select", add_options(option_tags, options, value), html_options)
+ select = content_tag("select", add_options(option_tags, options, value), html_options.except!("skip_default_ids", "allow_method_names_outside_object"))
if html_options["multiple"] && options.fetch(:include_hidden, true)
tag("input", disabled: html_options["disabled"], name: html_options["name"], type: "hidden", value: "") + select
diff --git a/actionview/lib/action_view/helpers/url_helper.rb b/actionview/lib/action_view/helpers/url_helper.rb
index 70fc57c35f..a6857101b9 100644
--- a/actionview/lib/action_view/helpers/url_helper.rb
+++ b/actionview/lib/action_view/helpers/url_helper.rb
@@ -542,7 +542,7 @@ module ActionView
return false unless request.get? || request.head?
- check_parameters ||= !options.is_a?(String) && options.try(:delete, :check_parameters)
+ check_parameters ||= options.is_a?(Hash) && options.delete(:check_parameters)
url_string = URI.parser.unescape(url_for(options)).force_encoding(Encoding::BINARY)
# We ignore any extra parameters in the request_uri if the
diff --git a/actionview/test/activerecord/controller_runtime_test.rb b/actionview/test/activerecord/controller_runtime_test.rb
index 590559f592..1cec5072c0 100644
--- a/actionview/test/activerecord/controller_runtime_test.rb
+++ b/actionview/test/activerecord/controller_runtime_test.rb
@@ -67,7 +67,7 @@ class ControllerRuntimeLogSubscriberTest < ActionController::TestCase
wait
assert_equal 2, @logger.logged(:info).size
- assert_match(/\(Views: [\d.]+ms \| ActiveRecord: 0.0ms\)/, @logger.logged(:info)[1])
+ assert_match(/\(Views: [\d.]+ms \| ActiveRecord: 0\.0ms\)/, @logger.logged(:info)[1])
end
def test_log_with_active_record_when_post
diff --git a/actionview/test/fixtures/comments/empty.html+grid.erb b/actionview/test/fixtures/comments/empty.html+grid.erb
new file mode 100644
index 0000000000..dc3fa32a81
--- /dev/null
+++ b/actionview/test/fixtures/comments/empty.html+grid.erb
@@ -0,0 +1 @@
+<h1>No Comment</h1>
diff --git a/actionview/test/fixtures/test/_partial_with_variants.html+grid.erb b/actionview/test/fixtures/test/_partial_with_variants.html+grid.erb
new file mode 100644
index 0000000000..225363c8c3
--- /dev/null
+++ b/actionview/test/fixtures/test/_partial_with_variants.html+grid.erb
@@ -0,0 +1 @@
+<h1>Partial with variants</h1>
diff --git a/actionview/test/template/asset_tag_helper_test.rb b/actionview/test/template/asset_tag_helper_test.rb
index 07a6452cc1..b7a993c5c9 100644
--- a/actionview/test/template/asset_tag_helper_test.rb
+++ b/actionview/test/template/asset_tag_helper_test.rb
@@ -709,13 +709,13 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase
def test_should_wildcard_asset_host
@controller.config.asset_host = "http://a%d.example.com"
- assert_match(%r(http://a[0123].example.com), compute_asset_host("foo"))
+ assert_match(%r(http://a[0123]\.example\.com), compute_asset_host("foo"))
end
def test_should_wildcard_asset_host_between_zero_and_four
@controller.config.asset_host = "http://a%d.example.com"
- assert_match(%r(http://a[0123].example.com/collaboration/hieraki/images/xml.png), image_path("xml.png"))
- assert_match(%r(http://a[0123].example.com/collaboration/hieraki/images/xml.png), image_url("xml.png"))
+ assert_match(%r(http://a[0123]\.example\.com/collaboration/hieraki/images/xml\.png), image_path("xml.png"))
+ assert_match(%r(http://a[0123]\.example\.com/collaboration/hieraki/images/xml\.png), image_url("xml.png"))
end
def test_asset_host_without_protocol_should_be_protocol_relative
diff --git a/actionview/test/template/atom_feed_helper_test.rb b/actionview/test/template/atom_feed_helper_test.rb
index 1245a1a966..7304b769a4 100644
--- a/actionview/test/template/atom_feed_helper_test.rb
+++ b/actionview/test/template/atom_feed_helper_test.rb
@@ -301,8 +301,8 @@ class AtomFeedTest < ActionController::TestCase
with_restful_routing(:scrolls) do
get :index, params: { id: "feed_with_atomPub_namespace" }
assert_match %r{xml:lang="en-US"}, @response.body
- assert_match %r{xmlns="http://www.w3.org/2005/Atom"}, @response.body
- assert_match %r{xmlns:app="http://www.w3.org/2007/app"}, @response.body
+ assert_match %r{xmlns="http://www\.w3\.org/2005/Atom"}, @response.body
+ assert_match %r{xmlns:app="http://www\.w3\.org/2007/app"}, @response.body
end
end
@@ -319,7 +319,7 @@ class AtomFeedTest < ActionController::TestCase
with_restful_routing(:scrolls) do
get :index, params: { id: "feed_with_xml_processing_instructions" }
assert_match %r{<\?xml-stylesheet [^\?]*type="text/css"}, @response.body
- assert_match %r{<\?xml-stylesheet [^\?]*href="t.css"}, @response.body
+ assert_match %r{<\?xml-stylesheet [^\?]*href="t\.css"}, @response.body
end
end
@@ -334,7 +334,7 @@ class AtomFeedTest < ActionController::TestCase
def test_feed_xhtml
with_restful_routing(:scrolls) do
get :index, params: { id: "feed_with_xhtml_content" }
- assert_match %r{xmlns="http://www.w3.org/1999/xhtml"}, @response.body
+ assert_match %r{xmlns="http://www\.w3\.org/1999/xhtml"}, @response.body
assert_select "summary", text: /Something Boring/
assert_select "summary", text: /after 2/
end
diff --git a/actionview/test/template/date_helper_test.rb b/actionview/test/template/date_helper_test.rb
index d257147e1f..a259752d6a 100644
--- a/actionview/test/template/date_helper_test.rb
+++ b/actionview/test/template/date_helper_test.rb
@@ -128,6 +128,16 @@ class DateHelperTest < ActionView::TestCase
assert_distance_of_time_in_words(from)
end
+ def test_distance_in_words_with_nil_input
+ assert_raises(ArgumentError) { distance_of_time_in_words(nil) }
+ assert_raises(ArgumentError) { distance_of_time_in_words(0, nil) }
+ end
+
+ def test_distance_in_words_with_mixed_argument_types
+ assert_equal "1 minute", distance_of_time_in_words(0, Time.at(60))
+ assert_equal "10 minutes", distance_of_time_in_words(Time.at(600), 0)
+ end
+
def test_distance_in_words_with_mathn_required
# test we avoid Integer#/ (redefined by mathn)
silence_warnings { require "mathn" }
diff --git a/actionview/test/template/form_helper/form_with_test.rb b/actionview/test/template/form_helper/form_with_test.rb
index a09dd468dd..bff0643fb0 100644
--- a/actionview/test/template/form_helper/form_with_test.rb
+++ b/actionview/test/template/form_helper/form_with_test.rb
@@ -302,6 +302,7 @@ class FormWithActsLikeFormForTest < FormWithTest
concat f.text_field(:title)
concat f.text_area(:body)
concat f.check_box(:secret)
+ concat f.select(:category, %w( animal economy sports ))
concat f.submit("Create post")
concat f.button("Create post")
concat f.button {
@@ -315,6 +316,7 @@ class FormWithActsLikeFormForTest < FormWithTest
"<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" \
"<input name='post[secret]' type='hidden' value='0' />" \
"<input name='post[secret]' checked='checked' type='checkbox' value='1' />" \
+ "<select name='post[category]'><option value='animal'>animal</option>\n<option value='economy'>economy</option>\n<option value='sports'>sports</option></select>" \
"<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />" \
"<button name='button' type='submit'>Create post</button>" \
"<button name='button' type='submit'><span>Create post</span></button>"
diff --git a/actionview/test/template/render_test.rb b/actionview/test/template/render_test.rb
index 412948719c..3f66ab3ed3 100644
--- a/actionview/test/template/render_test.rb
+++ b/actionview/test/template/render_test.rb
@@ -27,7 +27,7 @@ module RenderTestCases
def test_render_without_options
e = assert_raises(ArgumentError) { @view.render() }
- assert_match(/You invoked render but did not give any of (.+) option./, e.message)
+ assert_match(/You invoked render but did not give any of (.+) option\./, e.message)
end
def test_render_file
@@ -83,6 +83,10 @@ module RenderTestCases
assert_equal "<h1>Kein Kommentar</h1>", @view.render(template: "comments/empty", locale: [:de])
end
+ def test_render_template_with_variants
+ assert_equal "<h1>No Comment</h1>\n", @view.render(template: "comments/empty", variants: :grid)
+ end
+
def test_render_file_with_handlers
assert_equal "<h1>No Comment</h1>\n", @view.render(file: "comments/empty", handlers: [:builder])
assert_equal "<h1>No Comment</h1>\n", @view.render(file: "comments/empty", handlers: :builder)
@@ -170,6 +174,10 @@ module RenderTestCases
assert_equal "partial html", @view.render(partial: "test/partial")
end
+ def test_render_partial_with_variants
+ assert_equal "<h1>Partial with variants</h1>\n", @view.render(partial: "test/partial_with_variants", variants: :grid)
+ end
+
def test_render_partial_with_selected_format
assert_equal "partial html", @view.render(partial: "test/partial", formats: :html)
assert_equal "partial js", @view.render(partial: "test/partial", formats: [:js])
@@ -253,7 +261,7 @@ module RenderTestCases
def test_render_sub_template_with_errors
e = assert_raises(ActionView::Template::Error) { @view.render(template: "test/sub_template_raise") }
assert_match %r!method.*doesnt_exist!, e.message
- assert_match %r{Trace of template inclusion: .*test/sub_template_raise.html.erb}, e.sub_template_message
+ assert_match %r{Trace of template inclusion: .*test/sub_template_raise\.html\.erb}, e.sub_template_message
assert_equal "1", e.line_number
assert_equal File.expand_path("#{FIXTURE_LOAD_PATH}/test/_raise.html.erb"), e.file_name
end
diff --git a/actionview/test/template/url_helper_test.rb b/actionview/test/template/url_helper_test.rb
index a6444a1686..6adfa95dd1 100644
--- a/actionview/test/template/url_helper_test.rb
+++ b/actionview/test/template/url_helper_test.rb
@@ -509,6 +509,12 @@ class UrlHelperTest < ActiveSupport::TestCase
assert !current_page?("http://www.example.com/", check_parameters: true)
end
+ def test_current_page_considering_params_when_options_does_not_respond_to_to_hash
+ @request = request_for_url("/?order=desc&page=1")
+
+ assert !current_page?(:back, check_parameters: false)
+ end
+
def test_current_page_with_params_that_match
@request = request_for_url("/?order=desc&page=1")
@@ -676,13 +682,6 @@ class UrlHelperTest < ActiveSupport::TestCase
def request_forgery_protection_token
"form_token"
end
-
- private
- def sort_query_string_params(uri)
- path, qs = uri.split("?")
- qs = qs.split("&amp;").sort.join("&amp;") if qs
- qs ? "#{path}?#{qs}" : path
- end
end
class UrlHelperControllerTest < ActionController::TestCase
@@ -880,6 +879,11 @@ class WorkshopsController < ActionController::Base
@workshop = Workshop.new(params[:id])
render inline: "<%= url_for(@workshop) %>\n<%= link_to('Workshop', @workshop) %>"
end
+
+ def edit
+ @workshop = Workshop.new(params[:id])
+ render inline: "<%= current_page?(@workshop) %>"
+ end
end
class SessionsController < ActionController::Base
@@ -944,4 +948,11 @@ class PolymorphicControllerTest < ActionController::TestCase
get :edit, params: { workshop_id: 1, id: 1, format: "json" }
assert_equal %{/workshops/1/sessions/1.json\n<a href="/workshops/1/sessions/1.json">Session</a>}, @response.body
end
+
+ def test_current_page_when_options_does_not_respond_to_to_hash
+ @controller = WorkshopsController.new
+
+ get :edit, params: { id: 1 }
+ assert_equal "false", @response.body
+ end
end
diff --git a/activejob/CHANGELOG.md b/activejob/CHANGELOG.md
index ddfb926e02..77dfdefc05 100644
--- a/activejob/CHANGELOG.md
+++ b/activejob/CHANGELOG.md
@@ -4,4 +4,5 @@
*Steven Bull*
+
Please check [5-1-stable](https://github.com/rails/rails/blob/5-1-stable/activejob/CHANGELOG.md) for previous changes.
diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md
index cdba0cee12..e707a65147 100644
--- a/activemodel/CHANGELOG.md
+++ b/activemodel/CHANGELOG.md
@@ -4,27 +4,27 @@
Change `#values` to only return the not empty values.
- Example:
-
- # Before
- person = Person.new
- person.errors.keys # => []
- person.errors.values # => []
- person.errors.messages # => {}
- person.errors[:name] # => []
- person.errors.messages # => {:name => []}
- person.errors.keys # => [:name]
- person.errors.values # => [[]]
-
- # After
- person = Person.new
- person.errors.keys # => []
- person.errors.values # => []
- person.errors.messages # => {}
- person.errors[:name] # => []
- person.errors.messages # => {:name => []}
- person.errors.keys # => []
- person.errors.values # => []
+ Example:
+
+ # Before
+ person = Person.new
+ person.errors.keys # => []
+ person.errors.values # => []
+ person.errors.messages # => {}
+ person.errors[:name] # => []
+ person.errors.messages # => {:name => []}
+ person.errors.keys # => [:name]
+ person.errors.values # => [[]]
+
+ # After
+ person = Person.new
+ person.errors.keys # => []
+ person.errors.values # => []
+ person.errors.messages # => {}
+ person.errors[:name] # => []
+ person.errors.messages # => {:name => []}
+ person.errors.keys # => []
+ person.errors.values # => []
*bogdanvlviv*
diff --git a/activemodel/lib/active_model/validations/validates.rb b/activemodel/lib/active_model/validations/validates.rb
index 0ce5935f3a..a8b958e974 100644
--- a/activemodel/lib/active_model/validations/validates.rb
+++ b/activemodel/lib/active_model/validations/validates.rb
@@ -18,7 +18,6 @@ module ActiveModel
# validates :first_name, length: { maximum: 30 }
# validates :age, numericality: true
# validates :username, presence: true
- # validates :username, uniqueness: true
#
# The power of the +validates+ method comes when using custom validators
# and default validators in one call for a given attribute.
@@ -34,7 +33,7 @@ module ActiveModel
# include ActiveModel::Validations
# attr_accessor :name, :email
#
- # validates :name, presence: true, uniqueness: true, length: { maximum: 100 }
+ # validates :name, presence: true, length: { maximum: 100 }
# validates :email, presence: true, email: true
# end
#
@@ -94,7 +93,7 @@ module ActiveModel
# Example:
#
# validates :password, presence: true, confirmation: true, if: :password_required?
- # validates :token, uniqueness: true, strict: TokenGenerationException
+ # validates :token, length: 24, strict: TokenLengthException
#
#
# Finally, the options +:if+, +:unless+, +:on+, +:allow_blank+, +:allow_nil+, +:strict+
diff --git a/activemodel/lib/active_model/validator.rb b/activemodel/lib/active_model/validator.rb
index 98234e9b6b..1a4d13f2d0 100644
--- a/activemodel/lib/active_model/validator.rb
+++ b/activemodel/lib/active_model/validator.rb
@@ -97,7 +97,7 @@ module ActiveModel
# Returns the kind of the validator.
#
# PresenceValidator.kind # => :presence
- # UniquenessValidator.kind # => :uniqueness
+ # AcceptanceValidator.kind # => :acceptance
def self.kind
@kind ||= name.split("::").last.underscore.chomp("_validator").to_sym unless anonymous?
end
@@ -109,8 +109,8 @@ module ActiveModel
# Returns the kind for this validator.
#
- # PresenceValidator.new.kind # => :presence
- # UniquenessValidator.new.kind # => :uniqueness
+ # PresenceValidator.new(attributes: [:username]).kind # => :presence
+ # AcceptanceValidator.new(attributes: [:terms]).kind # => :acceptance
def kind
self.class.kind
end
diff --git a/activemodel/test/cases/validations/format_validation_test.rb b/activemodel/test/cases/validations/format_validation_test.rb
index d7e6bf3707..f5b1ad721c 100644
--- a/activemodel/test/cases/validations/format_validation_test.rb
+++ b/activemodel/test/cases/validations/format_validation_test.rb
@@ -107,7 +107,7 @@ class PresenceValidationTest < ActiveModel::TestCase
end
def test_validates_format_of_with_lambda
- Topic.validates_format_of :content, with: lambda { |topic| topic.title == "digit" ? /\A\d+\Z/ : /\A\S+\Z/ }
+ Topic.validates_format_of :content, with: lambda { |topic| topic.title == "digit" ? /\A\d+\z/ : /\A\S+\z/ }
t = Topic.new
t.title = "digit"
@@ -119,7 +119,7 @@ class PresenceValidationTest < ActiveModel::TestCase
end
def test_validates_format_of_without_lambda
- Topic.validates_format_of :content, without: lambda { |topic| topic.title == "characters" ? /\A\d+\Z/ : /\A\S+\Z/ }
+ Topic.validates_format_of :content, without: lambda { |topic| topic.title == "characters" ? /\A\d+\z/ : /\A\S+\z/ }
t = Topic.new
t.title = "characters"
@@ -131,7 +131,7 @@ class PresenceValidationTest < ActiveModel::TestCase
end
def test_validates_format_of_for_ruby_class
- Person.validates_format_of :karma, with: /\A\d+\Z/
+ Person.validates_format_of :karma, with: /\A\d+\z/
p = Person.new
p.karma = "Pixies"
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index a229b4eaa2..4e264f5f2a 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,4 +1,18 @@
-* Quote database name in db:create grant statement (when database_user does not have access to create the database).
+* Respect 'SchemaDumper.ignore_tables' in rake tasks for databases structure dump
+
+ *Rusty Geldmacher*, *Guillermo Iguaran*
+
+* Add type caster to `RuntimeReflection#alias_name`
+
+ Fixes #28959.
+
+ *Jon Moss*
+
+* Deprecate `supports_statement_cache?`.
+
+ *Ryuta Kamizono*
+
+* Quote database name in `db:create` grant statement (when database user does not have access to create the database).
*Rune Philosof*
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index e52c2004f3..7c37132d3a 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1276,7 +1276,7 @@ module ActiveRecord
# Scope examples:
# has_many :comments, -> { where(author_id: 1) }
# has_many :employees, -> { joins(:address) }
- # has_many :posts, ->(post) { where("max_post_length > ?", post.length) }
+ # has_many :posts, ->(blog) { where("max_post_length > ?", blog.max_post_length) }
#
# === Extensions
#
@@ -1443,7 +1443,7 @@ module ActiveRecord
# Scope examples:
# has_one :author, -> { where(comment_id: 1) }
# has_one :employer, -> { joins(:company) }
- # has_one :dob, ->(dob) { where("Date.new(2000, 01, 01) > ?", dob) }
+ # has_one :latest_post, ->(blog) { where("created_at > ?", blog.enabled_at) }
#
# === Options
#
@@ -1573,7 +1573,7 @@ module ActiveRecord
# Scope examples:
# belongs_to :firm, -> { where(id: 2) }
# belongs_to :user, -> { joins(:friends) }
- # belongs_to :level, ->(level) { where("game_level > ?", level.current) }
+ # belongs_to :level, ->(game) { where("game_level > ?", game.current_level) }
#
# === Options
#
@@ -1769,9 +1769,8 @@ module ActiveRecord
#
# Scope examples:
# has_and_belongs_to_many :projects, -> { includes(:milestones, :manager) }
- # has_and_belongs_to_many :categories, ->(category) {
- # where("default_category = ?", category.name)
- # }
+ # has_and_belongs_to_many :categories, ->(post) {
+ # where("default_category = ?", post.default_category)
#
# === Extensions
#
diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb
index a2432e389a..0e61dbfb00 100644
--- a/activerecord/lib/active_record/associations/belongs_to_association.rb
+++ b/activerecord/lib/active_record/associations/belongs_to_association.rb
@@ -22,7 +22,7 @@ module ActiveRecord
end
def default(&block)
- writer(instance_exec(&block)) if reader.nil?
+ writer(owner.instance_exec(&block)) if reader.nil?
end
def reset
diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb
index 5d6676f0df..74a4d515c2 100644
--- a/activerecord/lib/active_record/associations/collection_proxy.rb
+++ b/activerecord/lib/active_record/associations/collection_proxy.rb
@@ -1121,6 +1121,19 @@ module ActiveRecord
delegate(*delegate_methods, to: :scope)
+ module DelegateExtending # :nodoc:
+ private
+ def method_missing(method, *args, &block)
+ extending_values = association_scope.extending_values
+ if extending_values.any? && (extending_values - self.class.included_modules).any?
+ self.class.include(*extending_values)
+ public_send(method, *args, &block)
+ else
+ super
+ end
+ end
+ end
+
private
def find_nth_with_limit(index, limit)
@@ -1141,21 +1154,16 @@ module ActiveRecord
@association.find_from_target?
end
+ def association_scope
+ @association.association_scope
+ end
+
def exec_queries
load_target
end
def respond_to_missing?(method, _)
- scope.respond_to?(method) || super
- end
-
- def method_missing(method, *args, &block)
- if scope.respond_to?(method) && scope.extending_values.any?
- extend(*scope.extending_values)
- public_send(method, *args, &block)
- else
- super
- end
+ association_scope.respond_to?(method) || super
end
end
end
diff --git a/activerecord/lib/active_record/associations/preloader/through_association.rb b/activerecord/lib/active_record/associations/preloader/through_association.rb
index 9d44a02021..d53d3f777b 100644
--- a/activerecord/lib/active_record/associations/preloader/through_association.rb
+++ b/activerecord/lib/active_record/associations/preloader/through_association.rb
@@ -16,15 +16,13 @@ module ActiveRecord
through_scope)
through_records = owners.map do |owner|
- association = owner.association through_reflection.name
-
- center = target_records_from_association(association)
+ center = owner.association(through_reflection.name).target
[owner, Array(center)]
end
reset_association owners, through_reflection.name
- middle_records = through_records.flat_map { |(_, rec)| rec }
+ middle_records = through_records.flat_map(&:last)
preloaders = preloader.preload(middle_records,
source_reflection.name,
@@ -43,9 +41,7 @@ module ActiveRecord
records_by_owner[lhs] = pl_to_middle.flat_map do |pl, middles|
rhs_records = middles.flat_map { |r|
- association = r.association source_reflection.name
-
- target_records_from_association(association)
+ r.association(source_reflection.name).target
}.compact
# Respect the order on `reflection_scope` if it exists, else use the natural order.
@@ -98,10 +94,6 @@ module ActiveRecord
scope
end
-
- def target_records_from_association(association)
- association.loaded? ? association.target : association.reader
- end
end
end
end
diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb
index 607c54e481..ebe92e7878 100644
--- a/activerecord/lib/active_record/autosave_association.rb
+++ b/activerecord/lib/active_record/autosave_association.rb
@@ -389,7 +389,7 @@ module ActiveRecord
autosave = reflection.options[:autosave]
# reconstruct the scope now that we know the owner's id
- association.reset_scope if association.respond_to?(:reset_scope)
+ association.reset_scope
if records = associated_records_to_validate_or_save(association, @new_record_before_save, autosave)
if autosave
diff --git a/activerecord/lib/active_record/collection_cache_key.rb b/activerecord/lib/active_record/collection_cache_key.rb
index 1e1de1863a..8b937b6703 100644
--- a/activerecord/lib/active_record/collection_cache_key.rb
+++ b/activerecord/lib/active_record/collection_cache_key.rb
@@ -20,7 +20,7 @@ module ActiveRecord
subquery_alias = "subquery_for_cache_key"
subquery_column = "#{subquery_alias}.#{timestamp_column}"
subquery = query.arel.as(subquery_alias)
- arel = Arel::SelectManager.new(query.engine).project(select_values % subquery_column).from(subquery)
+ arel = Arel::SelectManager.new(subquery).project(select_values % subquery_column)
else
query = collection.unscope(:order)
query.select_values = [select_values % column]
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
index 177b253645..61bf5477aa 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -506,14 +506,16 @@ module ActiveRecord
# +conn+: an AbstractAdapter object, which was obtained by earlier by
# calling #checkout on this pool.
def checkin(conn)
- synchronize do
- remove_connection_from_thread_cache conn
+ conn.lock.synchronize do
+ synchronize do
+ remove_connection_from_thread_cache conn
- conn._run_checkin_callbacks do
- conn.expire
- end
+ conn._run_checkin_callbacks do
+ conn.expire
+ end
- @available.add conn
+ @available.add conn
+ end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
index 769f488469..c6811a4802 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -137,9 +137,10 @@ module ActiveRecord
# Returns +true+ when the connection adapter supports prepared statement
# caching, otherwise returns +false+
- def supports_statement_cache?
- false
+ def supports_statement_cache? # :nodoc:
+ true
end
+ deprecate :supports_statement_cache?
# Runs the given block in a database transaction, and returns the result
# of the block.
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
index f0c0fbab6c..61233dcc51 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
@@ -10,8 +10,15 @@ module ActiveRecord
value = id_value_for_database(value) if value.is_a?(Base)
if value.respond_to?(:quoted_id)
+ at = value.method(:quoted_id).source_location
+ at &&= " at %s:%d" % at
+
+ owner = value.method(:quoted_id).owner.to_s
+ klass = value.class.to_s
+ klass += "(#{owner})" unless owner == klass
+
ActiveSupport::Deprecation.warn \
- "Using #quoted_id is deprecated and will be removed in Rails 5.2."
+ "Defining #quoted_id is deprecated and will be ignored in Rails 5.2. (defined on #{klass}#{at})"
return value.quoted_id
end
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 c742799aab..abc15f595f 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -76,12 +76,6 @@ module ActiveRecord
true
end
- # Returns true, since this connection adapter supports prepared statement
- # caching.
- def supports_statement_cache?
- true
- end
-
def supports_index_sort_order?
!mariadb? && version >= "8.0.1"
end
@@ -720,16 +714,14 @@ module ActiveRecord
# MySQL is too stupid to create a temporary table for use subquery, so we have
# to give it some prompting in the form of a subsubquery. Ugh!
def subquery_for(key, select)
- subsubselect = select.clone
- subsubselect.projections = [key]
+ subselect = select.clone
+ subselect.projections = [key]
# Materialize subquery by adding distinct
# to work with MySQL 5.7.6 which sets optimizer_switch='derived_merge=on'
- subsubselect.distinct unless select.limit || select.offset || select.orders.any?
+ subselect.distinct unless select.limit || select.offset || select.orders.any?
- subselect = Arel::SelectManager.new(select.engine)
- subselect.project Arel.sql(key.name)
- subselect.from subsubselect.as("__active_record_temp")
+ Arel::SelectManager.new(subselect.as("__active_record_temp")).project(Arel.sql(key.name))
end
def supports_rename_index?
diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
index 45e400b75b..af55cfe2f6 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
@@ -10,8 +10,6 @@ module ActiveRecord
# Establishes a connection to the database that's used by all Active Record objects.
def mysql2_connection(config)
config = config.symbolize_keys
-
- config[:username] = "root" if config[:username].nil?
config[:flags] ||= 0
if config[:flags].kind_of? Array
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/referential_integrity.rb b/activerecord/lib/active_record/connection_adapters/postgresql/referential_integrity.rb
index 730e7c7137..44a7338bf5 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/referential_integrity.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/referential_integrity.rb
@@ -6,50 +6,8 @@ module ActiveRecord
true
end
- def disable_referential_integrity(&block) # :nodoc:
+ def disable_referential_integrity # :nodoc:
if supports_disable_referential_integrity?
- if supports_alter_constraint?
- disable_referential_integrity_with_alter_constraint(&block)
- else
- disable_referential_integrity_with_disable_trigger(&block)
- end
- else
- yield
- end
- end
-
- private
-
- def disable_referential_integrity_with_alter_constraint
- tables_constraints = execute(<<-SQL).values
- SELECT table_name, constraint_name
- FROM information_schema.table_constraints
- WHERE constraint_type = 'FOREIGN KEY'
- AND is_deferrable = 'NO'
- SQL
-
- execute(
- tables_constraints.collect { |table, constraint|
- "ALTER TABLE #{quote_table_name(table)} ALTER CONSTRAINT #{constraint} DEFERRABLE"
- }.join(";")
- )
-
- begin
- transaction do
- execute("SET CONSTRAINTS ALL DEFERRED")
-
- yield
- end
- ensure
- execute(
- tables_constraints.collect { |table, constraint|
- "ALTER TABLE #{quote_table_name(table)} ALTER CONSTRAINT #{constraint} NOT DEFERRABLE"
- }.join(";")
- )
- end
- end
-
- def disable_referential_integrity_with_disable_trigger
original_exception = nil
begin
@@ -81,7 +39,10 @@ Rails needs superuser privileges to disable referential integrity.
end
rescue ActiveRecord::ActiveRecordError
end
+ else
+ yield
end
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 7ae9bd9a5f..f74f966fd9 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -121,12 +121,6 @@ module ActiveRecord
include PostgreSQL::DatabaseStatements
include PostgreSQL::ColumnDumper
- # Returns true, since this connection adapter supports prepared statement
- # caching.
- def supports_statement_cache?
- true
- end
-
def supports_index_sort_order?
true
end
@@ -314,12 +308,6 @@ module ActiveRecord
postgresql_version >= 90400
end
- def supports_alter_constraint?
- # PostgreSQL 9.4 introduces ALTER TABLE ... ALTER CONSTRAINT but it has a bug and fixed in 9.4.2
- # https://www.postgresql.org/docs/9.4/static/release-9-4-2.html
- postgresql_version >= 90402
- end
-
def get_advisory_lock(lock_id) # :nodoc:
unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
raise(ArgumentError, "Postgres requires advisory lock ids to be a signed 64 bit integer")
@@ -561,7 +549,7 @@ module ActiveRecord
end
def has_default_function?(default_value, default)
- !default_value && (%r{\w+\(.*\)|\(.*\)::\w+} === default)
+ !default_value && %r{\w+\(.*\)|\(.*\)::\w+|CURRENT_DATE|CURRENT_TIMESTAMP}.match?(default)
end
def load_additional_types(type_map, oids = nil)
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index e2c05ccc4e..7233325d5a 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -105,12 +105,6 @@ module ActiveRecord
sqlite_version >= "3.8.0"
end
- # Returns true, since this connection adapter supports prepared statement
- # caching.
- def supports_statement_cache?
- true
- end
-
def requires_reloading?
true
end
diff --git a/activerecord/lib/active_record/dynamic_matchers.rb b/activerecord/lib/active_record/dynamic_matchers.rb
index d9912cfb22..3a9625092e 100644
--- a/activerecord/lib/active_record/dynamic_matchers.rb
+++ b/activerecord/lib/active_record/dynamic_matchers.rb
@@ -1,15 +1,14 @@
module ActiveRecord
module DynamicMatchers #:nodoc:
- def respond_to_missing?(name, include_private = false)
- if self == Base
- super
- else
- match = Method.match(self, name)
- match && match.valid? || super
- end
- end
-
private
+ def respond_to_missing?(name, _)
+ if self == Base
+ super
+ else
+ match = Method.match(self, name)
+ match && match.valid? || super
+ end
+ end
def method_missing(name, *arguments, &block)
match = Method.match(self, name)
diff --git a/activerecord/lib/active_record/migration/command_recorder.rb b/activerecord/lib/active_record/migration/command_recorder.rb
index 03103bba98..f9cf59b283 100644
--- a/activerecord/lib/active_record/migration/command_recorder.rb
+++ b/activerecord/lib/active_record/migration/command_recorder.rb
@@ -92,10 +92,6 @@ module ActiveRecord
send(method, args, &block)
end
- def respond_to_missing?(*args) # :nodoc:
- super || delegate.respond_to?(*args)
- end
-
ReversibleAndIrreversibleMethods.each do |method|
class_eval <<-EOV, __FILE__, __LINE__ + 1
def #{method}(*args, &block) # def create_table(*args, &block)
@@ -225,10 +221,14 @@ module ActiveRecord
[:add_foreign_key, reversed_args]
end
+ def respond_to_missing?(method, _)
+ super || delegate.respond_to?(method)
+ end
+
# Forwards any missing method call to the \target.
def method_missing(method, *args, &block)
- if @delegate.respond_to?(method)
- @delegate.send(method, *args, &block)
+ if delegate.respond_to?(method)
+ delegate.public_send(method, *args, &block)
else
super
end
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index f3e2df8786..711099e9e1 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -93,7 +93,7 @@ db_namespace = namespace :db do
# desc 'Runs the "up" for a given migration VERSION.'
task up: [:environment, :load_config] do
- raise "VERSION is required" if ENV["VERSION"] && ENV["VERSION"].empty?
+ raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty?
version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
ActiveRecord::Migrator.run(:up, ActiveRecord::Tasks::DatabaseTasks.migrations_paths, version)
@@ -102,7 +102,7 @@ db_namespace = namespace :db do
# desc 'Runs the "down" for a given migration VERSION.'
task down: [:environment, :load_config] do
- raise "VERSION is required - To go down one migration, use db:rollback" if ENV["VERSION"] && ENV["VERSION"].empty?
+ raise "VERSION is required - To go down one migration, use db:rollback" if !ENV["VERSION"] || ENV["VERSION"].empty?
version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
ActiveRecord::Migrator.run(:down, ActiveRecord::Tasks::DatabaseTasks.migrations_paths, version)
db_namespace["_dump"].invoke
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 24ca8b0be4..1a9e0a4a40 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -212,7 +212,7 @@ module ActiveRecord
end
def constraints
- chain.map(&:scopes).flatten
+ chain.flat_map(&:scopes)
end
def counter_cache_column
@@ -1105,7 +1105,7 @@ module ActiveRecord
end
def alias_name
- Arel::Table.new(table_name)
+ Arel::Table.new(table_name, type_caster: klass.type_caster)
end
def all_includes; yield; end
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 5775eda5a5..333ad16e11 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -269,8 +269,7 @@ module ActiveRecord
# Returns true if there are no records.
def empty?
return @records.empty? if loaded?
-
- limit_value == 0 || !exists?
+ !exists?
end
# Returns true if there are no records.
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index 9cabd1af13..861b2125d4 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -368,9 +368,8 @@ module ActiveRecord
relation.select_values = [aliased_column]
subquery = relation.arel.as(subquery_alias)
- sm = Arel::SelectManager.new relation.engine
select_value = operation_over_aggregate_column(column_alias, "count", distinct)
- sm.project(select_value).from(subquery)
+ Arel::SelectManager.new(subquery).project(select_value)
end
end
end
diff --git a/activerecord/lib/active_record/relation/delegation.rb b/activerecord/lib/active_record/relation/delegation.rb
index 50378f9d99..257ae04ff4 100644
--- a/activerecord/lib/active_record/relation/delegation.rb
+++ b/activerecord/lib/active_record/relation/delegation.rb
@@ -25,6 +25,8 @@ module ActiveRecord
def inherited(child_class)
child_class.initialize_relation_delegate_cache
+ delegate = child_class.relation_delegate_class(ActiveRecord::Associations::CollectionProxy)
+ delegate.include ActiveRecord::Associations::CollectionProxy::DelegateExtending
super
end
end
@@ -109,12 +111,10 @@ module ActiveRecord
end
end
- def respond_to_missing?(method, include_private = false)
- super || @klass.respond_to?(method, include_private) ||
- arel.respond_to?(method, include_private)
- end
-
private
+ def respond_to_missing?(method, _)
+ super || @klass.respond_to?(method) || arel.respond_to?(method)
+ end
def method_missing(method, *args, &block)
if @klass.respond_to?(method)
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index a1459c87c6..1d661fa8ed 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -307,9 +307,11 @@ module ActiveRecord
MSG
end
- return false if !conditions
+ return false if !conditions || limit_value == 0
+
+ relation = self unless eager_loading?
+ relation ||= apply_join_dependency(self, construct_join_dependency(eager_loading: false))
- relation = apply_join_dependency(self, construct_join_dependency(eager_loading: false))
return false if ActiveRecord::NullRelation === relation
relation = construct_relation_for_exists(relation, conditions)
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 1178dec706..76e529f2de 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -248,7 +248,7 @@ module ActiveRecord
return super()
end
- raise ArgumentError, "Call this with at least one field" if fields.empty?
+ raise ArgumentError, "Call `select' with at least one field" if fields.empty?
spawn._select!(*fields)
end
diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb
index 94d63765c9..24b81aabc8 100644
--- a/activerecord/lib/active_record/schema_dumper.rb
+++ b/activerecord/lib/active_record/schema_dumper.rb
@@ -11,8 +11,8 @@ module ActiveRecord
##
# :singleton-method:
# A list of tables which should not be dumped to the schema.
- # Acceptable values are strings as well as regexp.
- # This setting is only used if ActiveRecord::Base.schema_format == :ruby
+ # Acceptable values are strings as well as regexp if ActiveRecord::Base.schema_format == :ruby.
+ # Only strings are accepted if ActiveRecord::Base.schema_format == :sql.
cattr_accessor :ignore_tables
@@ignore_tables = []
diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb
index 46fa8a70a3..c53dee43d7 100644
--- a/activerecord/lib/active_record/tasks/database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/database_tasks.rb
@@ -71,9 +71,9 @@ module ActiveRecord
@tasks[pattern] = task
end
- register_task(/mysql/, ActiveRecord::Tasks::MySQLDatabaseTasks)
- register_task(/postgresql/, ActiveRecord::Tasks::PostgreSQLDatabaseTasks)
- register_task(/sqlite/, ActiveRecord::Tasks::SQLiteDatabaseTasks)
+ register_task(/mysql/, 'ActiveRecord::Tasks::MySQLDatabaseTasks')
+ register_task(/postgresql/, 'ActiveRecord::Tasks::PostgreSQLDatabaseTasks')
+ register_task(/sqlite/, 'ActiveRecord::Tasks::SQLiteDatabaseTasks')
def db_dir
@db_dir ||= Rails.application.config.paths["db"].first
@@ -164,7 +164,7 @@ module ActiveRecord
def migrate
raise "Empty VERSION provided" if ENV["VERSION"] && ENV["VERSION"].empty?
- verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
+ verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] != "false" : true
version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
scope = ENV["SCOPE"]
verbose_was, Migration.verbose = Migration.verbose, verbose
@@ -288,11 +288,11 @@ module ActiveRecord
private
def class_for_adapter(adapter)
- key = @tasks.keys.detect { |pattern| adapter[pattern] }
- unless key
+ _key, task = @tasks.each_pair.detect { |pattern, _task| adapter[pattern] }
+ unless task
raise DatabaseNotSupported, "Rake tasks not supported by '#{adapter}' adapter"
end
- @tasks[key]
+ task.is_a?(String) ? task.constantize : task
end
def each_current_configuration(environment)
diff --git a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
index c05f0a8fbb..541165b3d1 100644
--- a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
@@ -60,6 +60,12 @@ module ActiveRecord
args.concat(["--routines"])
args.concat(["--skip-comments"])
args.concat(Array(extra_flags)) if extra_flags
+
+ ignore_tables = ActiveRecord::SchemaDumper.ignore_tables
+ if ignore_tables.any?
+ args += ignore_tables.map { |table| "--ignore-table=#{configuration['database']}.#{table}" }
+ end
+
args.concat(["#{configuration['database']}"])
run_cmd("mysqldump", args, "dumping")
diff --git a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
index f1af90c1e8..7f1a768d8b 100644
--- a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
@@ -66,6 +66,12 @@ module ActiveRecord
"--schema=#{part.strip}"
end
end
+
+ ignore_tables = ActiveRecord::SchemaDumper.ignore_tables
+ if ignore_tables.any?
+ args += ignore_tables.flat_map { |table| ["-T", table] }
+ end
+
args << configuration["database"]
run_cmd("pg_dump", args, "dumping")
remove_sql_header_comments(filename)
diff --git a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb
index 1f756c2979..7043d2f0c8 100644
--- a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb
@@ -36,9 +36,18 @@ module ActiveRecord
end
def structure_dump(filename, extra_flags)
- dbfile = configuration["database"]
- flags = extra_flags.join(" ") if extra_flags
- `sqlite3 #{flags} #{dbfile} .schema > #{filename}`
+ args = []
+ args.concat(Array(extra_flags)) if extra_flags
+ args << configuration["database"]
+
+ ignore_tables = ActiveRecord::SchemaDumper.ignore_tables
+ if ignore_tables.any?
+ condition = ignore_tables.map { |table| connection.quote_table_name(table) }.join(", ")
+ args << "SELECT sql FROM sqlite_master WHERE tbl_name NOT IN (#{condition}) ORDER BY tbl_name, type DESC, name"
+ else
+ args << ".schema"
+ end
+ run_cmd("sqlite3", args, filename)
end
def structure_load(filename, extra_flags)
@@ -56,6 +65,17 @@ module ActiveRecord
def root
@root
end
+
+ def run_cmd(cmd, args, out)
+ fail run_cmd_error(cmd, args) unless Kernel.system(cmd, *args, out: out)
+ end
+
+ def run_cmd_error(cmd, args)
+ msg = "failed to execute:\n"
+ msg << "#{cmd} #{args.join(' ')}\n\n"
+ msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
+ msg
+ end
end
end
end
diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb
index 601d575c0e..a1fb6427f9 100644
--- a/activerecord/test/cases/adapter_test.rb
+++ b/activerecord/test/cases/adapter_test.rb
@@ -220,7 +220,7 @@ module ActiveRecord
def test_select_all_with_legacy_binds
post = Post.create!(title: "foo", body: "bar")
expected = @connection.select_all("SELECT * FROM posts WHERE id = #{post.id}")
- result = @connection.select_all("SELECT * FROM posts WHERE id = #{Arel::Nodes::BindParam.new.to_sql}", nil, [[nil, post.id]])
+ result = @connection.select_all("SELECT * FROM posts WHERE id = #{bind_param.to_sql}", nil, [[nil, post.id]])
assert_equal expected.to_hash, result.to_hash
end
end
diff --git a/activerecord/test/cases/adapters/mysql2/charset_collation_test.rb b/activerecord/test/cases/adapters/mysql2/charset_collation_test.rb
index 8826ad7fd1..e4a6ed5482 100644
--- a/activerecord/test/cases/adapters/mysql2/charset_collation_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/charset_collation_test.rb
@@ -48,7 +48,7 @@ class Mysql2CharsetCollationTest < ActiveRecord::Mysql2TestCase
test "schema dump includes collation" do
output = dump_table_schema("charset_collations")
- assert_match %r{t.string\s+"string_ascii_bin",\s+collation: "ascii_bin"$}, output
- assert_match %r{t.text\s+"text_ucs2_unicode_ci",\s+collation: "ucs2_unicode_ci"$}, output
+ assert_match %r{t\.string\s+"string_ascii_bin",\s+collation: "ascii_bin"$}, output
+ assert_match %r{t\.text\s+"text_ucs2_unicode_ci",\s+collation: "ucs2_unicode_ci"$}, output
end
end
diff --git a/activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb b/activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb
index a0823be143..71dcfaa241 100644
--- a/activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb
@@ -58,9 +58,9 @@ class Mysql2UnsignedTypeTest < ActiveRecord::Mysql2TestCase
test "schema dump includes unsigned option" do
schema = dump_table_schema "unsigned_types"
- assert_match %r{t.integer\s+"unsigned_integer",\s+unsigned: true$}, schema
- assert_match %r{t.bigint\s+"unsigned_bigint",\s+unsigned: true$}, schema
- assert_match %r{t.float\s+"unsigned_float",\s+limit: 24,\s+unsigned: true$}, schema
- assert_match %r{t.decimal\s+"unsigned_decimal",\s+precision: 10,\s+scale: 2,\s+unsigned: true$}, schema
+ assert_match %r{t\.integer\s+"unsigned_integer",\s+unsigned: true$}, schema
+ assert_match %r{t\.bigint\s+"unsigned_bigint",\s+unsigned: true$}, schema
+ assert_match %r{t\.float\s+"unsigned_float",\s+limit: 24,\s+unsigned: true$}, schema
+ assert_match %r{t\.decimal\s+"unsigned_decimal",\s+precision: 10,\s+scale: 2,\s+unsigned: true$}, schema
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/collation_test.rb b/activerecord/test/cases/adapters/postgresql/collation_test.rb
index b39e298a5d..a603221d8f 100644
--- a/activerecord/test/cases/adapters/postgresql/collation_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/collation_test.rb
@@ -47,7 +47,7 @@ class PostgresqlCollationTest < ActiveRecord::PostgreSQLTestCase
test "schema dump includes collation" do
output = dump_table_schema("postgresql_collations")
- assert_match %r{t.string\s+"string_c",\s+collation: "C"$}, output
- assert_match %r{t.text\s+"text_posix",\s+collation: "POSIX"$}, output
+ assert_match %r{t\.string\s+"string_c",\s+collation: "C"$}, output
+ assert_match %r{t\.text\s+"text_posix",\s+collation: "POSIX"$}, output
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/connection_test.rb b/activerecord/test/cases/adapters/postgresql/connection_test.rb
index c52d9e37cc..3deb007513 100644
--- a/activerecord/test/cases/adapters/postgresql/connection_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/connection_test.rb
@@ -127,8 +127,8 @@ module ActiveRecord
if ActiveRecord::Base.connection.prepared_statements
def test_statement_key_is_logged
- bind = Relation::QueryAttribute.new(nil, 1, Type::Value.new)
- @connection.exec_query("SELECT $1::integer", "SQL", [bind], prepare: true)
+ binds = [bind_attribute(nil, 1)]
+ @connection.exec_query("SELECT $1::integer", "SQL", binds, prepare: true)
name = @subscriber.payloads.last[:statement_name]
assert name
res = @connection.exec_query("EXPLAIN (FORMAT JSON) EXECUTE #{name}(1)")
diff --git a/activerecord/test/cases/adapters/postgresql/explain_test.rb b/activerecord/test/cases/adapters/postgresql/explain_test.rb
index 7493bce4fb..d79fbccf47 100644
--- a/activerecord/test/cases/adapters/postgresql/explain_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/explain_test.rb
@@ -7,14 +7,14 @@ class PostgreSQLExplainTest < ActiveRecord::PostgreSQLTestCase
def test_explain_for_one_query
explain = Developer.where(id: 1).explain
- assert_match %r(EXPLAIN for: SELECT "developers".* FROM "developers" WHERE "developers"."id" = (?:\$1 \[\["id", 1\]\]|1)), explain
+ assert_match %r(EXPLAIN for: SELECT "developers"\.\* FROM "developers" WHERE "developers"\."id" = (?:\$1 \[\["id", 1\]\]|1)), explain
assert_match %(QUERY PLAN), explain
end
def test_explain_with_eager_loading
explain = Developer.where(id: 1).includes(:audit_logs).explain
assert_match %(QUERY PLAN), explain
- assert_match %r(EXPLAIN for: SELECT "developers".* FROM "developers" WHERE "developers"."id" = (?:\$1 \[\["id", 1\]\]|1)), explain
+ assert_match %r(EXPLAIN for: SELECT "developers"\.\* FROM "developers" WHERE "developers"\."id" = (?:\$1 \[\["id", 1\]\]|1)), explain
assert_match %(EXPLAIN for: SELECT "audit_logs".* FROM "audit_logs" WHERE "audit_logs"."developer_id" = 1), explain
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
index 003e6e62e7..bfc763e1ef 100644
--- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
@@ -202,8 +202,8 @@ module ActiveRecord
string = @connection.quote("foo")
@connection.exec_query("INSERT INTO ex (id, data) VALUES (1, #{string})")
- bind = Relation::QueryAttribute.new("id", 1, Type::Value.new)
- result = @connection.exec_query("SELECT id, data FROM ex WHERE id = $1", nil, [bind])
+ binds = [bind_attribute("id", 1)]
+ result = @connection.exec_query("SELECT id, data FROM ex WHERE id = $1", nil, binds)
assert_equal 1, result.rows.length
assert_equal 2, result.columns.length
@@ -217,8 +217,8 @@ module ActiveRecord
string = @connection.quote("foo")
@connection.exec_query("INSERT INTO ex (id, data) VALUES (1, #{string})")
- bind = Relation::QueryAttribute.new("id", "1-fuu", Type::Integer.new)
- result = @connection.exec_query("SELECT id, data FROM ex WHERE id = $1", nil, [bind])
+ binds = [bind_attribute("id", "1-fuu", Type::Integer.new)]
+ result = @connection.exec_query("SELECT id, data FROM ex WHERE id = $1", nil, binds)
assert_equal 1, result.rows.length
assert_equal 2, result.columns.length
@@ -346,7 +346,7 @@ module ActiveRecord
@connection.select_all "SELECT NULL::anyelement"
@connection.select_all "SELECT NULL::anyelement"
}
- assert_match(/\Aunknown OID \d+: failed to recognize type of 'anyelement'. It will be treated as String.\n\z/, warning)
+ assert_match(/\Aunknown OID \d+: failed to recognize type of 'anyelement'\. It will be treated as String\.\n\z/, warning)
ensure
reset_connection
end
diff --git a/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb b/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb
index c5c540cebc..0ff04bfa27 100644
--- a/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb
@@ -1,150 +1,111 @@
require "cases/helper"
require "support/connection_helper"
-if ActiveRecord::Base.connection.respond_to?(:supports_alter_constraint?) &&
- ActiveRecord::Base.connection.supports_alter_constraint?
- class PostgreSQLReferentialIntegrityWithAlterConstraintTest < ActiveRecord::PostgreSQLTestCase
- self.use_transactional_tests = false
+class PostgreSQLReferentialIntegrityTest < ActiveRecord::PostgreSQLTestCase
+ self.use_transactional_tests = false
- include ConnectionHelper
+ include ConnectionHelper
- IS_REFERENTIAL_INTEGRITY_SQL = lambda do |sql|
- sql.match(/SET CONSTRAINTS ALL DEFERRED/)
- end
+ IS_REFERENTIAL_INTEGRITY_SQL = lambda do |sql|
+ sql.match(/DISABLE TRIGGER ALL/) || sql.match(/ENABLE TRIGGER ALL/)
+ end
- module ProgrammerMistake
- def execute(sql)
- if IS_REFERENTIAL_INTEGRITY_SQL.call(sql)
- raise ArgumentError, "something is not right."
- else
- super
- end
+ module MissingSuperuserPrivileges
+ def execute(sql)
+ if IS_REFERENTIAL_INTEGRITY_SQL.call(sql)
+ super "BROKEN;" rescue nil # put transaction in broken state
+ raise ActiveRecord::StatementInvalid, "PG::InsufficientPrivilege"
+ else
+ super
end
end
+ end
- def setup
- @connection = ActiveRecord::Base.connection
- end
-
- def teardown
- reset_connection
- end
-
- def test_errors_bubble_up
- @connection.extend ProgrammerMistake
-
- assert_raises ArgumentError do
- @connection.disable_referential_integrity {}
+ module ProgrammerMistake
+ def execute(sql)
+ if IS_REFERENTIAL_INTEGRITY_SQL.call(sql)
+ raise ArgumentError, "something is not right."
+ else
+ super
end
end
end
-else
- class PostgreSQLReferentialIntegrityWithDisableTriggerTest < ActiveRecord::PostgreSQLTestCase
- self.use_transactional_tests = false
- include ConnectionHelper
+ def setup
+ @connection = ActiveRecord::Base.connection
+ end
- IS_REFERENTIAL_INTEGRITY_SQL = lambda do |sql|
- sql.match(/DISABLE TRIGGER ALL/) || sql.match(/ENABLE TRIGGER ALL/)
+ def teardown
+ reset_connection
+ if ActiveRecord::Base.connection.is_a?(MissingSuperuserPrivileges)
+ raise "MissingSuperuserPrivileges patch was not removed"
end
+ end
- module MissingSuperuserPrivileges
- def execute(sql)
- if IS_REFERENTIAL_INTEGRITY_SQL.call(sql)
- super "BROKEN;" rescue nil # put transaction in broken state
- raise ActiveRecord::StatementInvalid, "PG::InsufficientPrivilege"
- else
- super
- end
- end
- end
+ def test_should_reraise_invalid_foreign_key_exception_and_show_warning
+ @connection.extend MissingSuperuserPrivileges
- module ProgrammerMistake
- def execute(sql)
- if IS_REFERENTIAL_INTEGRITY_SQL.call(sql)
- raise ArgumentError, "something is not right."
- else
- super
+ warning = capture(:stderr) do
+ e = assert_raises(ActiveRecord::InvalidForeignKey) do
+ @connection.disable_referential_integrity do
+ raise ActiveRecord::InvalidForeignKey, "Should be re-raised"
end
end
+ assert_equal "Should be re-raised", e.message
end
+ assert_match (/WARNING: Rails was not able to disable referential integrity/), warning
+ assert_match (/cause: PG::InsufficientPrivilege/), warning
+ end
- def setup
- @connection = ActiveRecord::Base.connection
- end
-
- def teardown
- reset_connection
- if ActiveRecord::Base.connection.is_a?(MissingSuperuserPrivileges)
- raise "MissingSuperuserPrivileges patch was not removed"
- end
- end
-
- def test_should_reraise_invalid_foreign_key_exception_and_show_warning
- @connection.extend MissingSuperuserPrivileges
+ def test_does_not_print_warning_if_no_invalid_foreign_key_exception_was_raised
+ @connection.extend MissingSuperuserPrivileges
- warning = capture(:stderr) do
- e = assert_raises(ActiveRecord::InvalidForeignKey) do
- @connection.disable_referential_integrity do
- raise ActiveRecord::InvalidForeignKey, "Should be re-raised"
- end
+ warning = capture(:stderr) do
+ e = assert_raises(ActiveRecord::StatementInvalid) do
+ @connection.disable_referential_integrity do
+ raise ActiveRecord::StatementInvalid, "Should be re-raised"
end
- assert_equal "Should be re-raised", e.message
end
- assert_match (/WARNING: Rails was not able to disable referential integrity/), warning
- assert_match (/cause: PG::InsufficientPrivilege/), warning
+ assert_equal "Should be re-raised", e.message
end
+ assert warning.blank?, "expected no warnings but got:\n#{warning}"
+ end
- def test_does_not_print_warning_if_no_invalid_foreign_key_exception_was_raised
- @connection.extend MissingSuperuserPrivileges
+ def test_does_not_break_transactions
+ @connection.extend MissingSuperuserPrivileges
- warning = capture(:stderr) do
- e = assert_raises(ActiveRecord::StatementInvalid) do
- @connection.disable_referential_integrity do
- raise ActiveRecord::StatementInvalid, "Should be re-raised"
- end
- end
- assert_equal "Should be re-raised", e.message
+ @connection.transaction do
+ @connection.disable_referential_integrity do
+ assert_transaction_is_not_broken
end
- assert warning.blank?, "expected no warnings but got:\n#{warning}"
+ assert_transaction_is_not_broken
end
+ end
- def test_does_not_break_transactions
- @connection.extend MissingSuperuserPrivileges
+ def test_does_not_break_nested_transactions
+ @connection.extend MissingSuperuserPrivileges
- @connection.transaction do
+ @connection.transaction do
+ @connection.transaction(requires_new: true) do
@connection.disable_referential_integrity do
assert_transaction_is_not_broken
end
- assert_transaction_is_not_broken
end
+ assert_transaction_is_not_broken
end
+ end
- def test_does_not_break_nested_transactions
- @connection.extend MissingSuperuserPrivileges
+ def test_only_catch_active_record_errors_others_bubble_up
+ @connection.extend ProgrammerMistake
- @connection.transaction do
- @connection.transaction(requires_new: true) do
- @connection.disable_referential_integrity do
- assert_transaction_is_not_broken
- end
- end
- assert_transaction_is_not_broken
- end
+ assert_raises ArgumentError do
+ @connection.disable_referential_integrity {}
end
+ end
- def test_only_catch_active_record_errors_others_bubble_up
- @connection.extend ProgrammerMistake
+ private
- assert_raises ArgumentError do
- @connection.disable_referential_integrity {}
- end
+ def assert_transaction_is_not_broken
+ assert_equal 1, @connection.select_value("SELECT 1")
end
-
- private
-
- def assert_transaction_is_not_broken
- assert_equal 1, @connection.select_value("SELECT 1")
- end
- end
end
diff --git a/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb b/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb
index f6a07da85f..bf570176f4 100644
--- a/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb
@@ -68,7 +68,7 @@ class SchemaAuthorizationTest < ActiveRecord::PostgreSQLTestCase
USERS.each do |u|
@connection.clear_cache!
set_session_auth u
- assert_equal u, @connection.select_value("SELECT name FROM #{TABLE_NAME} WHERE id = $1", "SQL", [bind_param(1)])
+ assert_equal u, @connection.select_value("SELECT name FROM #{TABLE_NAME} WHERE id = $1", "SQL", [bind_attribute("id", 1)])
set_session_auth
end
end
@@ -112,8 +112,4 @@ class SchemaAuthorizationTest < ActiveRecord::PostgreSQLTestCase
def set_session_auth(auth = nil)
@connection.session_auth = auth || "default"
end
-
- def bind_param(value)
- ActiveRecord::Relation::QueryAttribute.new(nil, value, ActiveRecord::Type::Value.new)
- end
end
diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb
index 75e30e4fe9..f6b957476b 100644
--- a/activerecord/test/cases/adapters/postgresql/schema_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb
@@ -169,17 +169,17 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase
def test_raise_wrapped_exception_on_bad_prepare
assert_raises(ActiveRecord::StatementInvalid) do
- @connection.exec_query "select * from developers where id = ?", "sql", [bind_param(1)]
+ @connection.exec_query "select * from developers where id = ?", "sql", [bind_attribute("id", 1)]
end
end
if ActiveRecord::Base.connection.prepared_statements
def test_schema_change_with_prepared_stmt
altered = false
- @connection.exec_query "select * from developers where id = $1", "sql", [bind_param(1)]
+ @connection.exec_query "select * from developers where id = $1", "sql", [bind_attribute("id", 1)]
@connection.exec_query "alter table developers add column zomg int", "sql", []
altered = true
- @connection.exec_query "select * from developers where id = $1", "sql", [bind_param(1)]
+ @connection.exec_query "select * from developers where id = $1", "sql", [bind_attribute("id", 1)]
ensure
# We are not using DROP COLUMN IF EXISTS because that syntax is only
# supported by pg 9.X
@@ -467,10 +467,6 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase
assert_equal this_index_column, this_index.columns[0]
assert_equal this_index_name, this_index.name
end
-
- def bind_param(value)
- ActiveRecord::Relation::QueryAttribute.new(nil, value, ActiveRecord::Type::Value.new)
- end
end
class SchemaForeignKeyTest < ActiveRecord::PostgreSQLTestCase
diff --git a/activerecord/test/cases/adapters/sqlite3/collation_test.rb b/activerecord/test/cases/adapters/sqlite3/collation_test.rb
index 28e8f12c18..dd88ed3656 100644
--- a/activerecord/test/cases/adapters/sqlite3/collation_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/collation_test.rb
@@ -47,7 +47,7 @@ class SQLite3CollationTest < ActiveRecord::SQLite3TestCase
test "schema dump includes collation" do
output = dump_table_schema("collation_table_sqlite3")
- assert_match %r{t.string\s+"string_nocase",\s+collation: "NOCASE"$}, output
- assert_match %r{t.text\s+"text_rtrim",\s+collation: "RTRIM"$}, output
+ assert_match %r{t\.string\s+"string_nocase",\s+collation: "NOCASE"$}, output
+ assert_match %r{t\.text\s+"text_rtrim",\s+collation: "RTRIM"$}, output
end
end
diff --git a/activerecord/test/cases/adapters/sqlite3/explain_test.rb b/activerecord/test/cases/adapters/sqlite3/explain_test.rb
index 128acb79cf..29d97ae78c 100644
--- a/activerecord/test/cases/adapters/sqlite3/explain_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/explain_test.rb
@@ -7,13 +7,13 @@ class SQLite3ExplainTest < ActiveRecord::SQLite3TestCase
def test_explain_for_one_query
explain = Developer.where(id: 1).explain
- assert_match %r(EXPLAIN for: SELECT "developers".* FROM "developers" WHERE "developers"."id" = (?:\? \[\["id", 1\]\]|1)), explain
+ assert_match %r(EXPLAIN for: SELECT "developers"\.\* FROM "developers" WHERE "developers"\."id" = (?:\? \[\["id", 1\]\]|1)), explain
assert_match(/(SEARCH )?TABLE developers USING (INTEGER )?PRIMARY KEY/, explain)
end
def test_explain_with_eager_loading
explain = Developer.where(id: 1).includes(:audit_logs).explain
- assert_match %r(EXPLAIN for: SELECT "developers".* FROM "developers" WHERE "developers"."id" = (?:\? \[\["id", 1\]\]|1)), explain
+ assert_match %r(EXPLAIN for: SELECT "developers"\.\* FROM "developers" WHERE "developers"\."id" = (?:\? \[\["id", 1\]\]|1)), explain
assert_match(/(SEARCH )?TABLE developers USING (INTEGER )?PRIMARY KEY/, explain)
assert_match %(EXPLAIN for: SELECT "audit_logs".* FROM "audit_logs" WHERE "audit_logs"."developer_id" = 1), explain
assert_match(/(SCAN )?TABLE audit_logs/, explain)
diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
index 2179d1294c..9a812e325e 100644
--- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
@@ -66,11 +66,11 @@ module ActiveRecord
def test_exec_insert
with_example_table do
- vals = [Relation::QueryAttribute.new("number", 10, Type::Value.new)]
- @conn.exec_insert("insert into ex (number) VALUES (?)", "SQL", vals)
+ binds = [bind_attribute("number", 10)]
+ @conn.exec_insert("insert into ex (number) VALUES (?)", "SQL", binds)
result = @conn.exec_query(
- "select number from ex where number = ?", "SQL", vals)
+ "select number from ex where number = ?", "SQL", binds)
assert_equal 1, result.rows.length
assert_equal 10, result.rows.first.first
@@ -134,7 +134,7 @@ module ActiveRecord
with_example_table "id int, data string" do
@conn.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")')
result = @conn.exec_query(
- "SELECT id, data FROM ex WHERE id = ?", nil, [Relation::QueryAttribute.new(nil, 1, Type::Value.new)])
+ "SELECT id, data FROM ex WHERE id = ?", nil, [bind_attribute("id", 1)])
assert_equal 1, result.rows.length
assert_equal 2, result.columns.length
@@ -148,7 +148,7 @@ module ActiveRecord
@conn.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")')
result = @conn.exec_query(
- "SELECT id, data FROM ex WHERE id = ?", nil, [Relation::QueryAttribute.new("id", "1-fuu", Type::Integer.new)])
+ "SELECT id, data FROM ex WHERE id = ?", nil, [bind_attribute("id", "1-fuu", Type::Integer.new)])
assert_equal 1, result.rows.length
assert_equal 2, result.columns.length
diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb
index 5b08ba1358..c8b26232b6 100644
--- a/activerecord/test/cases/associations/belongs_to_associations_test.rb
+++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb
@@ -136,6 +136,24 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_equal david, ship.developer
end
+ def test_default_with_lambda
+ model = Class.new(ActiveRecord::Base) do
+ self.table_name = "ships"
+ def self.name; "Temp"; end
+ belongs_to :developer, default: -> { default_developer }
+
+ def default_developer
+ Developer.first
+ end
+ end
+
+ ship = model.create!
+ assert_equal developers(:david), ship.developer
+
+ ship = model.create!(developer: developers(:jamis))
+ assert_equal developers(:jamis), ship.developer
+ end
+
def test_default_scope_on_relations_is_not_cached
counter = 0
diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb
index 11f4aae5b3..36238dd088 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -1363,6 +1363,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
assert_nothing_raised do
authors(:david).essays.includes(:writer).any?
authors(:david).essays.includes(:writer).exists?
+ authors(:david).essays.includes(:owner).where("name IS NOT NULL").exists?
end
end
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index 25133fc580..6a479a344c 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -2037,12 +2037,6 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal client_association.new.attributes, client_association.send(:new).attributes
end
- def test_respond_to_private_class_methods
- client_association = companies(:first_firm).clients
- assert !client_association.respond_to?(:private_method)
- assert client_association.respond_to?(:private_method, true)
- end
-
def test_creating_using_primary_key
firm = Firm.all.merge!(order: "id").first
client = firm.clients_using_primary_key.create!(name: "test")
diff --git a/activerecord/test/cases/associations/left_outer_join_association_test.rb b/activerecord/test/cases/associations/left_outer_join_association_test.rb
index 2aca3523c4..6d3757f467 100644
--- a/activerecord/test/cases/associations/left_outer_join_association_test.rb
+++ b/activerecord/test/cases/associations/left_outer_join_association_test.rb
@@ -7,7 +7,7 @@ require "models/categorization"
require "models/person"
class LeftOuterJoinAssociationTest < ActiveRecord::TestCase
- fixtures :authors, :essays, :posts, :comments, :categorizations, :people, :author_addresses
+ fixtures :authors, :author_addresses, :essays, :posts, :comments, :categorizations, :people
def test_construct_finder_sql_applies_aliases_tables_on_association_conditions
result = Author.left_outer_joins(:thinking_posts, :welcome_posts).to_a
diff --git a/activerecord/test/cases/batches_test.rb b/activerecord/test/cases/batches_test.rb
index f7e21faf0f..fbc3fbb44f 100644
--- a/activerecord/test/cases/batches_test.rb
+++ b/activerecord/test/cases/batches_test.rb
@@ -35,12 +35,10 @@ class EachTest < ActiveRecord::TestCase
end
end
- if Enumerator.method_defined? :size
- def test_each_should_return_a_sized_enumerator
- assert_equal 11, Post.find_each(batch_size: 1).size
- assert_equal 5, Post.find_each(batch_size: 2, start: 7).size
- assert_equal 11, Post.find_each(batch_size: 10_000).size
- end
+ def test_each_should_return_a_sized_enumerator
+ assert_equal 11, Post.find_each(batch_size: 1).size
+ assert_equal 5, Post.find_each(batch_size: 2, start: 7).size
+ assert_equal 11, Post.find_each(batch_size: 10_000).size
end
def test_each_enumerator_should_execute_one_query_per_batch
@@ -145,7 +143,7 @@ class EachTest < ActiveRecord::TestCase
def test_find_in_batches_should_quote_batch_order
c = Post.connection
- assert_sql(/ORDER BY #{c.quote_table_name('posts')}.#{c.quote_column_name('id')}/) do
+ assert_sql(/ORDER BY #{c.quote_table_name('posts')}\.#{c.quote_column_name('id')}/) do
Post.find_in_batches(batch_size: 1) do |batch|
assert_kind_of Array, batch
assert_kind_of Post, batch.first
@@ -410,7 +408,7 @@ class EachTest < ActiveRecord::TestCase
def test_in_batches_should_quote_batch_order
c = Post.connection
- assert_sql(/ORDER BY #{c.quote_table_name('posts')}.#{c.quote_column_name('id')}/) do
+ assert_sql(/ORDER BY #{c.quote_table_name('posts')}\.#{c.quote_column_name('id')}/) do
Post.in_batches(of: 1) do |relation|
assert_kind_of ActiveRecord::Relation, relation
assert_kind_of Post, relation.first
@@ -515,14 +513,12 @@ class EachTest < ActiveRecord::TestCase
assert_equal 2, person.reload.author_id # incremented only once
end
- if Enumerator.method_defined? :size
- def test_find_in_batches_should_return_a_sized_enumerator
- assert_equal 11, Post.find_in_batches(batch_size: 1).size
- assert_equal 6, Post.find_in_batches(batch_size: 2).size
- assert_equal 4, Post.find_in_batches(batch_size: 2, start: 4).size
- assert_equal 4, Post.find_in_batches(batch_size: 3).size
- assert_equal 1, Post.find_in_batches(batch_size: 10_000).size
- end
+ def test_find_in_batches_should_return_a_sized_enumerator
+ assert_equal 11, Post.find_in_batches(batch_size: 1).size
+ assert_equal 6, Post.find_in_batches(batch_size: 2).size
+ assert_equal 4, Post.find_in_batches(batch_size: 2, start: 4).size
+ assert_equal 4, Post.find_in_batches(batch_size: 3).size
+ assert_equal 1, Post.find_in_batches(batch_size: 10_000).size
end
[true, false].each do |load|
diff --git a/activerecord/test/cases/bind_parameter_test.rb b/activerecord/test/cases/bind_parameter_test.rb
index 6032aa9250..5af44c27eb 100644
--- a/activerecord/test/cases/bind_parameter_test.rb
+++ b/activerecord/test/cases/bind_parameter_test.rb
@@ -3,8 +3,7 @@ require "models/topic"
require "models/author"
require "models/post"
-if ActiveRecord::Base.connection.supports_statement_cache? &&
- ActiveRecord::Base.connection.prepared_statements
+if ActiveRecord::Base.connection.prepared_statements
module ActiveRecord
class BindParameterTest < ActiveRecord::TestCase
fixtures :topics, :authors, :author_addresses, :posts
@@ -40,9 +39,8 @@ if ActiveRecord::Base.connection.supports_statement_cache? &&
end
def test_binds_are_logged
- sub = Arel::Nodes::BindParam.new
- binds = [Relation::QueryAttribute.new("id", 1, Type::Value.new)]
- sql = "select * from topics where id = #{sub.to_sql}"
+ binds = [bind_attribute("id", 1)]
+ sql = "select * from topics where id = #{bind_param.to_sql}"
@connection.exec_query(sql, "SQL", binds)
@@ -57,7 +55,7 @@ if ActiveRecord::Base.connection.supports_statement_cache? &&
end
def test_logs_binds_after_type_cast
- binds = [Relation::QueryAttribute.new("id", "10", Type::Integer.new)]
+ binds = [bind_attribute("id", "10", Type::Integer.new)]
assert_logs_binds(binds)
end
@@ -66,6 +64,10 @@ if ActiveRecord::Base.connection.supports_statement_cache? &&
assert_logs_binds(binds)
end
+ def test_deprecate_supports_statement_cache
+ assert_deprecated { ActiveRecord::Base.connection.supports_statement_cache? }
+ end
+
private
def assert_logs_binds(binds)
payload = {
diff --git a/activerecord/test/cases/collection_cache_key_test.rb b/activerecord/test/cases/collection_cache_key_test.rb
index 92620761e4..f344c77691 100644
--- a/activerecord/test/cases/collection_cache_key_test.rb
+++ b/activerecord/test/cases/collection_cache_key_test.rb
@@ -11,16 +11,16 @@ module ActiveRecord
fixtures :developers, :projects, :developers_projects, :topics, :comments, :posts
test "collection_cache_key on model" do
- assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\Z/, Developer.collection_cache_key)
+ assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\z/, Developer.collection_cache_key)
end
test "cache_key for relation" do
developers = Developer.where(salary: 100000).order(updated_at: :desc)
last_developer_timestamp = developers.first.updated_at
- assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\Z/, developers.cache_key)
+ assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\z/, developers.cache_key)
- /\Adevelopers\/query-(\h+)-(\d+)-(\d+)\Z/ =~ developers.cache_key
+ /\Adevelopers\/query-(\h+)-(\d+)-(\d+)\z/ =~ developers.cache_key
assert_equal Digest::MD5.hexdigest(developers.to_sql), $1
assert_equal developers.count.to_s, $2
@@ -31,9 +31,9 @@ module ActiveRecord
developers = Developer.where(salary: 100000).order(updated_at: :desc).limit(5)
last_developer_timestamp = developers.first.updated_at
- assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\Z/, developers.cache_key)
+ assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\z/, developers.cache_key)
- /\Adevelopers\/query-(\h+)-(\d+)-(\d+)\Z/ =~ developers.cache_key
+ /\Adevelopers\/query-(\h+)-(\d+)-(\d+)\z/ =~ developers.cache_key
assert_equal Digest::MD5.hexdigest(developers.to_sql), $1
assert_equal developers.count.to_s, $2
@@ -44,9 +44,9 @@ module ActiveRecord
developers = Developer.where(salary: 100000).order(updated_at: :desc).limit(5).load
last_developer_timestamp = developers.first.updated_at
- assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\Z/, developers.cache_key)
+ assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\z/, developers.cache_key)
- /\Adevelopers\/query-(\h+)-(\d+)-(\d+)\Z/ =~ developers.cache_key
+ /\Adevelopers\/query-(\h+)-(\d+)-(\d+)\z/ =~ developers.cache_key
assert_equal Digest::MD5.hexdigest(developers.to_sql), $1
assert_equal developers.count.to_s, $2
@@ -74,7 +74,7 @@ module ActiveRecord
test "cache_key for empty relation" do
developers = Developer.where(name: "Non Existent Developer")
- assert_match(/\Adevelopers\/query-(\h+)-0\Z/, developers.cache_key)
+ assert_match(/\Adevelopers\/query-(\h+)-0\z/, developers.cache_key)
end
test "cache_key with custom timestamp column" do
@@ -90,7 +90,7 @@ module ActiveRecord
test "collection proxy provides a cache_key" do
developers = projects(:active_record).developers
- assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\Z/, developers.cache_key)
+ assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\z/, developers.cache_key)
end
test "cache_key for loaded collection with zero size" do
@@ -98,18 +98,18 @@ module ActiveRecord
posts = Post.includes(:comments)
empty_loaded_collection = posts.first.comments
- assert_match(/\Acomments\/query-(\h+)-0\Z/, empty_loaded_collection.cache_key)
+ assert_match(/\Acomments\/query-(\h+)-0\z/, empty_loaded_collection.cache_key)
end
test "cache_key for queries with offset which return 0 rows" do
developers = Developer.offset(20)
- assert_match(/\Adevelopers\/query-(\h+)-0\Z/, developers.cache_key)
+ assert_match(/\Adevelopers\/query-(\h+)-0\z/, developers.cache_key)
end
test "cache_key with a relation having selected columns" do
developers = Developer.select(:salary)
- assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\Z/, developers.cache_key)
+ assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\z/, developers.cache_key)
end
end
end
diff --git a/activerecord/test/cases/defaults_test.rb b/activerecord/test/cases/defaults_test.rb
index a6297673c9..996d298689 100644
--- a/activerecord/test/cases/defaults_test.rb
+++ b/activerecord/test/cases/defaults_test.rb
@@ -87,9 +87,14 @@ if current_adapter?(:PostgreSQLAdapter)
test "schema dump includes default expression" do
output = dump_table_schema("defaults")
- assert_match %r/t\.date\s+"modified_date",\s+default: -> { "\('now'::text\)::date" }/, output
+ if ActiveRecord::Base.connection.postgresql_version >= 100000
+ assert_match %r/t\.date\s+"modified_date",\s+default: -> { "CURRENT_DATE" }/, output
+ assert_match %r/t\.datetime\s+"modified_time",\s+default: -> { "CURRENT_TIMESTAMP" }/, output
+ else
+ assert_match %r/t\.date\s+"modified_date",\s+default: -> { "\('now'::text\)::date" }/, output
+ assert_match %r/t\.datetime\s+"modified_time",\s+default: -> { "now\(\)" }/, output
+ end
assert_match %r/t\.date\s+"modified_date_function",\s+default: -> { "now\(\)" }/, output
- assert_match %r/t\.datetime\s+"modified_time",\s+default: -> { "now\(\)" }/, output
assert_match %r/t\.datetime\s+"modified_time_function",\s+default: -> { "now\(\)" }/, output
end
end
diff --git a/activerecord/test/cases/enum_test.rb b/activerecord/test/cases/enum_test.rb
index b7641fcf32..7f63bb2473 100644
--- a/activerecord/test/cases/enum_test.rb
+++ b/activerecord/test/cases/enum_test.rb
@@ -1,10 +1,12 @@
require "cases/helper"
+require "models/author"
require "models/book"
class EnumTest < ActiveRecord::TestCase
- fixtures :books
+ fixtures :books, :authors
setup do
+ @author = authors(:david)
@book = books(:awdr)
end
@@ -55,6 +57,7 @@ class EnumTest < ActiveRecord::TestCase
assert_not_equal @book, Book.where(status: :written).first
assert_equal @book, Book.where(status: [:published]).first
assert_not_equal @book, Book.where(status: [:written]).first
+ assert_not @author.unpublished_books.include?(@book)
assert_not_equal @book, Book.where.not(status: :published).first
assert_equal @book, Book.where.not(status: :written).first
end
diff --git a/activerecord/test/cases/explain_test.rb b/activerecord/test/cases/explain_test.rb
index 86fe90ae51..4f6bd9327c 100644
--- a/activerecord/test/cases/explain_test.rb
+++ b/activerecord/test/cases/explain_test.rb
@@ -47,7 +47,7 @@ if ActiveRecord::Base.connection.supports_explain?
def test_exec_explain_with_binds
sqls = %w(foo bar)
- binds = [[bind_param("wadus", 1)], [bind_param("chaflan", 2)]]
+ binds = [[bind_attribute("wadus", 1)], [bind_attribute("chaflan", 2)]]
queries = sqls.zip(binds)
stub_explain_for_query_plans(["query plan foo\n", "query plan bar\n"]) do
@@ -79,9 +79,5 @@ if ActiveRecord::Base.connection.supports_explain?
yield
end
end
-
- def bind_param(name, value)
- ActiveRecord::Relation::QueryAttribute.new(name, value, ActiveRecord::Type::Value.new)
- end
end
end
diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb
index e570e9ac1d..d70572d6eb 100644
--- a/activerecord/test/cases/inheritance_test.rb
+++ b/activerecord/test/cases/inheritance_test.rb
@@ -417,7 +417,7 @@ class InheritanceTest < ActiveRecord::TestCase
def test_eager_load_belongs_to_primary_key_quoting
con = Account.connection
- assert_sql(/#{con.quote_table_name('companies')}.#{con.quote_column_name('id')} = 1/) do
+ assert_sql(/#{con.quote_table_name('companies')}\.#{con.quote_column_name('id')} = 1/) do
Account.all.merge!(includes: :firm).find(1)
end
end
diff --git a/activerecord/test/cases/log_subscriber_test.rb b/activerecord/test/cases/log_subscriber_test.rb
index 90ad970e16..b80257962c 100644
--- a/activerecord/test/cases/log_subscriber_test.rb
+++ b/activerecord/test/cases/log_subscriber_test.rb
@@ -21,6 +21,7 @@ class LogSubscriberTest < ActiveRecord::TestCase
TRANSACTION: REGEXP_CYAN,
OTHER: REGEXP_MAGENTA
}
+ Event = Struct.new(:duration, :payload)
class TestDebugLogSubscriber < ActiveRecord::LogSubscriber
attr_reader :debugs
@@ -55,25 +56,22 @@ class LogSubscriberTest < ActiveRecord::TestCase
end
def test_schema_statements_are_ignored
- event = Struct.new(:duration, :payload)
-
logger = TestDebugLogSubscriber.new
assert_equal 0, logger.debugs.length
- logger.sql(event.new(0, sql: "hi mom!"))
+ logger.sql(Event.new(0.9, sql: "hi mom!"))
assert_equal 1, logger.debugs.length
- logger.sql(event.new(0, sql: "hi mom!", name: "foo"))
+ logger.sql(Event.new(0.9, sql: "hi mom!", name: "foo"))
assert_equal 2, logger.debugs.length
- logger.sql(event.new(0, sql: "hi mom!", name: "SCHEMA"))
+ logger.sql(Event.new(0.9, sql: "hi mom!", name: "SCHEMA"))
assert_equal 2, logger.debugs.length
end
def test_sql_statements_are_not_squeezed
- event = Struct.new(:duration, :payload)
logger = TestDebugLogSubscriber.new
- logger.sql(event.new(0, sql: "ruby rails"))
+ logger.sql(Event.new(0.9, sql: "ruby rails"))
assert_match(/ruby rails/, logger.debugs.first)
end
@@ -86,56 +84,51 @@ class LogSubscriberTest < ActiveRecord::TestCase
end
def test_basic_query_logging_coloration
- event = Struct.new(:duration, :payload)
logger = TestDebugLogSubscriber.new
logger.colorize_logging = true
SQL_COLORINGS.each do |verb, color_regex|
- logger.sql(event.new(0, sql: verb.to_s))
+ logger.sql(Event.new(0.9, sql: verb.to_s))
assert_match(/#{REGEXP_BOLD}#{color_regex}#{verb}#{REGEXP_CLEAR}/i, logger.debugs.last)
end
end
def test_basic_payload_name_logging_coloration_generic_sql
- event = Struct.new(:duration, :payload)
logger = TestDebugLogSubscriber.new
logger.colorize_logging = true
SQL_COLORINGS.each do |verb, _|
- logger.sql(event.new(0, sql: verb.to_s))
- assert_match(/#{REGEXP_BOLD}#{REGEXP_MAGENTA} \(0.0ms\)#{REGEXP_CLEAR}/i, logger.debugs.last)
+ logger.sql(Event.new(0.9, sql: verb.to_s))
+ assert_match(/#{REGEXP_BOLD}#{REGEXP_MAGENTA} \(0\.9ms\)#{REGEXP_CLEAR}/i, logger.debugs.last)
- logger.sql(event.new(0, sql: verb.to_s, name: "SQL"))
- assert_match(/#{REGEXP_BOLD}#{REGEXP_MAGENTA}SQL \(0.0ms\)#{REGEXP_CLEAR}/i, logger.debugs.last)
+ logger.sql(Event.new(0.9, sql: verb.to_s, name: "SQL"))
+ assert_match(/#{REGEXP_BOLD}#{REGEXP_MAGENTA}SQL \(0\.9ms\)#{REGEXP_CLEAR}/i, logger.debugs.last)
end
end
def test_basic_payload_name_logging_coloration_named_sql
- event = Struct.new(:duration, :payload)
logger = TestDebugLogSubscriber.new
logger.colorize_logging = true
SQL_COLORINGS.each do |verb, _|
- logger.sql(event.new(0, sql: verb.to_s, name: "Model Load"))
- assert_match(/#{REGEXP_BOLD}#{REGEXP_CYAN}Model Load \(0.0ms\)#{REGEXP_CLEAR}/i, logger.debugs.last)
+ logger.sql(Event.new(0.9, sql: verb.to_s, name: "Model Load"))
+ assert_match(/#{REGEXP_BOLD}#{REGEXP_CYAN}Model Load \(0\.9ms\)#{REGEXP_CLEAR}/i, logger.debugs.last)
- logger.sql(event.new(0, sql: verb.to_s, name: "Model Exists"))
- assert_match(/#{REGEXP_BOLD}#{REGEXP_CYAN}Model Exists \(0.0ms\)#{REGEXP_CLEAR}/i, logger.debugs.last)
+ logger.sql(Event.new(0.9, sql: verb.to_s, name: "Model Exists"))
+ assert_match(/#{REGEXP_BOLD}#{REGEXP_CYAN}Model Exists \(0\.9ms\)#{REGEXP_CLEAR}/i, logger.debugs.last)
- logger.sql(event.new(0, sql: verb.to_s, name: "ANY SPECIFIC NAME"))
- assert_match(/#{REGEXP_BOLD}#{REGEXP_CYAN}ANY SPECIFIC NAME \(0.0ms\)#{REGEXP_CLEAR}/i, logger.debugs.last)
+ logger.sql(Event.new(0.9, sql: verb.to_s, name: "ANY SPECIFIC NAME"))
+ assert_match(/#{REGEXP_BOLD}#{REGEXP_CYAN}ANY SPECIFIC NAME \(0\.9ms\)#{REGEXP_CLEAR}/i, logger.debugs.last)
end
end
def test_query_logging_coloration_with_nested_select
- event = Struct.new(:duration, :payload)
logger = TestDebugLogSubscriber.new
logger.colorize_logging = true
SQL_COLORINGS.slice(:SELECT, :INSERT, :UPDATE, :DELETE).each do |verb, color_regex|
- logger.sql(event.new(0, sql: "#{verb} WHERE ID IN SELECT"))
- assert_match(/#{REGEXP_BOLD}#{REGEXP_MAGENTA} \(0.0ms\)#{REGEXP_CLEAR} #{REGEXP_BOLD}#{color_regex}#{verb} WHERE ID IN SELECT#{REGEXP_CLEAR}/i, logger.debugs.last)
+ logger.sql(Event.new(0.9, sql: "#{verb} WHERE ID IN SELECT"))
+ assert_match(/#{REGEXP_BOLD}#{REGEXP_MAGENTA} \(0\.9ms\)#{REGEXP_CLEAR} #{REGEXP_BOLD}#{color_regex}#{verb} WHERE ID IN SELECT#{REGEXP_CLEAR}/i, logger.debugs.last)
end
end
def test_query_logging_coloration_with_multi_line_nested_select
- event = Struct.new(:duration, :payload)
logger = TestDebugLogSubscriber.new
logger.colorize_logging = true
SQL_COLORINGS.slice(:SELECT, :INSERT, :UPDATE, :DELETE).each do |verb, color_regex|
@@ -145,13 +138,12 @@ class LogSubscriberTest < ActiveRecord::TestCase
SELECT ID FROM THINGS
)
EOS
- logger.sql(event.new(0, sql: sql))
- assert_match(/#{REGEXP_BOLD}#{REGEXP_MAGENTA} \(0.0ms\)#{REGEXP_CLEAR} #{REGEXP_BOLD}#{color_regex}.*#{verb}.*#{REGEXP_CLEAR}/mi, logger.debugs.last)
+ logger.sql(Event.new(0.9, sql: sql))
+ assert_match(/#{REGEXP_BOLD}#{REGEXP_MAGENTA} \(0\.9ms\)#{REGEXP_CLEAR} #{REGEXP_BOLD}#{color_regex}.*#{verb}.*#{REGEXP_CLEAR}/mi, logger.debugs.last)
end
end
def test_query_logging_coloration_with_lock
- event = Struct.new(:duration, :payload)
logger = TestDebugLogSubscriber.new
logger.colorize_logging = true
sql = <<-EOS
@@ -159,14 +151,14 @@ class LogSubscriberTest < ActiveRecord::TestCase
(SELECT * FROM mytable FOR UPDATE) ss
WHERE col1 = 5;
EOS
- logger.sql(event.new(0, sql: sql))
- assert_match(/#{REGEXP_BOLD}#{REGEXP_MAGENTA} \(0.0ms\)#{REGEXP_CLEAR} #{REGEXP_BOLD}#{SQL_COLORINGS[:LOCK]}.*FOR UPDATE.*#{REGEXP_CLEAR}/mi, logger.debugs.last)
+ logger.sql(Event.new(0.9, sql: sql))
+ assert_match(/#{REGEXP_BOLD}#{REGEXP_MAGENTA} \(0\.9ms\)#{REGEXP_CLEAR} #{REGEXP_BOLD}#{SQL_COLORINGS[:LOCK]}.*FOR UPDATE.*#{REGEXP_CLEAR}/mi, logger.debugs.last)
sql = <<-EOS
LOCK TABLE films IN SHARE MODE;
EOS
- logger.sql(event.new(0, sql: sql))
- assert_match(/#{REGEXP_BOLD}#{REGEXP_MAGENTA} \(0.0ms\)#{REGEXP_CLEAR} #{REGEXP_BOLD}#{SQL_COLORINGS[:LOCK]}.*LOCK TABLE.*#{REGEXP_CLEAR}/mi, logger.debugs.last)
+ logger.sql(Event.new(0.9, sql: sql))
+ assert_match(/#{REGEXP_BOLD}#{REGEXP_MAGENTA} \(0\.9ms\)#{REGEXP_CLEAR} #{REGEXP_BOLD}#{SQL_COLORINGS[:LOCK]}.*LOCK TABLE.*#{REGEXP_CLEAR}/mi, logger.debugs.last)
end
def test_exists_query_logging
diff --git a/activerecord/test/cases/migrator_test.rb b/activerecord/test/cases/migrator_test.rb
index aadbc375af..2e4b454a86 100644
--- a/activerecord/test/cases/migrator_test.rb
+++ b/activerecord/test/cases/migrator_test.rb
@@ -299,6 +299,7 @@ class MigratorTest < ActiveRecord::TestCase
def test_migrator_verbosity
_, migrations = sensors(3)
+ ActiveRecord::Migration.verbose = true
ActiveRecord::Migrator.new(:up, migrations, 1).migrate
assert_not_equal 0, ActiveRecord::Migration.message_count
@@ -311,7 +312,6 @@ class MigratorTest < ActiveRecord::TestCase
def test_migrator_verbosity_off
_, migrations = sensors(3)
- ActiveRecord::Migration.message_count = 0
ActiveRecord::Migration.verbose = false
ActiveRecord::Migrator.new(:up, migrations, 1).migrate
assert_equal 0, ActiveRecord::Migration.message_count
diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb
index 5b7e2fd008..5895c51714 100644
--- a/activerecord/test/cases/persistence_test.rb
+++ b/activerecord/test/cases/persistence_test.rb
@@ -49,7 +49,7 @@ class PersistenceTest < ActiveRecord::TestCase
assert !test_update_with_order_succeeds.call("id ASC") # test that this wasn't a fluke and using an incorrect order results in an exception
else
# test that we're failing because the current Arel's engine doesn't support UPDATE ORDER BY queries is using subselects instead
- assert_sql(/\AUPDATE .+ \(SELECT .* ORDER BY id DESC\)\Z/i) do
+ assert_sql(/\AUPDATE .+ \(SELECT .* ORDER BY id DESC\)\z/i) do
test_update_with_order_succeeds.call("id DESC")
end
end
diff --git a/activerecord/test/cases/quoting_test.rb b/activerecord/test/cases/quoting_test.rb
index f260d043e4..0819776fbf 100644
--- a/activerecord/test/cases/quoting_test.rb
+++ b/activerecord/test/cases/quoting_test.rb
@@ -81,8 +81,21 @@ module ActiveRecord
end
end
+ class QuotedOne
+ def quoted_id
+ 1
+ end
+ end
+ class SubQuotedOne < QuotedOne
+ end
def test_quote_with_quoted_id
- assert_deprecated { assert_equal 1, @quoter.quote(Struct.new(:quoted_id).new(1)) }
+ assert_deprecated(/defined on \S+::QuotedOne at .*quoting_test\.rb:[0-9]/) do
+ assert_equal 1, @quoter.quote(QuotedOne.new)
+ end
+
+ assert_deprecated(/defined on \S+::SubQuotedOne\(\S+::QuotedOne\) at .*quoting_test\.rb:[0-9]/) do
+ assert_equal 1, @quoter.quote(SubQuotedOne.new)
+ end
end
def test_quote_nil
diff --git a/activerecord/test/cases/relation/delegation_test.rb b/activerecord/test/cases/relation/delegation_test.rb
index 8cb7b82015..cb6e4d76d3 100644
--- a/activerecord/test/cases/relation/delegation_test.rb
+++ b/activerecord/test/cases/relation/delegation_test.rb
@@ -3,29 +3,7 @@ require "models/post"
require "models/comment"
module ActiveRecord
- class DelegationTest < ActiveRecord::TestCase
- fixtures :posts
-
- def call_method(target, method)
- method_arity = target.to_a.method(method).arity
-
- if method_arity.zero?
- target.public_send(method)
- elsif method_arity < 0
- if method == :shuffle!
- target.public_send(method)
- else
- target.public_send(method, 1)
- end
- elsif method_arity == 1
- target.public_send(method, 1)
- else
- raise NotImplementedError
- end
- end
- end
-
- module DelegationWhitelistBlacklistTests
+ module DelegationWhitelistTests
ARRAY_DELEGATES = [
:+, :-, :|, :&, :[], :shuffle,
:all?, :collect, :compact, :detect, :each, :each_cons, :each_with_index,
@@ -43,16 +21,18 @@ module ActiveRecord
end
end
- class DelegationAssociationTest < DelegationTest
- include DelegationWhitelistBlacklistTests
+ class DelegationAssociationTest < ActiveRecord::TestCase
+ include DelegationWhitelistTests
+
+ fixtures :posts
def target
Post.first.comments
end
end
- class DelegationRelationTest < DelegationTest
- include DelegationWhitelistBlacklistTests
+ class DelegationRelationTest < ActiveRecord::TestCase
+ include DelegationWhitelistTests
fixtures :comments
diff --git a/activerecord/test/cases/relation/merging_test.rb b/activerecord/test/cases/relation/merging_test.rb
index 9e95149ede..64866eaf2d 100644
--- a/activerecord/test/cases/relation/merging_test.rb
+++ b/activerecord/test/cases/relation/merging_test.rb
@@ -21,7 +21,7 @@ class RelationMergingTest < ActiveRecord::TestCase
def test_relation_to_sql
post = Post.first
sql = post.comments.to_sql
- assert_match(/.?post_id.? = #{post.id}\Z/i, sql)
+ assert_match(/.?post_id.? = #{post.id}\z/i, sql)
end
def test_relation_merging_with_arel_equalities_keeps_last_equality
diff --git a/activerecord/test/cases/relation/where_chain_test.rb b/activerecord/test/cases/relation/where_chain_test.rb
index a96d1ae5b5..86e150ed79 100644
--- a/activerecord/test/cases/relation/where_chain_test.rb
+++ b/activerecord/test/cases/relation/where_chain_test.rb
@@ -25,7 +25,7 @@ module ActiveRecord
end
def test_association_not_eq
- expected = Arel::Nodes::Grouping.new(Comment.arel_table[@name].not_eq(Arel::Nodes::BindParam.new))
+ expected = Arel::Nodes::Grouping.new(Comment.arel_table[@name].not_eq(bind_param))
relation = Post.joins(:comments).where.not(comments: { title: "hello" })
assert_equal(expected.to_sql, relation.where_clause.ast.to_sql)
end
diff --git a/activerecord/test/cases/relation/where_clause_test.rb b/activerecord/test/cases/relation/where_clause_test.rb
index d8e4c304f0..f8eb0dee91 100644
--- a/activerecord/test/cases/relation/where_clause_test.rb
+++ b/activerecord/test/cases/relation/where_clause_test.rb
@@ -47,15 +47,15 @@ class ActiveRecord::Relation
test "merge removes bind parameters matching overlapping equality clauses" do
a = WhereClause.new(
[table["id"].eq(bind_param), table["name"].eq(bind_param)],
- [attribute("id", 1), attribute("name", "Sean")],
+ [bind_attribute("id", 1), bind_attribute("name", "Sean")],
)
b = WhereClause.new(
[table["name"].eq(bind_param)],
- [attribute("name", "Jim")]
+ [bind_attribute("name", "Jim")]
)
expected = WhereClause.new(
[table["id"].eq(bind_param), table["name"].eq(bind_param)],
- [attribute("id", 1), attribute("name", "Jim")],
+ [bind_attribute("id", 1), bind_attribute("name", "Jim")],
)
assert_equal expected, a.merge(b)
@@ -103,10 +103,10 @@ class ActiveRecord::Relation
table["name"].eq(bind_param),
table["age"].gteq(bind_param),
], [
- attribute("name", "Sean"),
- attribute("age", 30),
+ bind_attribute("name", "Sean"),
+ bind_attribute("age", 30),
])
- expected = WhereClause.new([table["age"].gteq(bind_param)], [attribute("age", 30)])
+ expected = WhereClause.new([table["age"].gteq(bind_param)], [bind_attribute("age", 30)])
assert_equal expected, where_clause.except("id", "name")
end
@@ -146,8 +146,8 @@ class ActiveRecord::Relation
end
test "or joins the two clauses using OR" do
- where_clause = WhereClause.new([table["id"].eq(bind_param)], [attribute("id", 1)])
- other_clause = WhereClause.new([table["name"].eq(bind_param)], [attribute("name", "Sean")])
+ where_clause = WhereClause.new([table["id"].eq(bind_param)], [bind_attribute("id", 1)])
+ other_clause = WhereClause.new([table["name"].eq(bind_param)], [bind_attribute("name", "Sean")])
expected_ast =
Arel::Nodes::Grouping.new(
Arel::Nodes::Or.new(table["id"].eq(bind_param), table["name"].eq(bind_param))
@@ -159,7 +159,7 @@ class ActiveRecord::Relation
end
test "or returns an empty where clause when either side is empty" do
- where_clause = WhereClause.new([table["id"].eq(bind_param)], [attribute("id", 1)])
+ where_clause = WhereClause.new([table["id"].eq(bind_param)], [bind_attribute("id", 1)])
assert_equal WhereClause.empty, where_clause.or(WhereClause.empty)
assert_equal WhereClause.empty, WhereClause.empty.or(where_clause)
@@ -170,13 +170,5 @@ class ActiveRecord::Relation
def table
Arel::Table.new("table")
end
-
- def bind_param
- Arel::Nodes::BindParam.new
- end
-
- def attribute(name, value)
- ActiveRecord::Attribute.with_cast_value(name, value, ActiveRecord::Type::Value.new)
- end
end
end
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index fcf68b0f2a..81173945a3 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -594,7 +594,7 @@ class RelationTest < ActiveRecord::TestCase
end
end
- def test_respond_to_delegates_to_relation
+ def test_respond_to_delegates_to_arel
relation = Topic.all
fake_arel = Struct.new(:responds) {
def respond_to?(method, access = false)
@@ -607,10 +607,6 @@ class RelationTest < ActiveRecord::TestCase
relation.respond_to?(:matching_attributes)
assert_equal [:matching_attributes, false], fake_arel.responds.first
-
- fake_arel.responds = []
- relation.respond_to?(:matching_attributes, true)
- assert_equal [:matching_attributes, true], fake_arel.responds.first
end
def test_respond_to_dynamic_finders
@@ -1985,24 +1981,28 @@ class RelationTest < ActiveRecord::TestCase
end
def test_unscope_removes_binds
- left = Post.where(id: Arel::Nodes::BindParam.new)
- column = Post.columns_hash["id"]
- left.bind_values += [[column, 20]]
+ left = Post.where(id: 20)
+
+ binds = [bind_attribute("id", 20, Post.type_for_attribute("id"))]
+ assert_equal binds, left.bound_attributes
relation = left.unscope(where: :id)
- assert_equal [], relation.bind_values
+ assert_equal [], relation.bound_attributes
end
- def test_merging_removes_rhs_bind_parameters
+ def test_merging_removes_rhs_binds
left = Post.where(id: 20)
right = Post.where(id: [1, 2, 3, 4])
+ binds = [bind_attribute("id", 20, Post.type_for_attribute("id"))]
+ assert_equal binds, left.bound_attributes
+
merged = left.merge(right)
- assert_equal [], merged.bind_values
+ assert_equal [], merged.bound_attributes
end
- def test_merging_keeps_lhs_bind_parameters
- binds = [ActiveRecord::Relation::QueryAttribute.new("id", 20, Post.type_for_attribute("id"))]
+ def test_merging_keeps_lhs_binds
+ binds = [bind_attribute("id", 20, Post.type_for_attribute("id"))]
right = Post.where(id: 20)
left = Post.where(id: 10)
@@ -2011,15 +2011,6 @@ class RelationTest < ActiveRecord::TestCase
assert_equal binds, merged.bound_attributes
end
- def test_merging_reorders_bind_params
- post = Post.first
- right = Post.where(id: post.id)
- left = Post.where(title: post.title)
-
- merged = left.merge(right)
- assert_equal post, merged.first
- end
-
def test_relation_join_method
assert_equal "Thank you for the welcome,Thank you again for the welcome", Post.first.comments.join(",")
end
diff --git a/activerecord/test/cases/result_test.rb b/activerecord/test/cases/result_test.rb
index 949086fda0..1a0b7c6ca7 100644
--- a/activerecord/test/cases/result_test.rb
+++ b/activerecord/test/cases/result_test.rb
@@ -45,10 +45,8 @@ module ActiveRecord
end
end
- if Enumerator.method_defined? :size
- test "each without block returns a sized enumerator" do
- assert_equal 3, result.each.size
- end
+ test "each without block returns a sized enumerator" do
+ assert_equal 3, result.each.size
end
test "cast_values returns rows after type casting" do
diff --git a/activerecord/test/cases/tasks/database_tasks_test.rb b/activerecord/test/cases/tasks/database_tasks_test.rb
index baa41a3a47..c47c97e9d9 100644
--- a/activerecord/test/cases/tasks/database_tasks_test.rb
+++ b/activerecord/test/cases/tasks/database_tasks_test.rb
@@ -343,8 +343,23 @@ module ActiveRecord
ENV["VERBOSE"] = "false"
ENV["VERSION"] = "4"
-
ActiveRecord::Migrator.expects(:migrate).with("custom/path", 4)
+ ActiveRecord::Migration.expects(:verbose=).with(false)
+ ActiveRecord::Migration.expects(:verbose=).with(ActiveRecord::Migration.verbose)
+ ActiveRecord::Tasks::DatabaseTasks.migrate
+
+ ENV.delete("VERBOSE")
+ ENV.delete("VERSION")
+ ActiveRecord::Migrator.expects(:migrate).with("custom/path", nil)
+ ActiveRecord::Migration.expects(:verbose=).with(true)
+ ActiveRecord::Migration.expects(:verbose=).with(ActiveRecord::Migration.verbose)
+ ActiveRecord::Tasks::DatabaseTasks.migrate
+
+ ENV["VERBOSE"] = "yes"
+ ENV["VERSION"] = "unknown"
+ ActiveRecord::Migrator.expects(:migrate).with("custom/path", 0)
+ ActiveRecord::Migration.expects(:verbose=).with(true)
+ ActiveRecord::Migration.expects(:verbose=).with(ActiveRecord::Migration.verbose)
ActiveRecord::Tasks::DatabaseTasks.migrate
ensure
ENV["VERBOSE"], ENV["VERSION"] = verbose, version
@@ -353,7 +368,8 @@ module ActiveRecord
def test_migrate_raise_error_on_empty_version
version = ENV["VERSION"]
ENV["VERSION"] = ""
- assert_raise(RuntimeError, "Empty VERSION provided") { ActiveRecord::Tasks::DatabaseTasks.migrate }
+ e = assert_raise(RuntimeError) { ActiveRecord::Tasks::DatabaseTasks.migrate }
+ assert_equal "Empty VERSION provided", e.message
ensure
ENV["VERSION"] = version
end
diff --git a/activerecord/test/cases/tasks/mysql_rake_test.rb b/activerecord/test/cases/tasks/mysql_rake_test.rb
index b85d303a91..33da3d11fc 100644
--- a/activerecord/test/cases/tasks/mysql_rake_test.rb
+++ b/activerecord/test/cases/tasks/mysql_rake_test.rb
@@ -294,6 +294,13 @@ if current_adapter?(:Mysql2Adapter)
ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, filename)
end
+ def test_structure_dump
+ filename = "awesome-file.sql"
+ Kernel.expects(:system).with("mysqldump", "--result-file", filename, "--no-data", "--routines", "--skip-comments", "test-db").returns(true)
+
+ ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, filename)
+ end
+
def test_structure_dump_with_extra_flags
filename = "awesome-file.sql"
expected_command = ["mysqldump", "--result-file", filename, "--no-data", "--routines", "--skip-comments", "--noop", "test-db"]
@@ -305,6 +312,15 @@ if current_adapter?(:Mysql2Adapter)
end
end
+ def test_structure_dump_with_ignore_tables
+ filename = "awesome-file.sql"
+ ActiveRecord::SchemaDumper.expects(:ignore_tables).returns(["foo", "bar"])
+
+ Kernel.expects(:system).with("mysqldump", "--result-file", filename, "--no-data", "--routines", "--skip-comments", "--ignore-table=test-db.foo", "--ignore-table=test-db.bar", "test-db").returns(true)
+
+ ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, filename)
+ end
+
def test_warn_when_external_structure_dump_command_execution_fails
filename = "awesome-file.sql"
Kernel.expects(:system)
diff --git a/activerecord/test/cases/tasks/postgresql_rake_test.rb b/activerecord/test/cases/tasks/postgresql_rake_test.rb
index 512388af6b..a2e968aedf 100644
--- a/activerecord/test/cases/tasks/postgresql_rake_test.rb
+++ b/activerecord/test/cases/tasks/postgresql_rake_test.rb
@@ -259,6 +259,14 @@ if current_adapter?(:PostgreSQLAdapter)
end
end
+ def test_structure_dump_with_ignore_tables
+ ActiveRecord::SchemaDumper.expects(:ignore_tables).returns(["foo", "bar"])
+
+ Kernel.expects(:system).with("pg_dump", "-s", "-x", "-O", "-f", @filename, "-T", "foo", "-T", "bar", "my-app-db").returns(true)
+
+ ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename)
+ end
+
def test_structure_dump_with_schema_search_path
@configuration["schema_search_path"] = "foo,bar"
diff --git a/activerecord/test/cases/tasks/sqlite_rake_test.rb b/activerecord/test/cases/tasks/sqlite_rake_test.rb
index 0d917f3f6c..ccb3834fee 100644
--- a/activerecord/test/cases/tasks/sqlite_rake_test.rb
+++ b/activerecord/test/cases/tasks/sqlite_rake_test.rb
@@ -180,6 +180,9 @@ if current_adapter?(:SQLite3Adapter)
"adapter" => "sqlite3",
"database" => @database
}
+
+ `sqlite3 #{@database} 'CREATE TABLE bar(id INTEGER)'`
+ `sqlite3 #{@database} 'CREATE TABLE foo(id INTEGER)'`
end
def test_structure_dump
@@ -189,6 +192,23 @@ if current_adapter?(:SQLite3Adapter)
ActiveRecord::Tasks::DatabaseTasks.structure_dump @configuration, filename, "/rails/root"
assert File.exist?(dbfile)
assert File.exist?(filename)
+ assert_match(/CREATE TABLE foo/, File.read(filename))
+ assert_match(/CREATE TABLE bar/, File.read(filename))
+ ensure
+ FileUtils.rm_f(filename)
+ FileUtils.rm_f(dbfile)
+ end
+
+ def test_structure_dump_with_ignore_tables
+ dbfile = @database
+ filename = "awesome-file.sql"
+ ActiveRecord::SchemaDumper.expects(:ignore_tables).returns(["foo"])
+
+ ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, filename, "/rails/root")
+ assert File.exist?(dbfile)
+ assert File.exist?(filename)
+ assert_match(/bar/, File.read(filename))
+ assert_no_match(/foo/, File.read(filename))
ensure
FileUtils.rm_f(filename)
FileUtils.rm_f(dbfile)
diff --git a/activerecord/test/cases/test_case.rb b/activerecord/test/cases/test_case.rb
index 31b11c19f7..9f594fef85 100644
--- a/activerecord/test/cases/test_case.rb
+++ b/activerecord/test/cases/test_case.rb
@@ -75,6 +75,14 @@ module ActiveRecord
model.reset_column_information
model.column_names.include?(column_name.to_s)
end
+
+ def bind_param
+ Arel::Nodes::BindParam.new
+ end
+
+ def bind_attribute(name, value, type = ActiveRecord::Type.default_value)
+ ActiveRecord::Relation::QueryAttribute.new(name, value, type)
+ end
end
class PostgreSQLTestCase < TestCase
diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb
index fab613afd1..2d9cba77e0 100644
--- a/activerecord/test/models/author.rb
+++ b/activerecord/test/models/author.rb
@@ -106,6 +106,7 @@ class Author < ActiveRecord::Base
has_many :tags_with_primary_key, through: :posts
has_many :books
+ has_many :unpublished_books, -> { where(status: [:proposed, :written]) }, class_name: "Book"
has_many :subscriptions, through: :books
has_many :subscribers, -> { order("subscribers.nick") }, through: :subscriptions
has_many :distinct_subscribers, -> { select("DISTINCT subscribers.*").order("subscribers.nick") }, through: :subscriptions, source: :subscriber
diff --git a/activerecord/test/models/book.rb b/activerecord/test/models/book.rb
index 17bf3fbcb4..5f8a8a96dd 100644
--- a/activerecord/test/models/book.rb
+++ b/activerecord/test/models/book.rb
@@ -1,5 +1,5 @@
class Book < ActiveRecord::Base
- has_many :authors
+ belongs_to :author
has_many :citations, foreign_key: "book1_id"
has_many :references, -> { distinct }, through: :citations, source: :reference_of
diff --git a/activerecord/test/models/comment.rb b/activerecord/test/models/comment.rb
index a4b81d56e0..76b484e616 100644
--- a/activerecord/test/models/comment.rb
+++ b/activerecord/test/models/comment.rb
@@ -19,6 +19,11 @@ class Comment < ActiveRecord::Base
has_many :children, class_name: "Comment", foreign_key: :parent_id
belongs_to :parent, class_name: "Comment", counter_cache: :children_count
+ # Should not be called if extending modules that having the method exists on an association.
+ def self.greeting
+ raise
+ end
+
def self.what_are_you
"a comment..."
end
diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb
index 20e37710e7..d269a95e8c 100644
--- a/activerecord/test/models/company.rb
+++ b/activerecord/test/models/company.rb
@@ -170,14 +170,6 @@ class Client < Company
def overwrite_to_raise
end
-
- class << self
- private
-
- def private_method
- "darkness"
- end
- end
end
class ExclusivelyDependentFirm < Company
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index a4fc1e34eb..3ce4a0bbab 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -18,4 +18,5 @@
*Josh Pencheon*
+
Please check [5-1-stable](https://github.com/rails/rails/blob/5-1-stable/activesupport/CHANGELOG.md) for previous changes.
diff --git a/activesupport/lib/active_support/cache/strategy/local_cache.rb b/activesupport/lib/active_support/cache/strategy/local_cache.rb
index 672eb2bb80..91875a56f5 100644
--- a/activesupport/lib/active_support/cache/strategy/local_cache.rb
+++ b/activesupport/lib/active_support/cache/strategy/local_cache.rb
@@ -115,7 +115,12 @@ module ActiveSupport
end
def write_entry(key, entry, options)
- local_cache.write_entry(key, entry, options) if local_cache
+ if options[:unless_exist]
+ local_cache.delete_entry(key, options) if local_cache
+ else
+ local_cache.write_entry(key, entry, options) if local_cache
+ end
+
super
end
diff --git a/activesupport/lib/active_support/core_ext/date_time/compatibility.rb b/activesupport/lib/active_support/core_ext/date_time/compatibility.rb
index eb8b8b2c65..870391aeaa 100644
--- a/activesupport/lib/active_support/core_ext/date_time/compatibility.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/compatibility.rb
@@ -1,4 +1,5 @@
require "active_support/core_ext/date_and_time/compatibility"
+require "active_support/core_ext/module/remove_method"
class DateTime
include DateAndTime::Compatibility
diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb
index 85ab739095..13f3894e6c 100644
--- a/activesupport/lib/active_support/core_ext/module/delegation.rb
+++ b/activesupport/lib/active_support/core_ext/module/delegation.rb
@@ -219,48 +219,43 @@ class Module
# When building decorators, a common pattern may emerge:
#
# class Partition
- # def initialize(first_event)
- # @events = [ first_event ]
+ # def initialize(event)
+ # @event = event
# end
#
- # def people
- # if @events.first.detail.people.any?
- # @events.collect { |e| Array(e.detail.people) }.flatten.uniq
- # else
- # @events.collect(&:creator).uniq
- # end
+ # def person
+ # @event.detail.person || @event.creator
# end
#
# private
# def respond_to_missing?(name, include_private = false)
- # @events.respond_to?(name, include_private)
+ # @event.respond_to?(name, include_private)
# end
#
# def method_missing(method, *args, &block)
- # @events.send(method, *args, &block)
+ # @event.send(method, *args, &block)
# end
# end
#
- # With `Module#delegate_missing_to`, the above is condensed to:
+ # With <tt>Module#delegate_missing_to</tt>, the above is condensed to:
#
# class Partition
- # delegate_missing_to :@events
+ # delegate_missing_to :@event
#
- # def initialize(first_event)
- # @events = [ first_event ]
+ # def initialize(event)
+ # @event = event
# end
#
- # def people
- # if @events.first.detail.people.any?
- # @events.collect { |e| Array(e.detail.people) }.flatten.uniq
- # else
- # @events.collect(&:creator).uniq
- # end
+ # def person
+ # @event.detail.person || @event.creator
# end
# end
#
- # The target can be anything callable within the object. E.g. instance
- # variables, methods, constants and the likes.
+ # The target can be anything callable within the object, e.g. instance
+ # variables, methods, constants, etc.
+ #
+ # The delegated method must be public on the target, otherwise it will
+ # raise +NoMethodError+.
def delegate_missing_to(target)
target = target.to_s
target = "self.#{target}" if DELEGATION_RESERVED_METHOD_NAMES.include?(target)
diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb
index 99080e34a1..d4424ed792 100644
--- a/activesupport/lib/active_support/duration.rb
+++ b/activesupport/lib/active_support/duration.rb
@@ -305,10 +305,6 @@ module ActiveSupport
to_i
end
- def respond_to_missing?(method, include_private = false) #:nodoc:
- @value.respond_to?(method, include_private)
- end
-
# Build ISO 8601 Duration string for this duration.
# The +precision+ parameter can be used to limit seconds' precision of duration.
def iso8601(precision: nil)
@@ -335,8 +331,12 @@ module ActiveSupport
end
end
+ def respond_to_missing?(method, _)
+ value.respond_to?(method)
+ end
+
def method_missing(method, *args, &block)
- value.send(method, *args, &block)
+ value.public_send(method, *args, &block)
end
def raise_type_error(other)
diff --git a/activesupport/lib/active_support/i18n_railtie.rb b/activesupport/lib/active_support/i18n_railtie.rb
index b749913ee9..f05c707ccd 100644
--- a/activesupport/lib/active_support/i18n_railtie.rb
+++ b/activesupport/lib/active_support/i18n_railtie.rb
@@ -42,7 +42,7 @@ module I18n
case setting
when :railties_load_path
reloadable_paths = value
- app.config.i18n.load_path.unshift(*value.map(&:existent).flatten)
+ app.config.i18n.load_path.unshift(*value.flat_map(&:existent))
when :load_path
I18n.load_path += value
else
@@ -58,7 +58,7 @@ module I18n
directories = watched_dirs_with_extensions(reloadable_paths)
reloader = app.config.file_watcher.new(I18n.load_path.dup, directories) do
I18n.load_path.keep_if { |p| File.exist?(p) }
- I18n.load_path |= reloadable_paths.map(&:existent).flatten
+ I18n.load_path |= reloadable_paths.flat_map(&:existent)
I18n.reload!
end
diff --git a/activesupport/lib/active_support/message_encryptor.rb b/activesupport/lib/active_support/message_encryptor.rb
index 24053b4fe5..726e1464ad 100644
--- a/activesupport/lib/active_support/message_encryptor.rb
+++ b/activesupport/lib/active_support/message_encryptor.rb
@@ -115,7 +115,7 @@ module ActiveSupport
# Currently the OpenSSL bindings do not raise an error if auth_tag is
# truncated, which would allow an attacker to easily forge it. See
# https://github.com/ruby/openssl/issues/63
- raise InvalidMessage if aead_mode? && auth_tag.bytes.length != 16
+ raise InvalidMessage if aead_mode? && (auth_tag.nil? || auth_tag.bytes.length != 16)
cipher.decrypt
cipher.key = @secret
diff --git a/activesupport/lib/active_support/rescuable.rb b/activesupport/lib/active_support/rescuable.rb
index ee6592fb5a..12ec8bf1b8 100644
--- a/activesupport/lib/active_support/rescuable.rb
+++ b/activesupport/lib/active_support/rescuable.rb
@@ -84,12 +84,18 @@ module ActiveSupport
# end
#
# Returns the exception if it was handled and +nil+ if it was not.
- def rescue_with_handler(exception, object: self)
+ def rescue_with_handler(exception, object: self, visited_exceptions: [])
+ visited_exceptions << exception
+
if handler = handler_for_rescue(exception, object: object)
handler.call exception
exception
elsif exception
- rescue_with_handler(exception.cause, object: object)
+ if visited_exceptions.include?(exception.cause)
+ nil
+ else
+ rescue_with_handler(exception.cause, object: object, visited_exceptions: visited_exceptions)
+ end
end
end
diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb
index c67ffe69b8..dbec684ce0 100644
--- a/activesupport/test/caching_test.rb
+++ b/activesupport/test/caching_test.rb
@@ -708,6 +708,14 @@ module LocalCacheBehavior
end
end
+ def test_local_cache_of_write_with_unless_exist
+ @cache.with_local_cache do
+ @cache.write("foo", "bar")
+ @cache.write("foo", "baz", unless_exist: true)
+ assert_equal @peek.read("foo"), @cache.read("foo")
+ end
+ end
+
def test_local_cache_of_delete
@cache.with_local_cache do
@cache.write("foo", "bar")
diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb
index 4f1ab993b8..0b345ecf0f 100644
--- a/activesupport/test/core_ext/enumerable_test.rb
+++ b/activesupport/test/core_ext/enumerable_test.rb
@@ -171,10 +171,8 @@ class EnumerableTests < ActiveSupport::TestCase
assert_equal({ 5 => Payment.new(5), 15 => Payment.new(15), 10 => Payment.new(10) },
payments.index_by(&:price))
assert_equal Enumerator, payments.index_by.class
- if Enumerator.method_defined? :size
- assert_nil payments.index_by.size
- assert_equal 42, (1..42).index_by.size
- end
+ assert_nil payments.index_by.size
+ assert_equal 42, (1..42).index_by.size
assert_equal({ 5 => Payment.new(5), 15 => Payment.new(15), 10 => Payment.new(10) },
payments.index_by.each(&:price))
end
diff --git a/activesupport/test/core_ext/module_test.rb b/activesupport/test/core_ext/module_test.rb
index 085fd6592d..a4d4444d69 100644
--- a/activesupport/test/core_ext/module_test.rb
+++ b/activesupport/test/core_ext/module_test.rb
@@ -348,15 +348,15 @@ class ModuleTest < ActiveSupport::TestCase
assert has_block.hello?
end
- def test_delegate_to_missing_with_method
+ def test_delegate_missing_to_with_method
assert_equal "David", DecoratedTester.new(@david).name
end
- def test_delegate_to_missing_with_reserved_methods
+ def test_delegate_missing_to_with_reserved_methods
assert_equal "David", DecoratedReserved.new(@david).name
end
- def test_delegate_to_missing_does_not_delegate_to_private_methods
+ def test_delegate_missing_to_does_not_delegate_to_private_methods
e = assert_raises(NoMethodError) do
DecoratedReserved.new(@david).private_name
end
@@ -364,7 +364,7 @@ class ModuleTest < ActiveSupport::TestCase
assert_match(/undefined method `private_name' for/, e.message)
end
- def test_delegate_to_missing_does_not_delegate_to_fake_methods
+ def test_delegate_missing_to_does_not_delegate_to_fake_methods
e = assert_raises(NoMethodError) do
DecoratedReserved.new(@david).my_fake_method
end
@@ -372,7 +372,7 @@ class ModuleTest < ActiveSupport::TestCase
assert_match(/undefined method `my_fake_method' for/, e.message)
end
- def test_delegate_to_missing_affects_respond_to
+ def test_delegate_missing_to_affects_respond_to
assert DecoratedTester.new(@david).respond_to?(:name)
assert_not DecoratedTester.new(@david).respond_to?(:private_name)
assert_not DecoratedTester.new(@david).respond_to?(:my_fake_method)
@@ -382,7 +382,7 @@ class ModuleTest < ActiveSupport::TestCase
assert_not DecoratedTester.new(@david).respond_to?(:my_fake_method, true)
end
- def test_delegate_to_missing_respects_superclass_missing
+ def test_delegate_missing_to_respects_superclass_missing
assert_equal 42, DecoratedTester.new(@david).extra_missing
assert_respond_to DecoratedTester.new(@david), :extra_missing
diff --git a/activesupport/test/message_encryptor_test.rb b/activesupport/test/message_encryptor_test.rb
index 56a436f751..4c3515b5e1 100644
--- a/activesupport/test/message_encryptor_test.rb
+++ b/activesupport/test/message_encryptor_test.rb
@@ -86,20 +86,32 @@ class MessageEncryptorTest < ActiveSupport::TestCase
assert_equal @data, encryptor.decrypt_and_verify(message)
end
+ def test_aead_mode_with_hmac_cbc_cipher_text
+ encryptor = ActiveSupport::MessageEncryptor.new(@secret, cipher: "aes-256-gcm")
+
+ assert_aead_not_decrypted(encryptor, "eHdGeExnZEwvMSt3U3dKaFl1WFo0TjVvYzA0eGpjbm5WSkt5MXlsNzhpZ0ZnbWhBWFlQZTRwaXE1bVJCS2oxMDZhYVp2dVN3V0lNZUlWQ3c2eVhQbnhnVjFmeVVubmhRKzF3WnZyWHVNMDg9LS1HSisyakJVSFlPb05ISzRMaXRzcFdBPT0=--831a1d54a3cda8a0658dc668a03dedcbce13b5ca")
+ end
+
def test_messing_with_aead_values_causes_failures
encryptor = ActiveSupport::MessageEncryptor.new(@secret, cipher: "aes-256-gcm")
text, iv, auth_tag = encryptor.encrypt_and_sign(@data).split("--")
- assert_not_decrypted([iv, text, auth_tag] * "--")
- assert_not_decrypted([munge(text), iv, auth_tag] * "--")
- assert_not_decrypted([text, munge(iv), auth_tag] * "--")
- assert_not_decrypted([text, iv, munge(auth_tag)] * "--")
- assert_not_decrypted([munge(text), munge(iv), munge(auth_tag)] * "--")
- assert_not_decrypted([text, iv] * "--")
- assert_not_decrypted([text, iv, auth_tag[0..-2]] * "--")
+ assert_aead_not_decrypted(encryptor, [iv, text, auth_tag] * "--")
+ assert_aead_not_decrypted(encryptor, [munge(text), iv, auth_tag] * "--")
+ assert_aead_not_decrypted(encryptor, [text, munge(iv), auth_tag] * "--")
+ assert_aead_not_decrypted(encryptor, [text, iv, munge(auth_tag)] * "--")
+ assert_aead_not_decrypted(encryptor, [munge(text), munge(iv), munge(auth_tag)] * "--")
+ assert_aead_not_decrypted(encryptor, [text, iv] * "--")
+ assert_aead_not_decrypted(encryptor, [text, iv, auth_tag[0..-2]] * "--")
end
private
+ def assert_aead_not_decrypted(encryptor, value)
+ assert_raise(ActiveSupport::MessageEncryptor::InvalidMessage) do
+ encryptor.decrypt_and_verify(value)
+ end
+ end
+
def assert_not_decrypted(value)
assert_raise(ActiveSupport::MessageEncryptor::InvalidMessage) do
@encryptor.decrypt_and_verify(@verifier.generate(value))
diff --git a/activesupport/test/rescuable_test.rb b/activesupport/test/rescuable_test.rb
index f7eb047d44..3bdd1651e7 100644
--- a/activesupport/test/rescuable_test.rb
+++ b/activesupport/test/rescuable_test.rb
@@ -43,7 +43,9 @@ class Stargate
def dispatch(method)
send(method)
rescue Exception => e
- rescue_with_handler(e)
+ unless rescue_with_handler(e)
+ @result = "unhandled"
+ end
end
def attack
@@ -58,6 +60,26 @@ class Stargate
raise MadRonon.new("dex")
end
+ def crash
+ raise "unhandled RuntimeError"
+ end
+
+ def looped_crash
+ ex1 = StandardError.new("error 1")
+ ex2 = StandardError.new("error 2")
+ begin
+ begin
+ raise ex1
+ rescue
+ # sets the cause on ex2 to be ex1
+ raise ex2
+ end
+ rescue
+ # sets the cause on ex1 to be ex2
+ raise ex1
+ end
+ end
+
def fall_back_to_cause
# This exception is the cause and has a handler.
ronanize
@@ -139,4 +161,14 @@ class RescuableTest < ActiveSupport::TestCase
@stargate.dispatch :fall_back_to_cause
assert_equal "dex", @stargate.result
end
+
+ def test_unhandled_exceptions
+ @stargate.dispatch(:crash)
+ assert_equal "unhandled", @stargate.result
+ end
+
+ def test_rescue_handles_loops_in_exception_cause_chain
+ @stargate.dispatch :looped_crash
+ assert_equal "unhandled", @stargate.result
+ end
end
diff --git a/activesupport/test/testing/file_fixtures_test.rb b/activesupport/test/testing/file_fixtures_test.rb
index e44fe58ce9..faa81b5e75 100644
--- a/activesupport/test/testing/file_fixtures_test.rb
+++ b/activesupport/test/testing/file_fixtures_test.rb
@@ -8,7 +8,7 @@ class FileFixturesTest < ActiveSupport::TestCase
test "#file_fixture returns Pathname to file fixture" do
path = file_fixture("sample.txt")
assert_kind_of Pathname, path
- assert_match %r{.*/test/file_fixtures/sample.txt$}, path.to_s
+ assert_match %r{.*/test/file_fixtures/sample\.txt$}, path.to_s
end
test "raises an exception when the fixture file does not exist" do
@@ -25,6 +25,6 @@ class FileFixturesPathnameDirectoryTest < ActiveSupport::TestCase
test "#file_fixture_path returns Pathname to file fixture" do
path = file_fixture("sample.txt")
assert_kind_of Pathname, path
- assert_match %r{.*/test/file_fixtures/sample.txt$}, path.to_s
+ assert_match %r{.*/test/file_fixtures/sample\.txt$}, path.to_s
end
end
diff --git a/activesupport/test/time_travel_test.rb b/activesupport/test/time_travel_test.rb
index e0d3fb0cf5..9d354f14f4 100644
--- a/activesupport/test/time_travel_test.rb
+++ b/activesupport/test/time_travel_test.rb
@@ -99,7 +99,7 @@ class TimeTravelTest < ActiveSupport::TestCase
#noop
end
end
- assert_match(/Calling `travel_to` with a block, when we have previously already made a call to `travel_to`, can lead to confusing time stubbing./, e.message)
+ assert_match(/Calling `travel_to` with a block, when we have previously already made a call to `travel_to`, can lead to confusing time stubbing\./, e.message)
end
end
end
diff --git a/guides/bug_report_templates/action_controller_gem.rb b/guides/bug_report_templates/action_controller_gem.rb
index 46fabca3e8..1d059cc2a5 100644
--- a/guides/bug_report_templates/action_controller_gem.rb
+++ b/guides/bug_report_templates/action_controller_gem.rb
@@ -8,7 +8,7 @@ end
gemfile(true) do
source "https://rubygems.org"
# Activate the gem you are reporting the issue against.
- gem "rails", "5.1.0.rc1"
+ gem "rails", "5.1.0"
end
require "rack/test"
diff --git a/guides/bug_report_templates/active_job_gem.rb b/guides/bug_report_templates/active_job_gem.rb
index 71fe356ea0..252b270a0c 100644
--- a/guides/bug_report_templates/active_job_gem.rb
+++ b/guides/bug_report_templates/active_job_gem.rb
@@ -8,7 +8,7 @@ end
gemfile(true) do
source "https://rubygems.org"
# Activate the gem you are reporting the issue against.
- gem "activejob", "5.1.0.rc1"
+ gem "activejob", "5.1.0"
end
require "minitest/autorun"
diff --git a/guides/bug_report_templates/active_record_gem.rb b/guides/bug_report_templates/active_record_gem.rb
index a685c257ea..61d4e8d395 100644
--- a/guides/bug_report_templates/active_record_gem.rb
+++ b/guides/bug_report_templates/active_record_gem.rb
@@ -8,7 +8,7 @@ end
gemfile(true) do
source "https://rubygems.org"
# Activate the gem you are reporting the issue against.
- gem "activerecord", "5.1.0.rc1"
+ gem "activerecord", "5.1.0"
gem "sqlite3"
end
diff --git a/guides/bug_report_templates/active_record_migrations_gem.rb b/guides/bug_report_templates/active_record_migrations_gem.rb
index b4e822dfe0..0c398e334a 100644
--- a/guides/bug_report_templates/active_record_migrations_gem.rb
+++ b/guides/bug_report_templates/active_record_migrations_gem.rb
@@ -8,7 +8,7 @@ end
gemfile(true) do
source "https://rubygems.org"
# Activate the gem you are reporting the issue against.
- gem "activerecord", "5.1.0.rc1"
+ gem "activerecord", "5.1.0"
gem "sqlite3"
end
diff --git a/guides/bug_report_templates/generic_gem.rb b/guides/bug_report_templates/generic_gem.rb
index e1b705bea4..4dcd04ea27 100644
--- a/guides/bug_report_templates/generic_gem.rb
+++ b/guides/bug_report_templates/generic_gem.rb
@@ -8,7 +8,7 @@ end
gemfile(true) do
source "https://rubygems.org"
# Activate the gem you are reporting the issue against.
- gem "activesupport", "5.1.0.rc1"
+ gem "activesupport", "5.1.0"
end
require "active_support/core_ext/object/blank"
diff --git a/guides/rails_guides/generator.rb b/guides/rails_guides/generator.rb
index 28164a3cb4..35f014747c 100644
--- a/guides/rails_guides/generator.rb
+++ b/guides/rails_guides/generator.rb
@@ -73,7 +73,7 @@ module RailsGuides
@output_dir = "#{@guides_dir}/output"
@output_dir += "/kindle" if @kindle
- @source_dir += "/#{@language}" if @language
+ @output_dir += "/#{@language}" if @language
end
def create_output_dir_if_needed
diff --git a/guides/rails_guides/helpers.rb b/guides/rails_guides/helpers.rb
index 6f4b0b492c..2a193ca6b5 100644
--- a/guides/rails_guides/helpers.rb
+++ b/guides/rails_guides/helpers.rb
@@ -15,7 +15,7 @@ module RailsGuides
end
def documents_by_section
- @documents_by_section ||= YAML.load_file(File.expand_path("../../source/#{@lang ? @lang + '/' : ''}documents.yaml", __FILE__))
+ @documents_by_section ||= YAML.load_file(File.expand_path("../../source/#{@language ? @language + '/' : ''}documents.yaml", __FILE__))
end
def documents_flat
diff --git a/guides/rails_guides/markdown/renderer.rb b/guides/rails_guides/markdown/renderer.rb
index 9d43c10be6..7ac3d417a4 100644
--- a/guides/rails_guides/markdown/renderer.rb
+++ b/guides/rails_guides/markdown/renderer.rb
@@ -93,7 +93,7 @@ HTML
def github_file_url(file_path)
tree = version || edge
- root = file_path[%r{(.+)/}, 1]
+ root = file_path[%r{(\w+)/}, 1]
path = \
case root
when "abstract_controller", "action_controller", "action_dispatch"
diff --git a/guides/source/5_1_release_notes.md b/guides/source/5_1_release_notes.md
index ffa18f1a2b..fa92b9e5f8 100644
--- a/guides/source/5_1_release_notes.md
+++ b/guides/source/5_1_release_notes.md
@@ -40,7 +40,7 @@ Major Features
[Pull Request](https://github.com/rails/rails/pull/26836)
-Rails 5.1 will allow managing JavaScript dependencies
+Rails 5.1 allows managing JavaScript dependencies
from NPM via Yarn. This will make it easy to use libraries like React, VueJS
or any other library from NPM world. The Yarn support is integrated with
the asset pipeline so that all dependencies will work seamlessly with the
@@ -70,14 +70,14 @@ offerings. It is no longer required, as the UJS has been rewritten to use plain,
vanilla JavaScript. This code now ships inside of Action View as
`rails-ujs`.
-You can still use the jQuery version if needed, but it is no longer required by default.
+You can still use jQuery if needed, but it is no longer required by default.
### System tests
[Pull Request](https://github.com/rails/rails/pull/26703)
Rails 5.1 has baked-in support for writing Capybara tests, in the form of
-System tests. You need no longer worry about configuring Capybara and
+System tests. You no longer need to worry about configuring Capybara and
database cleaning strategies for such tests. Rails 5.1 provides a wrapper
for running tests in Chrome with additional features such as failure
screenshots.
@@ -86,8 +86,8 @@ screenshots.
[Pull Request](https://github.com/rails/rails/pull/28038)
-Rails will now allow management of application secrets in a secure way,
-building on top of the [sekrets](https://github.com/ahoward/sekrets) gem.
+Rails now allows management of application secrets in a secure way,
+inspired by the [sekrets](https://github.com/ahoward/sekrets) gem.
Run `bin/rails secrets:setup` to setup a new encrypted secrets file. This will
also generate a master key, which must be stored outside of the repository. The
@@ -106,33 +106,24 @@ order to share instance variables, headers and other common setup.
``` ruby
class InvitationsMailer < ApplicationMailer
-
before_action { @inviter, @invitee = params[:inviter], params[:invitee] }
before_action { @account = params[:inviter].account }
def account_invitation
mail subject: "#{@inviter.name} invited you to their Basecamp (#{@account.name})"
end
-
- def project_invitation
- @project = params[:project]
- @summarizer = ProjectInvitationSummarizer.new(@project.bucket)
-
- mail subject: "#{@inviter.name.familiar} added you to a project in Basecamp (#{@account.name})"
- end
end
-InvitationsMailer.with(inviter: person_a, invitee: person_b).account_invitation.deliver_later
+InvitationsMailer.with(inviter: person_a, invitee: person_b)
+ .account_invitation.deliver_later
```
### Direct & resolved routes
[Pull Request](https://github.com/rails/rails/pull/23138)
-Rails 5.1 has added two new methods, `resolve` and `direct`, to the routing
-DSL.
-
-The `resolve` method allows customizing polymorphic mapping of models.
+Rails 5.1 adds two new methods, `resolve` and `direct`, to the routing
+DSL. The `resolve` method allows customizing polymorphic mapping of models.
``` ruby
resource :basket
@@ -181,50 +172,94 @@ Before Rails 5.1, there were two interfaces for handling HTML forms:
Rails 5.1 combines both of these interfaces with `form_with`, and
can generate form tags based on URLs, scopes or models.
-``` erb
-# Using just a URL:
+Using just a URL:
+``` erb
<%= form_with url: posts_path do |form| %>
<%= form.text_field :title %>
<% end %>
-# =>
+<%# Will generate %>
+
<form action="/posts" method="post" data-remote="true">
<input type="text" name="title">
</form>
+```
-# Adding a scope prefixes the input field names:
+Adding a scope prefixes the input field names:
+``` erb
<%= form_with scope: :post, url: posts_path do |form| %>
<%= form.text_field :title %>
<% end %>
-# =>
+
+<%# Will generate %>
+
<form action="/posts" method="post" data-remote="true">
<input type="text" name="post[title]">
</form>
+```
-# Using a model infers both the URL and scope:
+Using a model infers both the URL and scope:
+``` erb
<%= form_with model: Post.new do |form| %>
<%= form.text_field :title %>
<% end %>
-# =>
+
+<%# Will generate %>
+
<form action="/posts" method="post" data-remote="true">
<input type="text" name="post[title]">
</form>
+```
-# An existing model makes an update form and fills out field values:
+An existing model makes an update form and fills out field values:
+``` erb
<%= form_with model: Post.first do |form| %>
<%= form.text_field :title %>
<% end %>
-# =>
+
+<%# Will generate %>
+
<form action="/posts/1" method="post" data-remote="true">
<input type="hidden" name="_method" value="patch">
<input type="text" name="post[title]" value="<the title of the post>">
</form>
```
+Incompatibilities
+-----------------
+
+The following changes may require immediate action upon upgrade.
+
+### Transactional tests with multiple connections
+
+Transactional tests now wrap all Active Record connections in database
+transactions.
+
+When a test spawns additional threads, and those threads obtain database
+connections, those connections are now handled specially:
+
+The threads will share a single connection, which is inside the managed
+transaction. This ensures all threads see the database in the same
+state, ignoring the outermost transaction. Previously, such additional
+connections were unable to see the fixture rows, for example.
+
+When a thread enters a nested transaction, it will temporarily obtain
+exclusive use of the connection, to maintain isolation.
+
+If your tests currently rely on obtaining a separate,
+outside-of-transaction, connection in a spawned thread, you'll need to
+switch to more explicit connection management.
+
+If your tests spawn threads and those threads interact while also using
+explicit database transactions, this change may introduce a deadlock.
+
+The easy way to opt out of this new behavior is to disable transactional
+tests on any test cases it affects.
+
Railties
--------
@@ -233,7 +268,7 @@ Please refer to the [Changelog][railties] for detailed changes.
### Removals
* Remove deprecated `config.static_cache_control`.
- ([commit](https://github.com/rails/rails/commit/c861decd44198f8d7d774ee6a74194d1ac1a5a13)
+ ([commit](https://github.com/rails/rails/commit/c861decd44198f8d7d774ee6a74194d1ac1a5a13))
* Remove deprecated `config.serve_static_files`.
([commit](https://github.com/rails/rails/commit/0129ca2eeb6d5b2ea8c6e6be38eeb770fe45f1fa))
@@ -267,7 +302,7 @@ Please refer to the [Changelog][railties] for detailed changes.
* Add Yarn support in new apps with a yarn binstub and package.json.
([Pull Request](https://github.com/rails/rails/pull/26836))
-* Add Webpack support in new apps via the --webpack option, which will delegate
+* Add Webpack support in new apps via the `--webpack` option, which will delegate
to the rails/webpacker gem.
([Pull Request](https://github.com/rails/rails/pull/27288))
@@ -278,6 +313,9 @@ Please refer to the [Changelog][railties] for detailed changes.
* Add encrypted secrets in `config/secrets.yml.enc`.
([Pull Request](https://github.com/rails/rails/pull/28038))
+* Display railtie class name in `rails initializers`.
+ ([Pull Request](https://github.com/rails/rails/pull/25257))
+
Action Cable
-----------
@@ -290,10 +328,7 @@ Please refer to the [Changelog][action-cable] for detailed changes.
with multiple applications.
([Pull Request](https://github.com/rails/rails/pull/27425))
-* Permit same-origin connections by default.
- ([commit](https://github.com/rails/rails/commit/dae404473409fcab0e07976aec626df670e52282))
-
-* Add `ActiveSupport::Notifications` hook for broadcasing data.
+* Add `ActiveSupport::Notifications` hook for broadcasting data.
([Pull Request](https://github.com/rails/rails/pull/24988))
Action Pack
@@ -303,10 +338,34 @@ Please refer to the [Changelog][action-pack] for detailed changes.
### Removals
+* Removed support for non-keyword arguments in `#process`, `#get`, `#post`,
+ `#patch`, `#put`, `#delete`, and `#head` for the `ActionDispatch::IntegrationTest`
+ and `ActionController::TestCase` classes.
+ ([Commit](https://github.com/rails/rails/commit/98b8309569a326910a723f521911e54994b112fb),
+ [Commit](https://github.com/rails/rails/commit/de9542acd56f60d281465a59eac11e15ca8b3323))
+
+* Removed deprecated `ActionDispatch::Callbacks.to_prepare` and
+ `ActionDispatch::Callbacks.to_cleanup`.
+ ([Commit](https://github.com/rails/rails/commit/3f2b7d60a52ffb2ad2d4fcf889c06b631db1946b))
+
+* Removed deprecated methods related to controller filters.
+ ([Commit](https://github.com/rails/rails/commit/d7be30e8babf5e37a891522869e7b0191b79b757))
+
### Deprecations
+* Deprecated `config.action_controller.raise_on_unfiltered_parameters`.
+ It doesn't have any effect in Rails 5.1.
+ ([Commit](https://github.com/rails/rails/commit/c6640fb62b10db26004a998d2ece98baede509e5))
+
### Notable changes
+* Added the `direct` and `resolve` methods to the routing DSL.
+ ([Pull Request](https://github.com/rails/rails/pull/23138))
+
+* Added a new `ActionDispatch::SystemTestCase` class to write system tests in
+ your applications.
+ ([Pull Request](https://github.com/rails/rails/pull/26703))
+
Action View
-------------
@@ -341,6 +400,9 @@ Please refer to the [Changelog][action-view] for detailed changes.
* Add `form_with` to unify `form_tag` and `form_for` usage.
([Pull Request](https://github.com/rails/rails/pull/26976))
+* Add `check_parameters` option to `current_page?`.
+ ([Pull Request](https://github.com/rails/rails/pull/27549))
+
Action Mailer
-------------
@@ -348,10 +410,6 @@ Please refer to the [Changelog][action-mailer] for detailed changes.
### Notable changes
-* Exception handling: use `rescue_from` to handle exceptions raised by
- mailer actions, by message delivery, and by deferred delivery jobs.
- ([commit](https://github.com/rails/rails/commit/e35b98e6f5c54330245645f2ed40d56c74538902))
-
* Allowed setting custom content type when attachments are included
and body is set inline.
([Pull Request](https://github.com/rails/rails/pull/27227))
@@ -374,10 +432,88 @@ Please refer to the [Changelog][active-record] for detailed changes.
### Removals
+* Removed support for passing arguments and block at the same time to
+ `ActiveRecord::QueryMethods#select`.
+ ([Commit](https://github.com/rails/rails/commit/4fc3366d9d99a0eb19e45ad2bf38534efbf8c8ce))
+
+* Removed deprecated `activerecord.errors.messages.restrict_dependent_destroy.one` and
+ `activerecord.errors.messages.restrict_dependent_destroy.many` i18n scopes.
+ ([Commit](https://github.com/rails/rails/commit/00e3973a311))
+
+* Removed deprecated force reload argument in singular and collection association readers.
+ ([Commit](https://github.com/rails/rails/commit/09cac8c67af))
+
+* Removed deprecated support for passing a column to `#quote`.
+ ([Commit](https://github.com/rails/rails/commit/e646bad5b7c))
+
+* Removed deprecated `name` arguments from `#tables`.
+ ([Commit](https://github.com/rails/rails/commit/d5be101dd02214468a27b6839ffe338cfe8ef5f3))
+
+* Removed deprecated behavior of `#tables` and `#table_exists?` to return tables and views
+ to return only tables and not views.
+ ([Commit](https://github.com/rails/rails/commit/5973a984c369a63720c2ac18b71012b8347479a8))
+
+* Removed deprecated `original_exception` argument in `ActiveRecord::StatementInvalid#initialize`
+ and `ActiveRecord::StatementInvalid#original_exception`.
+ ([Commit](https://github.com/rails/rails/commit/bc6c5df4699d3f6b4a61dd12328f9e0f1bd6cf46))
+
+* Removed deprecated support of passing a class as a value in a query.
+ ([Commit](https://github.com/rails/rails/commit/b4664864c972463c7437ad983832d2582186e886))
+
+* Removed deprecated support to query using commas on LIMIT.
+ ([Commit](https://github.com/rails/rails/commit/fc3e67964753fb5166ccbd2030d7382e1976f393))
+
+* Removed deprecated `conditions` parameter from `#destroy_all`.
+ ([Commit](https://github.com/rails/rails/commit/d31a6d1384cd740c8518d0bf695b550d2a3a4e9b))
+
+* Removed deprecated `conditions` parameter from `#delete_all`.
+ ([Commit](https://github.com/rails/rails/pull/27503/commits/e7381d289e4f8751dcec9553dcb4d32153bd922b))
+
+* Removed deprecated method `#load_schema_for` in favor of `#load_schema`.
+ ([Commit](https://github.com/rails/rails/commit/419e06b56c3b0229f0c72d3e4cdf59d34d8e5545))
+
+* Removed deprecated `#raise_in_transactional_callbacks` configuration.
+ ([Commit](https://github.com/rails/rails/commit/8029f779b8a1dd9848fee0b7967c2e0849bf6e07))
+
+* Removed deprecated `#use_transactional_fixtures` configuration.
+ ([Commit](https://github.com/rails/rails/commit/3955218dc163f61c932ee80af525e7cd440514b3))
+
### Deprecations
+* Deprecated `error_on_ignored_order_or_limit` flag in favor of
+ `error_on_ignored_order`.
+ ([Commit](https://github.com/rails/rails/commit/451437c6f57e66cc7586ec966e530493927098c7))
+
+* Deprecated `sanitize_conditions` in favor of `sanitize_sql`.
+ ([Pull Request](https://github.com/rails/rails/pull/25999))
+
+* Deprecated `supports_migrations?` on connection adapters.
+ ([Pull Request](https://github.com/rails/rails/pull/28172))
+
+* Deprecated `Migrator.schema_migrations_table_name`, use `SchemaMigration.table_name` instead.
+ ([Pull Request](https://github.com/rails/rails/pull/28351))
+
+* Deprecated using `#quoted_id` in quoting and type casting.
+ ([Pull Request](https://github.com/rails/rails/pull/27962))
+
+* Deprecated passing `default` argument to `#index_name_exists?`.
+ ([Pull Request](https://github.com/rails/rails/pull/26930))
+
### Notable changes
+* Change Default Primary Keys to BIGINT.
+ ([Pull Request](https://github.com/rails/rails/pull/26266))
+
+* Virtual/generated column support for MySQL 5.7.5+ and MariaDB 5.2.0+.
+ ([Commit](https://github.com/rails/rails/commit/65bf1c60053e727835e06392d27a2fb49665484c))
+
+* Added support for limits in batch processing.
+ ([Commit](https://github.com/rails/rails/commit/451437c6f57e66cc7586ec966e530493927098c7))
+
+* Transactional tests now wrap all Active Record connections in database
+ transactions.
+ ([Pull Request](https://github.com/rails/rails/pull/28726))
+
* Skipped comments in the output of `mysqldump` command by default.
([Pull Request](https://github.com/rails/rails/pull/23301))
@@ -389,6 +525,16 @@ Please refer to the [Changelog][active-record] for detailed changes.
* Pass `"-v ON_ERROR_STOP=1"` flag with `psql` command to not suppress SQL errors.
([Pull Request](https://github.com/rails/rails/pull/24773))
+* Add `ActiveRecord::Base.connection_pool.stat`.
+ ([Pull Request](https://github.com/rails/rails/pull/26988))
+
+* Inheriting directly from `ActiveRecord::Migration` raises an error.
+ Specify the Rails version for which the migration was written for.
+ ([Commit](https://github.com/rails/rails/commit/249f71a22ab21c03915da5606a063d321f04d4d3))
+
+* An error is raised when `through` association has ambiguous reflection name.
+ ([Commit](https://github.com/rails/rails/commit/0944182ad7ed70d99b078b22426cbf844edd3f61))
+
Active Model
------------
@@ -440,10 +586,36 @@ Please refer to the [Changelog][active-support] for detailed changes.
### Removals
+* Removed the `ActiveSupport::Concurrency::Latch` class.
+ ([Commit](https://github.com/rails/rails/commit/0d7bd2031b4054fbdeab0a00dd58b1b08fb7fea6))
+
+* Removed `halt_callback_chains_on_return_false`.
+ ([Commit](https://github.com/rails/rails/commit/4e63ce53fc25c3bc15c5ebf54bab54fa847ee02a))
+
+* Removed deprecated behavior that halts callbacks when the return is false.
+ ([Commit](https://github.com/rails/rails/commit/3a25cdca3e0d29ee2040931d0cb6c275d612dffe))
+
### Deprecations
+* The top level `HashWithIndifferentAccess` class has been softly deprecated
+ in favor of the `ActiveSupport::HashWithIndifferentAccess` one.
+ ([Pull Request](https://github.com/rails/rails/pull/28157))
+
+* Deprecated passing string to `:if` and `:unless` conditional options on `set_callback` and `skip_callback`.
+ ([Commit](https://github.com/rails/rails/commit/0952552)
+
### Notable changes
+* Fixed duration parsing and traveling to make it consistent across DST changes.
+ ([Commit](https://github.com/rails/rails/commit/8931916f4a1c1d8e70c06063ba63928c5c7eab1e),
+ [Pull Request](https://github.com/rails/rails/pull/26597))
+
+* Updated Unicode to version 9.0.0.
+ ([Pull Request](https://github.com/rails/rails/pull/27822))
+
+* Add Duration#before and #after as aliases for #ago and #since.
+ ([Pull Request](https://github.com/rails/rails/pull/27721))
+
* Added `Module#delegate_missing_to` to delegate method calls not
defined for the current object to a proxy object.
([Pull Request](https://github.com/rails/rails/pull/23930))
@@ -452,6 +624,15 @@ Please refer to the [Changelog][active-support] for detailed changes.
of the current date & time.
([Pull Request](https://github.com/rails/rails/pull/24930))
+* Introduced the `assert_changes` and `assert_no_changes` methods for tests.
+ ([Pull Request](https://github.com/rails/rails/pull/25393))
+
+* The `travel` and `travel_to` methods now raise on nested calls.
+ ([Pull Request](https://github.com/rails/rails/pull/24890))
+
+* Update `DateTime#change` to support usec and nsec.
+ ([Pull Request](https://github.com/rails/rails/pull/28242))
+
Credits
-------
diff --git a/guides/source/autoloading_and_reloading_constants.md b/guides/source/autoloading_and_reloading_constants.md
index 61657023e7..05743ee4ce 100644
--- a/guides/source/autoloading_and_reloading_constants.md
+++ b/guides/source/autoloading_and_reloading_constants.md
@@ -983,20 +983,19 @@ WHERE "polygons"."type" IN ("Rectangle")
That is not a bug, the query includes all *known* descendants of `Rectangle`.
A way to ensure this works correctly regardless of the order of execution is to
-load the leaves of the tree by hand at the bottom of the file that defines the
-root class:
+manually load the direct subclasses at the bottom of the file that defines each
+intermediate class:
```ruby
-# app/models/polygon.rb
-class Polygon < ApplicationRecord
+# app/models/rectangle.rb
+class Rectangle < Polygon
end
-require_dependency ‘square’
+require_dependency 'square'
```
-Only the leaves that are **at least grandchildren** need to be loaded this
-way. Direct subclasses do not need to be preloaded. If the hierarchy is
-deeper, intermediate classes will be autoloaded recursively from the bottom
-because their constant will appear in the class definitions as superclass.
+This needs to happen for every intermediate (non-root and non-leaf) class. The
+root class does not scope the query by type, and therefore does not necessarily
+have to know all its descendants.
### Autoloading and `require`
diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md
index 39f4272b3c..2f2962a3e6 100644
--- a/guides/source/contributing_to_ruby_on_rails.md
+++ b/guides/source/contributing_to_ruby_on_rails.md
@@ -141,14 +141,15 @@ NOTE: To help our CI servers you should add [ci skip] to your documentation comm
Translating Rails Guides
------------------------
-We are happy to have people volunteer to translate the Rails guides into their own language.
-If you want to translate the Rails guides in your own language, follows these steps:
+We are happy to have people volunteer to translate the Rails guides. Just follow these steps:
-* Fork the project (rails/rails).
+* Fork https://github.com/rails/rails.
* Add a source folder for your own language, for example: *guides/source/it-IT* for Italian.
* Copy the contents of *guides/source* into your own language directory and translate them.
* Do NOT translate the HTML files, as they are automatically generated.
+Note that translations are not submitted to the Rails repository. As detailed above, your work happens in a fork. This is so because in practice documentation maintenance via patches is only sustainable in English.
+
To generate the guides in HTML format cd into the *guides* directory then run (eg. for it-IT):
```bash
diff --git a/guides/source/documents.yaml b/guides/source/documents.yaml
index 5fccdcccec..2afef57fc2 100644
--- a/guides/source/documents.yaml
+++ b/guides/source/documents.yaml
@@ -197,7 +197,6 @@
name: Ruby on Rails 5.1 Release Notes
url: 5_1_release_notes.html
description: Release notes for Rails 5.1.
- work_in_progress: true
-
name: Ruby on Rails 5.0 Release Notes
url: 5_0_release_notes.html
diff --git a/guides/source/testing.md b/guides/source/testing.md
index 7741834153..c0394f927e 100644
--- a/guides/source/testing.md
+++ b/guides/source/testing.md
@@ -350,7 +350,7 @@ Rails adds some custom assertions of its own to the `minitest` framework:
| --------------------------------------------------------------------------------- | ------- |
| [`assert_difference(expressions, difference = 1, message = nil) {...}`](http://api.rubyonrails.org/classes/ActiveSupport/Testing/Assertions.html#method-i-assert_difference) | Test numeric difference between the return value of an expression as a result of what is evaluated in the yielded block.|
| [`assert_no_difference(expressions, message = nil, &block)`](http://api.rubyonrails.org/classes/ActiveSupport/Testing/Assertions.html#method-i-assert_no_difference) | Asserts that the numeric result of evaluating an expression is not changed before and after invoking the passed in block.|
-| [`assert_nothing_raised { block }`](http://api.rubyonrails.org/classes/ActiveSupport/TestCase.html#method-i-assert_nothing_raised) | Ensures that the given block doesn't raise any exceptions.|
+| [`assert_nothing_raised { block }`](http://api.rubyonrails.org/classes/ActiveSupport/Testing/Assertions.html#method-i-assert_nothing_raised) | Ensures that the given block doesn't raise any exceptions.|
| [`assert_recognizes(expected_options, path, extras={}, message=nil)`](http://api.rubyonrails.org/classes/ActionDispatch/Assertions/RoutingAssertions.html#method-i-assert_recognizes) | Asserts that the routing of the given path was handled correctly and that the parsed options (given in the expected_options hash) match path. Basically, it asserts that Rails recognizes the route given by expected_options.|
| [`assert_generates(expected_path, options, defaults={}, extras = {}, message=nil)`](http://api.rubyonrails.org/classes/ActionDispatch/Assertions/RoutingAssertions.html#method-i-assert_generates) | Asserts that the provided options can be used to generate the provided path. This is the inverse of assert_recognizes. The extras parameter is used to tell the request the names and values of additional request parameters that would be in a query string. The message parameter allows you to specify a custom error message for assertion failures.|
| [`assert_response(type, message = nil)`](http://api.rubyonrails.org/classes/ActionDispatch/Assertions/ResponseAssertions.html#method-i-assert_response) | Asserts that the response comes with a specific status code. You can specify `:success` to indicate 200-299, `:redirect` to indicate 300-399, `:missing` to indicate 404, or `:error` to match the 500-599 range. You can also pass an explicit status number or its symbolic equivalent. For more information, see [full list of status codes](http://rubydoc.info/github/rack/rack/master/Rack/Utils#HTTP_STATUS_CODES-constant) and how their [mapping](http://rubydoc.info/github/rack/rack/master/Rack/Utils#SYMBOL_TO_STATUS_CODE-constant) works.|
@@ -610,9 +610,9 @@ For creating Rails system tests, you use the `test/system` directory in your
application. Rails provides a generator to create a system test skeleton for you.
```bash
-$ bin/rails generate system_test users_create
+$ bin/rails generate system_test users
invoke test_unit
- create test/system/users_creates_test.rb
+ create test/system/users_test.rb
```
Here's what a freshly-generated system test looks like:
@@ -620,11 +620,11 @@ Here's what a freshly-generated system test looks like:
```ruby
require "application_system_test_case"
-class UsersCreatesTest < ApplicationSystemTestCase
+class UsersTest < ApplicationSystemTestCase
# test "visiting the index" do
- # visit users_creates_url
+ # visit users_url
#
- # assert_selector "h1", text: "UsersCreate"
+ # assert_selector "h1", text: "Users"
# end
end
```
@@ -658,8 +658,8 @@ end
The driver name is a required argument for `driven_by`. The optional arguments
that can be passed to `driven_by` are `:using` for the browser (this will only
-be used for non-headless drivers like Selenium), and `:screen_size` to change
-the size of the screen for screenshots.
+be used by Selenium), and `:screen_size` to change the size of the screen for
+screenshots.
```ruby
require "test_helper"
@@ -1406,7 +1406,7 @@ In order to test that your mailer is working as expected, you can use unit tests
For the purposes of unit testing a mailer, fixtures are used to provide an example of how the output _should_ look. Because these are example emails, and not Active Record data like the other fixtures, they are kept in their own subdirectory apart from the other fixtures. The name of the directory within `test/fixtures` directly corresponds to the name of the mailer. So, for a mailer named `UserMailer`, the fixtures should reside in `test/fixtures/user_mailer` directory.
-When you generated your mailer, the generator creates stub fixtures for each of the mailers actions. If you didn't use the generator, you'll have to create those files yourself.
+If you generated your mailer, the generator does not create stub fixtures for the mailers actions. You'll have to create those files yourself as described above.
#### The Basic Test Case
@@ -1482,7 +1482,7 @@ class UserControllerTest < ActionDispatch::IntegrationTest
assert_equal "You have been invited by me@example.com", invite_email.subject
assert_equal 'friend@example.com', invite_email.to[0]
- assert_match(/Hi friend@example.com/, invite_email.body.to_s)
+ assert_match(/Hi friend@example\.com/, invite_email.body.to_s)
end
end
```
diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md
index ff747a95a0..93864db141 100644
--- a/guides/source/upgrading_ruby_on_rails.md
+++ b/guides/source/upgrading_ruby_on_rails.md
@@ -83,7 +83,7 @@ Also, if you have pretty old YAML documents containing dumps of such objects,
you may need to load and dump them again to make sure that they reference
the right constant, and that loading them won't break in the future.
-### `config.secrets` now loaded with all keys as symbols
+### `application.secrets` now loaded with all keys as symbols
If your application stores nested configuration in `config/secrets.yml`, all keys
are now loaded as symbols, so access using strings should be changed.
@@ -91,13 +91,13 @@ are now loaded as symbols, so access using strings should be changed.
From:
```ruby
-Rails.appplication.config.secrets[:smtp_settings]["address"]
+Rails.application.secrets[:smtp_settings]["address"]
```
To:
```ruby
-Rails.application.config.secrets[:smtp_settings][:address]
+Rails.application.secrets[:smtp_settings][:address]
```
Upgrading from Rails 4.2 to Rails 5.0
diff --git a/guides/source/working_with_javascript_in_rails.md b/guides/source/working_with_javascript_in_rails.md
index 2a6a87c232..cf08c5dd1d 100644
--- a/guides/source/working_with_javascript_in_rails.md
+++ b/guides/source/working_with_javascript_in_rails.md
@@ -141,6 +141,8 @@ follow this pattern.
Built-in Helpers
----------------------
+### Remote elements
+
Rails provides a bunch of view helper methods written in Ruby to assist you
in generating HTML. Sometimes, you want to add a little Ajax to those elements,
and Rails has got your back in those cases.
@@ -153,14 +155,18 @@ Unless you have disabled the Asset Pipeline,
provides the JavaScript half, and the regular Ruby view helpers add appropriate
tags to your DOM.
-### form_for
+You can read below about the different events that are fired dealing with
+remote elements inside your application.
+
+#### form_with
-[`form_for`](http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_for)
-is a helper that assists with writing forms. `form_for` takes a `:remote`
-option. It works like this:
+[`form_with`](http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_with)
+is a helper that assists with writing forms. By default, `form_with` assumes that
+your form will be using Ajax. You can opt out of this behavior by
+passing the `:local` option `form_with`.
```erb
-<%= form_for(@article, remote: true) do |f| %>
+<%= form_with(model: @article) do |f| %>
...
<% end %>
```
@@ -168,7 +174,7 @@ option. It works like this:
This will generate the following HTML:
```html
-<form accept-charset="UTF-8" action="/articles" class="new_article" data-remote="true" id="new_article" method="post">
+<form action="/articles" method="post" data-remote="true">
...
</form>
```
@@ -189,32 +195,9 @@ $(document).ready ->
```
Obviously, you'll want to be a bit more sophisticated than that, but it's a
-start. You can see more about the events [in the jquery-ujs wiki](https://github.com/rails/jquery-ujs/wiki/ajax).
-
-### form_tag
-
-[`form_tag`](http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html#method-i-form_tag)
-is very similar to `form_for`. It has a `:remote` option that you can use like
-this:
-
-```erb
-<%= form_tag('/articles', remote: true) do %>
- ...
-<% end %>
-```
-
-This will generate the following HTML:
-
-```html
-<form accept-charset="UTF-8" action="/articles" data-remote="true" method="post">
- ...
-</form>
-```
-
-Everything else is the same as `form_for`. See its documentation for full
-details.
+start.
-### link_to
+#### link_to
[`link_to`](http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to)
is a helper that assists with generating links. It has a `:remote` option you
@@ -230,7 +213,7 @@ which generates
<a href="/articles/1" data-remote="true">an article</a>
```
-You can bind to the same Ajax events as `form_for`. Here's an example. Let's
+You can bind to the same Ajax events as `form_with`. Here's an example. Let's
assume that we have a list of articles that can be deleted with just one
click. We would generate some HTML like this:
@@ -246,7 +229,7 @@ $ ->
alert "The article was deleted."
```
-### button_to
+#### button_to
[`button_to`](http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-button_to) is a helper that helps you create buttons. It has a `:remote` option that you can call like this:
@@ -262,7 +245,136 @@ this generates
</form>
```
-Since it's just a `<form>`, all of the information on `form_for` also applies.
+Since it's just a `<form>`, all of the information on `form_with` also applies.
+
+### Customize remote elements
+
+It is possible to customize the behavior of elements with a `data-remote`
+attribute without writing a line of JavaScript. Your can specify extra `data-`
+attributes to accomplish this.
+
+#### `data-method`
+
+Activating hyperlinks always results in an HTTP GET request. However, if your
+application is [RESTful](http://en.wikipedia.org/wiki/Representational_State_Transfer),
+some links are in fact actions that change data on the server, and must be
+performed with non-GET requests. This attribute allows marking up such links
+with an explicit method such as "post", "put" or "delete".
+
+The way it works is that, when the link is activated, it constructs a hidden form
+in the document with the "action" attribute corresponding to "href" value of the
+link, and the method corresponding to `data-method` value, and submits that form.
+
+NOTE: Because submitting forms with HTTP methods other than GET and POST isn't
+widely supported across browsers, all other HTTP methods are actually sent over
+POST with the intended method indicated in the `_method` parameter. Rails
+automatically detects and compensates for this.
+
+#### `data-url` and `data-params`
+
+Certain elements of your page aren't actually referring to any URL, but you may want
+them to trigger Ajax calls. Specifying the `data-url` attribute along with
+the `data-remote` one will trigger an Ajax call to the given URL. You can also
+specify extra parameters through the `data-params` attribute.
+
+This can be useful to trigger an action on check-boxes for instance:
+
+```html
+<input type="checkbox" data-remote="true"
+ data-url="/update" data-params="id=10" data-method="put">
+```
+
+#### `data-type`
+
+It is also possible to define the Ajax `dataType` explicitly while performing
+requests for `data-remote` elements, by way of the `data-type` attribute.
+
+### Confirmations
+
+You can ask for an extra confirmation of the user by adding a `data-confirm`
+attribute on links and forms. The user will be presented a JavaScript `confirm()`
+dialog containing the attribute's text. If the user chooses to cancel, the action
+doesn't take place.
+
+Adding this attribute on links will trigger the dialog on click, and adding it
+on forms will trigger it on submit. For example:
+
+```erb
+<%= link_to "Dangerous zone", dangerous_zone_path,
+ data: { confirm: 'Are you sure?' } %>
+```
+
+This generates:
+
+```html
+<a href="..." data-confirm="Are you sure?">Dangerous zone</a>
+```
+
+The attribute is also allowed on form submit buttons. This allows you to customize
+the warning message depending on the button which was activated. In this case,
+you should **not** have `data-confirm` on the form itself.
+
+The default confirmation uses a JavaScript confirm dialog, but you can customize
+this by listening to the `confirm` event, which is fired just before the confirmation
+window appears to the user. To cancel this default confirmation, have the confirm
+handler to return `false`.
+
+### Automatic disabling
+
+It is also possible to automatically disable an input while the form is submitting
+by using the `data-disable-with` attribute. This is to prevent accidental
+double-clicks from the user, which could result in duplicate HTTP requests that
+the backend may not detect as such. The value of the attribute is the text that will
+become the new value of the button in its disabled state.
+
+This also works for links with `data-method` attribute.
+
+For example:
+
+```erb
+<%= form_with(model: @article.new) do |f| %>
+ <%= f.submit data: { "disable-with": "Saving..." } %>
+<%= end %>
+```
+
+This generates a form with:
+
+```html
+<input data-disable-with="Saving..." type="submit">
+```
+
+Dealing with Ajax events
+------------------------
+
+Here are the different events that are fired when you deal with elements
+that have a `data-remote` attribute:
+
+NOTE: All handlers bound to these events are always passed the event object as the
+first argument. The table below describes the extra parameters passed after the
+event argument. For example, if the extra parameters are listed as `xhr, settings`,
+then to access them, you would define your handler with `function(event, xhr, settings)`.
+
+| Event name | Extra parameters | Fired |
+|---------------------|------------------|-------------------------------------------------------------|
+| `ajax:before` | | Before the whole ajax business, aborts if stopped. |
+| `ajax:beforeSend` | xhr, options | Before the request is sent, aborts if stopped. |
+| `ajax:send` | xhr | When the request is sent. |
+| `ajax:success` | xhr, status, err | After completion, if the response was a success. |
+| `ajax:error` | xhr, status, err | After completion, if the response was an error. |
+| `ajax:complete` | xhr, status | After the request has been completed, no matter the outcome.|
+| `ajax:aborted:file` | elements | If there are non-blank file inputs, aborts if stopped. |
+
+### Stoppable events
+
+If you stop `ajax:before` or `ajax:beforeSend` by returning false from the
+handler method, the Ajax request will never take place. The `ajax:before` event
+is also useful for manipulating form data before serialization. The
+`ajax:beforeSend` event is also useful for adding custom request headers.
+
+If you stop the `ajax:aborted:file` event, the default behavior of allowing the
+browser to submit the form via normal means (i.e. non-AJAX submission) will be
+canceled and the form will not be submitted at all. This is useful for
+implementing your own AJAX file upload workaround.
Server-Side Concerns
--------------------
@@ -297,7 +409,7 @@ The index view (`app/views/users/index.html.erb`) contains:
<br>
-<%= form_for(@user, remote: true) do |f| %>
+<%= form_with(model: @user) do |f| %>
<%= f.label :name %><br>
<%= f.text_field :name %>
<%= f.submit %>
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 5463b05b60..d93c532c7e 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,8 +1,17 @@
+* Allow irb options to be passed from `rails console` command.
+
+ Fixes #28988.
+
+ *Yuji Yaginuma*
+
+* Added a shared section to config/database.yml that will be loaded for all environments.
+
+ *Pierre Schambacher*
+
* Namespace error pages' CSS selectors to stop the styles from bleeding into other pages
- when using Turbolinks.
-
+ when using Turbolinks.
+
*Jan Krutisch*
-
Please check [5-1-stable](https://github.com/rails/rails/blob/5-1-stable/railties/CHANGELOG.md) for previous changes.
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index 7c49fabba5..27c1572357 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -133,7 +133,14 @@ module Rails
config = if yaml && yaml.exist?
require "yaml"
require "erb"
- YAML.load(ERB.new(yaml.read).result) || {}
+ loaded_yaml = YAML.load(ERB.new(yaml.read).result) || {}
+ shared = loaded_yaml.delete("shared")
+ if shared
+ loaded_yaml.each do |_k, values|
+ values.reverse_merge!(shared)
+ end
+ end
+ Hash.new(shared).merge(loaded_yaml)
elsif ENV["DATABASE_URL"]
# Value from ENV['DATABASE_URL'] is set to default database connection
# by Active Record.
diff --git a/railties/lib/rails/commands/console/console_command.rb b/railties/lib/rails/commands/console/console_command.rb
index 62e3aa19df..ec58540923 100644
--- a/railties/lib/rails/commands/console/console_command.rb
+++ b/railties/lib/rails/commands/console/console_command.rb
@@ -73,14 +73,26 @@ module Rails
class_option :environment, aliases: "-e", type: :string,
desc: "Specifies the environment to run this console under (test/development/production)."
+ def initialize(args = [], local_options = {}, config = {})
+ console_options = []
+
+ # For the same behavior as OptionParser, leave only options after "--" in ARGV.
+ termination = local_options.find_index("--")
+ if termination
+ console_options = local_options[termination + 1..-1]
+ local_options = local_options[0...termination]
+ end
+
+ ARGV.replace(console_options)
+ super(args, local_options, config)
+ end
+
def perform
extract_environment_option_from_argument
# RAILS_ENV needs to be set before config/application is required.
ENV["RAILS_ENV"] = options[:environment]
- ARGV.clear # Clear ARGV so IRB doesn't freak.
-
require_application_and_environment!
Rails::Console.start(Rails.application, options)
end
diff --git a/railties/lib/rails/commands/help/USAGE b/railties/lib/rails/commands/help/USAGE
index c5f8ab72bb..8eb98319d2 100644
--- a/railties/lib/rails/commands/help/USAGE
+++ b/railties/lib/rails/commands/help/USAGE
@@ -1,13 +1,14 @@
The most common rails commands are:
- generate Generate new code (short-cut alias: "g")
- console Start the Rails console (short-cut alias: "c")
- server Start the Rails server (short-cut alias: "s")
- test Run tests (short-cut alias: "t")
- dbconsole Start a console for the database specified in config/database.yml
- (short-cut alias: "db")
+ generate Generate new code (short-cut alias: "g")
+ console Start the Rails console (short-cut alias: "c")
+ server Start the Rails server (short-cut alias: "s")
+ test Run tests except system tests (short-cut alias: "t")
+ test:system Run system tests
+ dbconsole Start a console for the database specified in config/database.yml
+ (short-cut alias: "db")
<% unless engine? %>
- new Create a new Rails application. "rails new my_app" creates a
- new application called MyApp in "./my_app"
+ new Create a new Rails application. "rails new my_app" creates a
+ new application called MyApp in "./my_app"
<% end %>
All commands can be run with -h (or --help) for more information.
diff --git a/railties/lib/rails/commands/server/server_command.rb b/railties/lib/rails/commands/server/server_command.rb
index 278fe63c51..cf3903f3ae 100644
--- a/railties/lib/rails/commands/server/server_command.rb
+++ b/railties/lib/rails/commands/server/server_command.rb
@@ -95,10 +95,11 @@ module Rails
module Command
class ServerCommand < Base # :nodoc:
+ DEFAULT_PORT = 3000
DEFAULT_PID_PATH = "tmp/pids/server.pid".freeze
class_option :port, aliases: "-p", type: :numeric,
- desc: "Runs Rails on the specified port.", banner: :port, default: 3000
+ desc: "Runs Rails on the specified port - defaults to 3000.", banner: :port
class_option :binding, aliases: "-b", type: :string,
desc: "Binds Rails to the specified IP - defaults to 'localhost' in development and '0.0.0.0' in other environments'.",
banner: :IP
@@ -184,7 +185,7 @@ module Rails
end
def port
- ENV.fetch("PORT", options[:port]).to_i
+ options[:port] || ENV.fetch("PORT", DEFAULT_PORT).to_i
end
def host
diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb
index f4717bb35b..669514b37e 100644
--- a/railties/lib/rails/generators/rails/app/app_generator.rb
+++ b/railties/lib/rails/generators/rails/app/app_generator.rb
@@ -67,6 +67,10 @@ module Rails
end
end
+ def package_json
+ template "package.json"
+ end
+
def app
directory "app"
@@ -198,10 +202,6 @@ module Rails
def vendor
empty_directory_with_keep_file "vendor"
-
- unless options[:skip_yarn]
- template "package.json"
- end
end
end
@@ -248,6 +248,7 @@ module Rails
build(:gitignore) unless options[:skip_git]
build(:gemfile) unless options[:skip_gemfile]
build(:version_control)
+ build(:package_json) unless options[:skip_yarn]
end
def create_app_files
@@ -317,10 +318,6 @@ module Rails
def create_vendor_files
build(:vendor)
-
- if options[:skip_yarn]
- remove_file "package.json"
- end
end
def delete_app_assets_if_api_option
diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile
index 06f0dd6d6d..1911fb7a7b 100644
--- a/railties/lib/rails/generators/rails/app/templates/Gemfile
+++ b/railties/lib/rails/generators/rails/app/templates/Gemfile
@@ -34,7 +34,7 @@ group :development, :test do
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
<%- if depends_on_system_test? -%>
# Adds support for Capybara system testing and selenium driver
- gem 'capybara', '~> 2.13.0'
+ gem 'capybara', '~> 2.13'
gem 'selenium-webdriver'
<%- end -%>
end
diff --git a/railties/lib/rails/generators/rails/app/templates/bin/yarn b/railties/lib/rails/generators/rails/app/templates/bin/yarn
index 4ae896a8d3..44f75c22a4 100644
--- a/railties/lib/rails/generators/rails/app/templates/bin/yarn
+++ b/railties/lib/rails/generators/rails/app/templates/bin/yarn
@@ -3,7 +3,8 @@ Dir.chdir(VENDOR_PATH) do
begin
exec "yarnpkg #{ARGV.join(" ")}"
rescue Errno::ENOENT
- puts "Yarn executable was not detected in the system."
- puts "Download Yarn at https://yarnpkg.com/en/docs/install"
+ $stderr.puts "Yarn executable was not detected in the system."
+ $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
+ exit 1
end
end
diff --git a/railties/lib/rails/mailers_controller.rb b/railties/lib/rails/mailers_controller.rb
index 000ce40fbc..7ff55ef5bf 100644
--- a/railties/lib/rails/mailers_controller.rb
+++ b/railties/lib/rails/mailers_controller.rb
@@ -6,6 +6,8 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc:
before_action :require_local!, unless: :show_previews?
before_action :find_preview, only: :preview
+ helper_method :part_query
+
def index
@previews = ActionMailer::Preview.all
@page_title = "Mailer Previews"
@@ -19,7 +21,7 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc:
@email_action = File.basename(params[:path])
if @preview.email_exists?(@email_action)
- @email = @preview.call(@email_action)
+ @email = @preview.call(@email_action, params)
if params[:part]
part_type = Mime::Type.lookup(params[:part])
@@ -76,4 +78,8 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc:
@email
end
end
+
+ def part_query(mime_type)
+ request.query_parameters.merge(part: mime_type).to_query
+ end
end
diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb
index 474118c0a9..3476bb0eb5 100644
--- a/railties/lib/rails/railtie.rb
+++ b/railties/lib/rails/railtie.rb
@@ -162,10 +162,6 @@ module Rails
@instance ||= new
end
- def respond_to_missing?(*args)
- instance.respond_to?(*args) || super
- end
-
# Allows you to configure the railtie. This is the same method seen in
# Railtie::Configurable, but this module is no longer required for all
# subclasses of Railtie so we provide the class method here.
@@ -178,6 +174,10 @@ module Rails
ActiveSupport::Inflector.underscore(string).tr("/", "_")
end
+ def respond_to_missing?(name, _)
+ instance.respond_to?(name) || super
+ end
+
# If the class method does not have a method, then send the method call
# to the Railtie instance.
def method_missing(name, *args, &block)
diff --git a/railties/lib/rails/templates/rails/mailers/email.html.erb b/railties/lib/rails/templates/rails/mailers/email.html.erb
index c63781ed0c..89c1129f90 100644
--- a/railties/lib/rails/templates/rails/mailers/email.html.erb
+++ b/railties/lib/rails/templates/rails/mailers/email.html.erb
@@ -98,8 +98,8 @@
<% if @email.multipart? %>
<dd>
<select onchange="formatChanged(this);">
- <option <%= request.format == Mime[:html] ? 'selected' : '' %> value="?part=text%2Fhtml">View as HTML email</option>
- <option <%= request.format == Mime[:text] ? 'selected' : '' %> value="?part=text%2Fplain">View as plain-text email</option>
+ <option <%= request.format == Mime[:html] ? 'selected' : '' %> value="?<%= part_query('text/html') %>">View as HTML email</option>
+ <option <%= request.format == Mime[:text] ? 'selected' : '' %> value="?<%= part_query('text/plain') %>">View as plain-text email</option>
</select>
</dd>
<% end %>
@@ -107,7 +107,7 @@
</header>
<% if @part && @part.mime_type %>
- <iframe seamless name="messageBody" src="?part=<%= Rack::Utils.escape(@part.mime_type) %>"></iframe>
+ <iframe seamless name="messageBody" src="?<%= part_query(@part.mime_type) %>"></iframe>
<% else %>
<p>
You are trying to preview an email that does not have any content.
diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb
index 0f9bf98737..81537d813e 100644
--- a/railties/lib/rails/test_help.rb
+++ b/railties/lib/rails/test_help.rb
@@ -12,7 +12,12 @@ require "rails/generators/test_case"
require "active_support/testing/autorun"
if defined?(ActiveRecord::Base)
- ActiveRecord::Migration.maintain_test_schema!
+ begin
+ ActiveRecord::Migration.maintain_test_schema!
+ rescue ActiveRecord::PendingMigrationError => e
+ puts e.to_s.strip
+ exit 1
+ end
module ActiveSupport
class TestCase
diff --git a/railties/lib/rails/test_unit/minitest_plugin.rb b/railties/lib/rails/test_unit/minitest_plugin.rb
index 8decdb0f4f..7a852d1109 100644
--- a/railties/lib/rails/test_unit/minitest_plugin.rb
+++ b/railties/lib/rails/test_unit/minitest_plugin.rb
@@ -6,7 +6,7 @@ require "shellwords"
module Minitest
class SuppressedSummaryReporter < SummaryReporter
# Disable extra failure output after a run if output is inline.
- def aggregated_results
+ def aggregated_results(*)
super unless options[:output_inline]
end
end
diff --git a/railties/lib/rails/test_unit/railtie.rb b/railties/lib/rails/test_unit/railtie.rb
index 9cc3f73a9c..443e743421 100644
--- a/railties/lib/rails/test_unit/railtie.rb
+++ b/railties/lib/rails/test_unit/railtie.rb
@@ -1,7 +1,7 @@
require "rails/test_unit/line_filtering"
if defined?(Rake.application) && Rake.application.top_level_tasks.grep(/^(default$|test(:|$))/).any?
- ENV["RAILS_ENV"] ||= "test"
+ ENV["RAILS_ENV"] ||= Rake.application.options.show_tasks ? "development" : "test"
end
module Rails
diff --git a/railties/lib/rails/test_unit/testing.rake b/railties/lib/rails/test_unit/testing.rake
index ef19bd7626..33408081f1 100644
--- a/railties/lib/rails/test_unit/testing.rake
+++ b/railties/lib/rails/test_unit/testing.rake
@@ -48,6 +48,7 @@ namespace :test do
Minitest.rake_run(["test/controllers", "test/mailers", "test/functional"])
end
+ desc "Run system tests only"
task system: "test:prepare" do
$: << "test"
Minitest.rake_run(["test/system"])
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index 07c6afed7f..06767167a9 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -1407,6 +1407,40 @@ module ApplicationTests
assert_match "config/database", err.message
end
+ test "loads database.yml using shared keys" do
+ app_file "config/database.yml", <<-YAML
+ shared:
+ username: bobby
+ adapter: sqlite3
+
+ development:
+ database: 'dev_db'
+ YAML
+
+ app "development"
+
+ ar_config = Rails.application.config.database_configuration
+ assert_equal "sqlite3", ar_config["development"]["adapter"]
+ assert_equal "bobby", ar_config["development"]["username"]
+ assert_equal "dev_db", ar_config["development"]["database"]
+ end
+
+ test "loads database.yml using shared keys for undefined environments" do
+ app_file "config/database.yml", <<-YAML
+ shared:
+ username: bobby
+ adapter: sqlite3
+ database: 'dev_db'
+ YAML
+
+ app "development"
+
+ ar_config = Rails.application.config.database_configuration
+ assert_equal "sqlite3", ar_config["development"]["adapter"]
+ assert_equal "bobby", ar_config["development"]["username"]
+ assert_equal "dev_db", ar_config["development"]["database"]
+ end
+
test "config.action_mailer.show_previews defaults to true in development" do
app "development"
diff --git a/railties/test/application/console_test.rb b/railties/test/application/console_test.rb
index 72f340df34..057d473870 100644
--- a/railties/test/application/console_test.rb
+++ b/railties/test/application/console_test.rb
@@ -136,9 +136,9 @@ class FullStackConsoleTest < ActiveSupport::TestCase
assert_output "> "
end
- def spawn_console
+ def spawn_console(options)
Process.spawn(
- "#{app_path}/bin/rails console --sandbox",
+ "#{app_path}/bin/rails console #{options}",
in: @slave, out: @slave, err: @slave
)
@@ -146,18 +146,26 @@ class FullStackConsoleTest < ActiveSupport::TestCase
end
def test_sandbox
- spawn_console
+ spawn_console("--sandbox")
write_prompt "Post.count", "=> 0"
write_prompt "Post.create"
write_prompt "Post.count", "=> 1"
@master.puts "quit"
- spawn_console
+ spawn_console("--sandbox")
write_prompt "Post.count", "=> 0"
write_prompt "Post.transaction { Post.create; raise }"
write_prompt "Post.count", "=> 0"
@master.puts "quit"
end
+
+ def test_environment_option_and_irb_option
+ spawn_console("test -- --verbose")
+
+ write_prompt "a = 1", "a = 1"
+ write_prompt "puts Rails.env", "puts Rails.env\r\ntest"
+ @master.puts "quit"
+ end
end
diff --git a/railties/test/application/mailer_previews_test.rb b/railties/test/application/mailer_previews_test.rb
index c3a360e5d4..f5c013dab6 100644
--- a/railties/test/application/mailer_previews_test.rb
+++ b/railties/test/application/mailer_previews_test.rb
@@ -485,6 +485,57 @@ module ApplicationTests
assert_match '<li><a href="/my_app/rails/mailers/notifier/foo">foo</a></li>', last_response.body
end
+ test "mailer preview receives query params" do
+ mailer "notifier", <<-RUBY
+ class Notifier < ActionMailer::Base
+ default from: "from@example.com"
+
+ def foo(name)
+ @name = name
+ mail to: "to@example.org"
+ end
+ end
+ RUBY
+
+ html_template "notifier/foo", <<-RUBY
+ <p>Hello, <%= @name %>!</p>
+ RUBY
+
+ text_template "notifier/foo", <<-RUBY
+ Hello, <%= @name %>!
+ RUBY
+
+ mailer_preview "notifier", <<-RUBY
+ class NotifierPreview < ActionMailer::Preview
+ def foo
+ Notifier.foo(params[:name] || "World")
+ end
+ end
+ RUBY
+
+ app("development")
+
+ get "/rails/mailers/notifier/foo.txt"
+ assert_equal 200, last_response.status
+ assert_match '<iframe seamless name="messageBody" src="?part=text%2Fplain">', last_response.body
+ assert_match '<option selected value="?part=text%2Fplain">', last_response.body
+ assert_match '<option value="?part=text%2Fhtml">', last_response.body
+
+ get "/rails/mailers/notifier/foo?part=text%2Fplain"
+ assert_equal 200, last_response.status
+ assert_match %r[Hello, World!], last_response.body
+
+ get "/rails/mailers/notifier/foo.html?name=Ruby"
+ assert_equal 200, last_response.status
+ assert_match '<iframe seamless name="messageBody" src="?name=Ruby&amp;part=text%2Fhtml">', last_response.body
+ assert_match '<option selected value="?name=Ruby&amp;part=text%2Fhtml">', last_response.body
+ assert_match '<option value="?name=Ruby&amp;part=text%2Fplain">', last_response.body
+
+ get "/rails/mailers/notifier/foo?name=Ruby&part=text%2Fhtml"
+ assert_equal 200, last_response.status
+ assert_match %r[<p>Hello, Ruby!</p>], last_response.body
+ end
+
test "plain text mailer preview with attachment" do
image_file "pixel.png", "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEWzIioca/JlAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJgggo="
diff --git a/railties/test/application/middleware/exceptions_test.rb b/railties/test/application/middleware/exceptions_test.rb
index cbb990f13b..fe07ad3cbe 100644
--- a/railties/test/application/middleware/exceptions_test.rb
+++ b/railties/test/application/middleware/exceptions_test.rb
@@ -100,6 +100,20 @@ module ApplicationTests
end
end
+ test "routing to an nonexistent controller when action_dispatch.show_exceptions and consider_all_requests_local are set shows diagnostics" do
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ resources :articles
+ end
+ RUBY
+
+ app.config.action_dispatch.show_exceptions = true
+ app.config.consider_all_requests_local = true
+
+ get "/articles"
+ assert_match "<title>Action Controller: Exception caught</title>", last_response.body
+ end
+
test "displays diagnostics message when exception raised in template that contains UTF-8" do
controller :foo, <<-RUBY
class FooController < ActionController::Base
diff --git a/railties/test/application/rake/migrations_test.rb b/railties/test/application/rake/migrations_test.rb
index 2c9770e147..51dfe2ef98 100644
--- a/railties/test/application/rake/migrations_test.rb
+++ b/railties/test/application/rake/migrations_test.rb
@@ -48,8 +48,14 @@ module ApplicationTests
output = `bin/rails db:migrate:up VERSION= 2>&1`
assert_match(/VERSION is required/, output)
+ output = `bin/rails db:migrate:up 2>&1`
+ assert_match(/VERSION is required/, output)
+
output = `bin/rails db:migrate:down VERSION= 2>&1`
assert_match(/VERSION is required - To go down one migration, use db:rollback/, output)
+
+ output = `bin/rails db:migrate:down 2>&1`
+ assert_match(/VERSION is required - To go down one migration, use db:rollback/, output)
end
end
diff --git a/railties/test/commands/server_test.rb b/railties/test/commands/server_test.rb
index 2d1f071969..7731d10d9b 100644
--- a/railties/test/commands/server_test.rb
+++ b/railties/test/commands/server_test.rb
@@ -140,6 +140,18 @@ class Rails::ServerTest < ActiveSupport::TestCase
end
def test_argument_precedence_over_environment_variable
+ switch_env "PORT", "1234" do
+ args = ["-p", "5678"]
+ options = parse_arguments(args)
+ assert_equal 5678, options[:Port]
+ end
+
+ switch_env "PORT", "1234" do
+ args = ["-p", "3000"]
+ options = parse_arguments(args)
+ assert_equal 3000, options[:Port]
+ end
+
switch_env "HOST", "1.2.3.4" do
args = ["-b", "127.0.0.1"]
options = parse_arguments(args)
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index 8a51beb380..ed8eea3243 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -569,9 +569,9 @@ class AppGeneratorTest < Rails::Generators::TestCase
run_generator
assert_file "config/environments/development.rb" do |content|
if RbConfig::CONFIG["host_os"] =~ /darwin|linux/
- assert_match(/^\s*config.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content)
+ assert_match(/^\s*config\.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content)
else
- assert_match(/^\s*# config.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content)
+ assert_match(/^\s*# config\.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content)
end
end
end
@@ -639,7 +639,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
assert_file "Gemfile" do |content|
assert_match(/gem 'web-console',\s+github: 'rails\/web-console'/, content)
- assert_no_match(/\Agem 'web-console', '>= 3.3.0'\z/, content)
+ assert_no_match(/\Agem 'web-console', '>= 3\.3\.0'\z/, content)
end
end
@@ -648,7 +648,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
assert_file "Gemfile" do |content|
assert_match(/gem 'web-console',\s+github: 'rails\/web-console'/, content)
- assert_no_match(/\Agem 'web-console', '>= 3.3.0'\z/, content)
+ assert_no_match(/\Agem 'web-console', '>= 3\.3\.0'\z/, content)
end
end
@@ -787,7 +787,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
def test_psych_gem
run_generator
- gem_regex = /gem 'psych',\s+'~> 2.0',\s+platforms: :rbx/
+ gem_regex = /gem 'psych',\s+'~> 2\.0',\s+platforms: :rbx/
assert_file "Gemfile" do |content|
if defined?(Rubinius)
@@ -870,7 +870,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
assert_gem "spring-watcher-listen"
assert_file "config/environments/development.rb" do |content|
- assert_match(/^\s*config.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content)
+ assert_match(/^\s*config\.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content)
end
end
@@ -880,7 +880,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
assert_file "config/environments/development.rb" do |content|
- assert_match(/^\s*# config.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content)
+ assert_match(/^\s*# config\.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content)
end
end
diff --git a/railties/test/generators/channel_generator_test.rb b/railties/test/generators/channel_generator_test.rb
index a1d54200ba..af68a9c49f 100644
--- a/railties/test/generators/channel_generator_test.rb
+++ b/railties/test/generators/channel_generator_test.rb
@@ -25,7 +25,7 @@ class ChannelGeneratorTest < Rails::Generators::TestCase
end
assert_file "app/assets/javascripts/channels/chat.js" do |channel|
- assert_match(/App.chat = App.cable.subscriptions.create\("ChatChannel/, channel)
+ assert_match(/App\.chat = App\.cable\.subscriptions\.create\("ChatChannel/, channel)
end
end
@@ -39,7 +39,7 @@ class ChannelGeneratorTest < Rails::Generators::TestCase
end
assert_file "app/assets/javascripts/channels/chat.js" do |channel|
- assert_match(/App.chat = App.cable.subscriptions.create\("ChatChannel/, channel)
+ assert_match(/App\.chat = App\.cable\.subscriptions\.create\("ChatChannel/, channel)
assert_match(/,\n\n speak/, channel)
assert_match(/,\n\n mute: function\(\) \{\n return this\.perform\('mute'\);\n \}\n\}\);/, channel)
end
diff --git a/railties/test/generators/create_migration_test.rb b/railties/test/generators/create_migration_test.rb
index ddd40e4d02..c7b0237f02 100644
--- a/railties/test/generators/create_migration_test.rb
+++ b/railties/test/generators/create_migration_test.rb
@@ -46,7 +46,7 @@ class CreateMigrationTest < Rails::Generators::TestCase
def test_invoke
create_migration
- assert_match(/create db\/migrate\/1_create_articles.rb\n/, invoke!)
+ assert_match(/create db\/migrate\/1_create_articles\.rb\n/, invoke!)
assert_file @migration.destination
end
@@ -67,7 +67,7 @@ class CreateMigrationTest < Rails::Generators::TestCase
migration_exists!
create_migration
- assert_match(/identical db\/migrate\/1_create_articles.rb\n/, invoke!)
+ assert_match(/identical db\/migrate\/1_create_articles\.rb\n/, invoke!)
assert @migration.identical?
end
@@ -84,8 +84,8 @@ class CreateMigrationTest < Rails::Generators::TestCase
create_migration(dest, force: true) { "different content" }
stdout = invoke!
- assert_match(/remove db\/migrate\/1_migration.rb\n/, stdout)
- assert_match(/create db\/migrate\/2_migration.rb\n/, stdout)
+ assert_match(/remove db\/migrate\/1_migration\.rb\n/, stdout)
+ assert_match(/create db\/migrate\/2_migration\.rb\n/, stdout)
assert_file @migration.destination
assert_no_file @existing_migration.destination
end
@@ -97,8 +97,8 @@ class CreateMigrationTest < Rails::Generators::TestCase
end
stdout = invoke!
- assert_match(/remove db\/migrate\/1_create_articles.rb\n/, stdout)
- assert_match(/create db\/migrate\/2_create_articles.rb\n/, stdout)
+ assert_match(/remove db\/migrate\/1_create_articles\.rb\n/, stdout)
+ assert_match(/create db\/migrate\/2_create_articles\.rb\n/, stdout)
assert_no_file @migration.destination
end
@@ -106,7 +106,7 @@ class CreateMigrationTest < Rails::Generators::TestCase
migration_exists!
create_migration(default_destination_path, {}, skip: true) { "different content" }
- assert_match(/skip db\/migrate\/2_create_articles.rb\n/, invoke!)
+ assert_match(/skip db\/migrate\/2_create_articles\.rb\n/, invoke!)
assert_no_file @migration.destination
end
@@ -114,7 +114,7 @@ class CreateMigrationTest < Rails::Generators::TestCase
migration_exists!
create_migration
- assert_match(/remove db\/migrate\/1_create_articles.rb\n/, revoke!)
+ assert_match(/remove db\/migrate\/1_create_articles\.rb\n/, revoke!)
assert_no_file @existing_migration.destination
end
@@ -122,13 +122,13 @@ class CreateMigrationTest < Rails::Generators::TestCase
migration_exists!
create_migration(default_destination_path, {}, pretend: true)
- assert_match(/remove db\/migrate\/1_create_articles.rb\n/, revoke!)
+ assert_match(/remove db\/migrate\/1_create_articles\.rb\n/, revoke!)
assert_file @existing_migration.destination
end
def test_revoke_when_no_exists
create_migration
- assert_match(/remove db\/migrate\/1_create_articles.rb\n/, revoke!)
+ assert_match(/remove db\/migrate\/1_create_articles\.rb\n/, revoke!)
end
end
diff --git a/railties/test/generators/mailer_generator_test.rb b/railties/test/generators/mailer_generator_test.rb
index 7d69d7470d..2ff03ea65e 100644
--- a/railties/test/generators/mailer_generator_test.rb
+++ b/railties/test/generators/mailer_generator_test.rb
@@ -9,13 +9,13 @@ class MailerGeneratorTest < Rails::Generators::TestCase
run_generator
assert_file "app/mailers/notifier_mailer.rb" do |mailer|
assert_match(/class NotifierMailer < ApplicationMailer/, mailer)
- assert_no_match(/default from: "from@example.com"/, mailer)
+ assert_no_match(/default from: "from@example\.com"/, mailer)
assert_no_match(/layout :mailer_notifier/, mailer)
end
assert_file "app/mailers/application_mailer.rb" do |mailer|
assert_match(/class ApplicationMailer < ActionMailer::Base/, mailer)
- assert_match(/default from: 'from@example.com'/, mailer)
+ assert_match(/default from: 'from@example\.com'/, mailer)
assert_match(/layout 'mailer'/, mailer)
end
end
@@ -48,11 +48,11 @@ class MailerGeneratorTest < Rails::Generators::TestCase
assert_match(/class NotifierMailerPreview < ActionMailer::Preview/, preview)
assert_match(/\# Preview this email at http:\/\/localhost\:3000\/rails\/mailers\/notifier_mailer\/foo/, preview)
assert_instance_method :foo, preview do |foo|
- assert_match(/NotifierMailer.foo/, foo)
+ assert_match(/NotifierMailer\.foo/, foo)
end
assert_match(/\# Preview this email at http:\/\/localhost\:3000\/rails\/mailers\/notifier_mailer\/bar/, preview)
assert_instance_method :bar, preview do |bar|
- assert_match(/NotifierMailer.bar/, bar)
+ assert_match(/NotifierMailer\.bar/, bar)
end
end
end
@@ -137,12 +137,12 @@ class MailerGeneratorTest < Rails::Generators::TestCase
assert_file "app/mailers/notifier_mailer.rb" do |mailer|
assert_instance_method :foo, mailer do |foo|
- assert_match(/mail to: "to@example.org"/, foo)
+ assert_match(/mail to: "to@example\.org"/, foo)
assert_match(/@greeting = "Hi"/, foo)
end
assert_instance_method :bar, mailer do |bar|
- assert_match(/mail to: "to@example.org"/, bar)
+ assert_match(/mail to: "to@example\.org"/, bar)
assert_match(/@greeting = "Hi"/, bar)
end
end
diff --git a/railties/test/generators/migration_generator_test.rb b/railties/test/generators/migration_generator_test.rb
index f46278cefe..6fe6e4ca07 100644
--- a/railties/test/generators/migration_generator_test.rb
+++ b/railties/test/generators/migration_generator_test.rb
@@ -204,8 +204,8 @@ class MigrationGeneratorTest < Rails::Generators::TestCase
assert_migration "db/migrate/#{migration}.rb" do |content|
assert_method :change, content do |change|
assert_match(/create_join_table :artists, :musics/, change)
- assert_match(/# t.index \[:artist_id, :music_id\]/, change)
- assert_match(/ t.index \[:music_id, :artist_id\], unique: true/, change)
+ assert_match(/# t\.index \[:artist_id, :music_id\]/, change)
+ assert_match(/ t\.index \[:music_id, :artist_id\], unique: true/, change)
end
end
end
@@ -265,8 +265,8 @@ class MigrationGeneratorTest < Rails::Generators::TestCase
assert_migration "db/migrate/#{migration}.rb" do |content|
assert_method :change, content do |change|
assert_match(/create_join_table :artist, :music/, change)
- assert_match(/# t.index \[:artist_id, :music_id\]/, change)
- assert_match(/ t.index \[:music_id, :artist_id\], unique: true/, change)
+ assert_match(/# t\.index \[:artist_id, :music_id\]/, change)
+ assert_match(/ t\.index \[:music_id, :artist_id\], unique: true/, change)
end
end
end
diff --git a/railties/test/generators/model_generator_test.rb b/railties/test/generators/model_generator_test.rb
index 99490af3a9..f41969fc46 100644
--- a/railties/test/generators/model_generator_test.rb
+++ b/railties/test/generators/model_generator_test.rb
@@ -10,7 +10,7 @@ class ModelGeneratorTest < Rails::Generators::TestCase
run_generator
assert_file "app/models/application_record.rb" do |record|
assert_match(/class ApplicationRecord < ActiveRecord::Base/, record)
- assert_match(/self.abstract_class = true/, record)
+ assert_match(/self\.abstract_class = true/, record)
end
end
@@ -253,7 +253,7 @@ class ModelGeneratorTest < Rails::Generators::TestCase
def test_migration_with_timestamps
run_generator
- assert_migration "db/migrate/create_accounts.rb", /t.timestamps/
+ assert_migration "db/migrate/create_accounts.rb", /t\.timestamps/
end
def test_migration_timestamps_are_skipped
@@ -261,7 +261,7 @@ class ModelGeneratorTest < Rails::Generators::TestCase
assert_migration "db/migrate/create_accounts.rb" do |m|
assert_method :change, m do |up|
- assert_no_match(/t.timestamps/, up)
+ assert_no_match(/t\.timestamps/, up)
end
end
end
@@ -269,19 +269,19 @@ class ModelGeneratorTest < Rails::Generators::TestCase
def test_migration_is_skipped_with_skip_option
run_generator
output = run_generator ["Account", "--skip"]
- assert_match %r{skip\s+db/migrate/\d+_create_accounts.rb}, output
+ assert_match %r{skip\s+db/migrate/\d+_create_accounts\.rb}, output
end
def test_migration_is_ignored_as_identical_with_skip_option
run_generator ["Account"]
output = run_generator ["Account", "--skip"]
- assert_match %r{identical\s+db/migrate/\d+_create_accounts.rb}, output
+ assert_match %r{identical\s+db/migrate/\d+_create_accounts\.rb}, output
end
def test_migration_is_skipped_on_skip_behavior
run_generator
output = run_generator ["Account"], behavior: :skip
- assert_match %r{skip\s+db/migrate/\d+_create_accounts.rb}, output
+ assert_match %r{skip\s+db/migrate/\d+_create_accounts\.rb}, output
end
def test_migration_error_is_not_shown_on_revoke
diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb
index afb37b6a99..e1aea7fa8a 100644
--- a/railties/test/generators/plugin_generator_test.rb
+++ b/railties/test/generators/plugin_generator_test.rb
@@ -48,7 +48,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase
run_generator [File.join(destination_root, "hyphenated-name")]
assert_no_file "hyphenated-name/lib/hyphenated-name.rb"
assert_no_file "hyphenated-name/lib/hyphenated_name.rb"
- assert_file "hyphenated-name/lib/hyphenated/name.rb", /module Hyphenated\n module Name\n # Your code goes here...\n end\nend/
+ assert_file "hyphenated-name/lib/hyphenated/name.rb", /module Hyphenated\n module Name\n # Your code goes here\.\.\.\n end\nend/
end
def test_correct_file_in_lib_folder_of_camelcase_plugin_name
@@ -152,7 +152,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase
run_generator [destination_root, "--skip-active-record"]
assert_file "bukkits.gemspec" do |contents|
- assert_no_match(/s.add_development_dependency "sqlite3"/, contents)
+ assert_no_match(/s\.add_development_dependency "sqlite3"/, contents)
end
end
@@ -308,14 +308,14 @@ class PluginGeneratorTest < Rails::Generators::TestCase
assert_file "my_hyphenated-name/app/helpers"
assert_file "my_hyphenated-name/app/mailers"
assert_file "my_hyphenated-name/bin/rails"
- assert_file "my_hyphenated-name/config/routes.rb", /Rails.application.routes.draw do/
+ assert_file "my_hyphenated-name/config/routes.rb", /Rails\.application\.routes\.draw do/
assert_file "my_hyphenated-name/lib/my_hyphenated/name/engine.rb", /module MyHyphenated\n module Name\n class Engine < ::Rails::Engine\n end\n end\nend/
assert_file "my_hyphenated-name/lib/my_hyphenated/name.rb", /require "my_hyphenated\/name\/engine"/
assert_file "my_hyphenated-name/bin/rails", /\.\.\/\.\.\/lib\/my_hyphenated\/name\/engine/
end
def test_being_quiet_while_creating_dummy_application
- assert_no_match(/create\s+config\/application.rb/, run_generator)
+ assert_no_match(/create\s+config\/application\.rb/, run_generator)
end
def test_create_mountable_application_with_mountable_option
@@ -323,13 +323,13 @@ class PluginGeneratorTest < Rails::Generators::TestCase
assert_file "app/assets/javascripts/bukkits"
assert_file "app/assets/stylesheets/bukkits"
assert_file "app/assets/images/bukkits"
- assert_file "config/routes.rb", /Bukkits::Engine.routes.draw do/
+ assert_file "config/routes.rb", /Bukkits::Engine\.routes\.draw do/
assert_file "lib/bukkits/engine.rb", /isolate_namespace Bukkits/
assert_file "test/dummy/config/routes.rb", /mount Bukkits::Engine => "\/bukkits"/
assert_file "app/controllers/bukkits/application_controller.rb", /module Bukkits\n class ApplicationController < ActionController::Base/
assert_file "app/models/bukkits/application_record.rb", /module Bukkits\n class ApplicationRecord < ActiveRecord::Base/
assert_file "app/jobs/bukkits/application_job.rb", /module Bukkits\n class ApplicationJob < ActiveJob::Base/
- assert_file "app/mailers/bukkits/application_mailer.rb", /module Bukkits\n class ApplicationMailer < ActionMailer::Base\n default from: 'from@example.com'\n layout 'mailer'\n/
+ assert_file "app/mailers/bukkits/application_mailer.rb", /module Bukkits\n class ApplicationMailer < ActionMailer::Base\n default from: 'from@example\.com'\n layout 'mailer'\n/
assert_file "app/helpers/bukkits/application_helper.rb", /module Bukkits\n module ApplicationHelper/
assert_file "app/views/layouts/bukkits/application.html.erb" do |contents|
assert_match "<title>Bukkits</title>", contents
@@ -350,15 +350,15 @@ class PluginGeneratorTest < Rails::Generators::TestCase
assert_file "hyphenated-name/app/assets/javascripts/hyphenated/name"
assert_file "hyphenated-name/app/assets/stylesheets/hyphenated/name"
assert_file "hyphenated-name/app/assets/images/hyphenated/name"
- assert_file "hyphenated-name/config/routes.rb", /Hyphenated::Name::Engine.routes.draw do/
- assert_file "hyphenated-name/lib/hyphenated/name/version.rb", /module Hyphenated\n module Name\n VERSION = '0.1.0'\n end\nend/
+ assert_file "hyphenated-name/config/routes.rb", /Hyphenated::Name::Engine\.routes\.draw do/
+ assert_file "hyphenated-name/lib/hyphenated/name/version.rb", /module Hyphenated\n module Name\n VERSION = '0\.1\.0'\n end\nend/
assert_file "hyphenated-name/lib/hyphenated/name/engine.rb", /module Hyphenated\n module Name\n class Engine < ::Rails::Engine\n isolate_namespace Hyphenated::Name\n end\n end\nend/
assert_file "hyphenated-name/lib/hyphenated/name.rb", /require "hyphenated\/name\/engine"/
assert_file "hyphenated-name/test/dummy/config/routes.rb", /mount Hyphenated::Name::Engine => "\/hyphenated-name"/
assert_file "hyphenated-name/app/controllers/hyphenated/name/application_controller.rb", /module Hyphenated\n module Name\n class ApplicationController < ActionController::Base\n protect_from_forgery with: :exception\n end\n end\nend\n/
assert_file "hyphenated-name/app/models/hyphenated/name/application_record.rb", /module Hyphenated\n module Name\n class ApplicationRecord < ActiveRecord::Base\n self\.abstract_class = true\n end\n end\nend/
assert_file "hyphenated-name/app/jobs/hyphenated/name/application_job.rb", /module Hyphenated\n module Name\n class ApplicationJob < ActiveJob::Base/
- assert_file "hyphenated-name/app/mailers/hyphenated/name/application_mailer.rb", /module Hyphenated\n module Name\n class ApplicationMailer < ActionMailer::Base\n default from: 'from@example.com'\n layout 'mailer'\n end\n end\nend/
+ assert_file "hyphenated-name/app/mailers/hyphenated/name/application_mailer.rb", /module Hyphenated\n module Name\n class ApplicationMailer < ActionMailer::Base\n default from: 'from@example\.com'\n layout 'mailer'\n end\n end\nend/
assert_file "hyphenated-name/app/helpers/hyphenated/name/application_helper.rb", /module Hyphenated\n module Name\n module ApplicationHelper\n end\n end\nend/
assert_file "hyphenated-name/app/views/layouts/hyphenated/name/application.html.erb" do |contents|
assert_match "<title>Hyphenated name</title>", contents
@@ -372,15 +372,15 @@ class PluginGeneratorTest < Rails::Generators::TestCase
assert_file "my_hyphenated-name/app/assets/javascripts/my_hyphenated/name"
assert_file "my_hyphenated-name/app/assets/stylesheets/my_hyphenated/name"
assert_file "my_hyphenated-name/app/assets/images/my_hyphenated/name"
- assert_file "my_hyphenated-name/config/routes.rb", /MyHyphenated::Name::Engine.routes.draw do/
- assert_file "my_hyphenated-name/lib/my_hyphenated/name/version.rb", /module MyHyphenated\n module Name\n VERSION = '0.1.0'\n end\nend/
+ assert_file "my_hyphenated-name/config/routes.rb", /MyHyphenated::Name::Engine\.routes\.draw do/
+ assert_file "my_hyphenated-name/lib/my_hyphenated/name/version.rb", /module MyHyphenated\n module Name\n VERSION = '0\.1\.0'\n end\nend/
assert_file "my_hyphenated-name/lib/my_hyphenated/name/engine.rb", /module MyHyphenated\n module Name\n class Engine < ::Rails::Engine\n isolate_namespace MyHyphenated::Name\n end\n end\nend/
assert_file "my_hyphenated-name/lib/my_hyphenated/name.rb", /require "my_hyphenated\/name\/engine"/
assert_file "my_hyphenated-name/test/dummy/config/routes.rb", /mount MyHyphenated::Name::Engine => "\/my_hyphenated-name"/
assert_file "my_hyphenated-name/app/controllers/my_hyphenated/name/application_controller.rb", /module MyHyphenated\n module Name\n class ApplicationController < ActionController::Base\n protect_from_forgery with: :exception\n end\n end\nend\n/
assert_file "my_hyphenated-name/app/models/my_hyphenated/name/application_record.rb", /module MyHyphenated\n module Name\n class ApplicationRecord < ActiveRecord::Base\n self\.abstract_class = true\n end\n end\nend/
assert_file "my_hyphenated-name/app/jobs/my_hyphenated/name/application_job.rb", /module MyHyphenated\n module Name\n class ApplicationJob < ActiveJob::Base/
- assert_file "my_hyphenated-name/app/mailers/my_hyphenated/name/application_mailer.rb", /module MyHyphenated\n module Name\n class ApplicationMailer < ActionMailer::Base\n default from: 'from@example.com'\n layout 'mailer'\n end\n end\nend/
+ assert_file "my_hyphenated-name/app/mailers/my_hyphenated/name/application_mailer.rb", /module MyHyphenated\n module Name\n class ApplicationMailer < ActionMailer::Base\n default from: 'from@example\.com'\n layout 'mailer'\n end\n end\nend/
assert_file "my_hyphenated-name/app/helpers/my_hyphenated/name/application_helper.rb", /module MyHyphenated\n module Name\n module ApplicationHelper\n end\n end\nend/
assert_file "my_hyphenated-name/app/views/layouts/my_hyphenated/name/application.html.erb" do |contents|
assert_match "<title>My hyphenated name</title>", contents
@@ -394,15 +394,15 @@ class PluginGeneratorTest < Rails::Generators::TestCase
assert_file "deep-hyphenated-name/app/assets/javascripts/deep/hyphenated/name"
assert_file "deep-hyphenated-name/app/assets/stylesheets/deep/hyphenated/name"
assert_file "deep-hyphenated-name/app/assets/images/deep/hyphenated/name"
- assert_file "deep-hyphenated-name/config/routes.rb", /Deep::Hyphenated::Name::Engine.routes.draw do/
- assert_file "deep-hyphenated-name/lib/deep/hyphenated/name/version.rb", /module Deep\n module Hyphenated\n module Name\n VERSION = '0.1.0'\n end\n end\nend/
+ assert_file "deep-hyphenated-name/config/routes.rb", /Deep::Hyphenated::Name::Engine\.routes\.draw do/
+ assert_file "deep-hyphenated-name/lib/deep/hyphenated/name/version.rb", /module Deep\n module Hyphenated\n module Name\n VERSION = '0\.1\.0'\n end\n end\nend/
assert_file "deep-hyphenated-name/lib/deep/hyphenated/name/engine.rb", /module Deep\n module Hyphenated\n module Name\n class Engine < ::Rails::Engine\n isolate_namespace Deep::Hyphenated::Name\n end\n end\n end\nend/
assert_file "deep-hyphenated-name/lib/deep/hyphenated/name.rb", /require "deep\/hyphenated\/name\/engine"/
assert_file "deep-hyphenated-name/test/dummy/config/routes.rb", /mount Deep::Hyphenated::Name::Engine => "\/deep-hyphenated-name"/
assert_file "deep-hyphenated-name/app/controllers/deep/hyphenated/name/application_controller.rb", /module Deep\n module Hyphenated\n module Name\n class ApplicationController < ActionController::Base\n protect_from_forgery with: :exception\n end\n end\n end\nend\n/
assert_file "deep-hyphenated-name/app/models/deep/hyphenated/name/application_record.rb", /module Deep\n module Hyphenated\n module Name\n class ApplicationRecord < ActiveRecord::Base\n self\.abstract_class = true\n end\n end\n end\nend/
assert_file "deep-hyphenated-name/app/jobs/deep/hyphenated/name/application_job.rb", /module Deep\n module Hyphenated\n module Name\n class ApplicationJob < ActiveJob::Base/
- assert_file "deep-hyphenated-name/app/mailers/deep/hyphenated/name/application_mailer.rb", /module Deep\n module Hyphenated\n module Name\n class ApplicationMailer < ActionMailer::Base\n default from: 'from@example.com'\n layout 'mailer'\n end\n end\n end\nend/
+ assert_file "deep-hyphenated-name/app/mailers/deep/hyphenated/name/application_mailer.rb", /module Deep\n module Hyphenated\n module Name\n class ApplicationMailer < ActionMailer::Base\n default from: 'from@example\.com'\n layout 'mailer'\n end\n end\n end\nend/
assert_file "deep-hyphenated-name/app/helpers/deep/hyphenated/name/application_helper.rb", /module Deep\n module Hyphenated\n module Name\n module ApplicationHelper\n end\n end\n end\nend/
assert_file "deep-hyphenated-name/app/views/layouts/deep/hyphenated/name/application.html.erb" do |contents|
assert_match "<title>Deep hyphenated name</title>", contents
@@ -413,16 +413,16 @@ class PluginGeneratorTest < Rails::Generators::TestCase
def test_creating_gemspec
run_generator
- assert_file "bukkits.gemspec", /s.name\s+= "bukkits"/
- assert_file "bukkits.gemspec", /s.files = Dir\["\{app,config,db,lib\}\/\*\*\/\*", "MIT-LICENSE", "Rakefile", "README\.md"\]/
- assert_file "bukkits.gemspec", /s.version\s+ = Bukkits::VERSION/
+ assert_file "bukkits.gemspec", /s\.name\s+= "bukkits"/
+ assert_file "bukkits.gemspec", /s\.files = Dir\["\{app,config,db,lib\}\/\*\*\/\*", "MIT-LICENSE", "Rakefile", "README\.md"\]/
+ assert_file "bukkits.gemspec", /s\.version\s+ = Bukkits::VERSION/
end
def test_usage_of_engine_commands
run_generator [destination_root, "--full"]
- assert_file "bin/rails", /ENGINE_PATH = File.expand_path\('..\/..\/lib\/bukkits\/engine', __FILE__\)/
- assert_file "bin/rails", /ENGINE_ROOT = File.expand_path\('..\/..', __FILE__\)/
- assert_file "bin/rails", %r|APP_PATH = File.expand_path\('../../test/dummy/config/application', __FILE__\)|
+ assert_file "bin/rails", /ENGINE_PATH = File\.expand_path\('\.\.\/\.\.\/lib\/bukkits\/engine', __FILE__\)/
+ assert_file "bin/rails", /ENGINE_ROOT = File\.expand_path\('\.\.\/\.\.', __FILE__\)/
+ assert_file "bin/rails", %r|APP_PATH = File\.expand_path\('\.\./\.\./test/dummy/config/application', __FILE__\)|
assert_file "bin/rails", /require 'rails\/all'/
assert_file "bin/rails", /require 'rails\/engine\/commands'/
end
@@ -469,7 +469,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase
run_generator
assert_file "test/dummy/config/environments/development.rb" do |contents|
- assert_match(/^\s*# config.file_watcher = ActiveSupport::EventedFileUpdateChecker/, contents)
+ assert_match(/^\s*# config\.file_watcher = ActiveSupport::EventedFileUpdateChecker/, contents)
end
end
@@ -687,7 +687,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase
assert_file "#{destination_root}/app/models/bukkits/application_record.rb" do |record|
assert_match(/module Bukkits/, record)
assert_match(/class ApplicationRecord < ActiveRecord::Base/, record)
- assert_match(/self.abstract_class = true/, record)
+ assert_match(/self\.abstract_class = true/, record)
end
end
diff --git a/railties/test/generators/shared_generator_tests.rb b/railties/test/generators/shared_generator_tests.rb
index cc9d3629e9..5e75879964 100644
--- a/railties/test/generators/shared_generator_tests.rb
+++ b/railties/test/generators/shared_generator_tests.rb
@@ -45,14 +45,14 @@ module SharedGeneratorTests
reserved_words = %w[application destroy plugin runner test]
reserved_words.each do |reserved|
content = capture(:stderr) { run_generator [File.join(destination_root, reserved)] }
- assert_match(/Invalid \w+ name #{reserved}. Please give a name which does not match one of the reserved rails words: application, destroy, plugin, runner, test\n/, content)
+ assert_match(/Invalid \w+ name #{reserved}\. Please give a name which does not match one of the reserved rails words: application, destroy, plugin, runner, test\n/, content)
end
end
def test_name_raises_an_error_if_name_already_used_constant
%w{ String Hash Class Module Set Symbol }.each do |ruby_class|
content = capture(:stderr) { run_generator [File.join(destination_root, ruby_class)] }
- assert_match(/Invalid \w+ name #{ruby_class}, constant #{ruby_class} is already in use. Please choose another \w+ name.\n/, content)
+ assert_match(/Invalid \w+ name #{ruby_class}, constant #{ruby_class} is already in use\. Please choose another \w+ name\.\n/, content)
end
end
diff --git a/railties/test/generators/test_runner_in_engine_test.rb b/railties/test/generators/test_runner_in_engine_test.rb
index 4b5fb3ba3f..680dc2608e 100644
--- a/railties/test/generators/test_runner_in_engine_test.rb
+++ b/railties/test/generators/test_runner_in_engine_test.rb
@@ -17,7 +17,7 @@ class TestRunnerInEngineTest < ActiveSupport::TestCase
create_test_file "post", pass: false
output = run_test_command("test/post_test.rb")
- expect = %r{Running:\n\nPostTest\nF\n\nFailure:\nPostTest#test_truth \[[^\]]+test/post_test.rb:6\]:\nwups!\n\nbin/rails test test/post_test.rb:4}
+ expect = %r{Running:\n\nPostTest\nF\n\nFailure:\nPostTest#test_truth \[[^\]]+test/post_test\.rb:6\]:\nwups!\n\nbin/rails test test/post_test\.rb:4}
assert_match expect, output
end
diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb
index 924503a522..2e742a005e 100644
--- a/railties/test/isolation/abstract_unit.rb
+++ b/railties/test/isolation/abstract_unit.rb
@@ -119,7 +119,7 @@ module TestHelpers
end
routes = File.read("#{app_path}/config/routes.rb")
- if routes =~ /(\n\s*end\s*)\Z/
+ if routes =~ /(\n\s*end\s*)\z/
File.open("#{app_path}/config/routes.rb", "w") do |f|
f.puts $` + "\nActiveSupport::Deprecation.silence { match ':controller(/:action(/:id))(.:format)', via: :all }\n" + $1
end
@@ -251,7 +251,7 @@ module TestHelpers
def add_to_config(str)
environment = File.read("#{app_path}/config/application.rb")
- if environment =~ /(\n\s*end\s*end\s*)\Z/
+ if environment =~ /(\n\s*end\s*end\s*)\z/
File.open("#{app_path}/config/application.rb", "w") do |f|
f.puts $` + "\n#{str}\n" + $1
end
@@ -260,7 +260,7 @@ module TestHelpers
def add_to_env_config(env, str)
environment = File.read("#{app_path}/config/environments/#{env}.rb")
- if environment =~ /(\n\s*end\s*)\Z/
+ if environment =~ /(\n\s*end\s*)\z/
File.open("#{app_path}/config/environments/#{env}.rb", "w") do |f|
f.puts $` + "\n#{str}\n" + $1
end
diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb
index 52d691b73b..e382a7a873 100644
--- a/railties/test/railties/engine_test.rb
+++ b/railties/test/railties/engine_test.rb
@@ -89,16 +89,16 @@ module RailtiesTest
assert File.exist?("#{app_path}/db/migrate/2_create_users.bukkits.rb")
assert File.exist?("#{app_path}/db/migrate/3_add_last_name_to_users.bukkits.rb")
- assert_match(/Copied migration 2_create_users.bukkits.rb from bukkits/, output)
- assert_match(/Copied migration 3_add_last_name_to_users.bukkits.rb from bukkits/, output)
- assert_match(/NOTE: Migration 3_create_sessions.rb from bukkits has been skipped/, output)
+ assert_match(/Copied migration 2_create_users\.bukkits\.rb from bukkits/, output)
+ assert_match(/Copied migration 3_add_last_name_to_users\.bukkits\.rb from bukkits/, output)
+ assert_match(/NOTE: Migration 3_create_sessions\.rb from bukkits has been skipped/, output)
assert_equal 3, Dir["#{app_path}/db/migrate/*.rb"].length
output = `bundle exec rake railties:install:migrations`.split("\n")
assert_no_match(/2_create_users/, output.join("\n"))
- bukkits_migration_order = output.index(output.detect { |o| /NOTE: Migration 3_create_sessions.rb from bukkits has been skipped/ =~ o })
+ bukkits_migration_order = output.index(output.detect { |o| /NOTE: Migration 3_create_sessions\.rb from bukkits has been skipped/ =~ o })
assert_not_nil bukkits_migration_order, "Expected migration to be skipped"
migrations_count = Dir["#{app_path}/db/migrate/*.rb"].length
@@ -135,8 +135,8 @@ module RailtiesTest
Dir.chdir(app_path) do
output = `bundle exec rake railties:install:migrations`.split("\n")
- assert_match(/Copied migration \d+_create_users.bukkits.rb from bukkits/, output.first)
- assert_match(/Copied migration \d+_create_blogs.blog_engine.rb from blog_engine/, output.last)
+ assert_match(/Copied migration \d+_create_users\.bukkits\.rb from bukkits/, output.first)
+ assert_match(/Copied migration \d+_create_blogs\.blog_engine\.rb from blog_engine/, output.last)
end
end
@@ -171,8 +171,8 @@ module RailtiesTest
Dir.chdir(app_path) do
output = `bundle exec rake railties:install:migrations`.split("\n")
- assert_match(/Copied migration \d+_create_users.core_engine.rb from core_engine/, output.first)
- assert_match(/Copied migration \d+_create_keys.api_engine.rb from api_engine/, output.last)
+ assert_match(/Copied migration \d+_create_users\.core_engine\.rb from core_engine/, output.first)
+ assert_match(/Copied migration \d+_create_keys\.api_engine\.rb from api_engine/, output.last)
end
end
@@ -202,7 +202,7 @@ module RailtiesTest
Dir.chdir(@plugin.path) do
output = `bundle exec rake app:bukkits:install:migrations`
assert File.exist?("#{app_path}/db/migrate/0_add_first_name_to_users.bukkits.rb")
- assert_match(/Copied migration 0_add_first_name_to_users.bukkits.rb from bukkits/, output)
+ assert_match(/Copied migration 0_add_first_name_to_users\.bukkits\.rb from bukkits/, output)
assert_equal 1, Dir["#{app_path}/db/migrate/*.rb"].length
end
end
diff --git a/railties/test/test_unit/reporter_test.rb b/railties/test/test_unit/reporter_test.rb
index e22c939981..98201394cd 100644
--- a/railties/test/test_unit/reporter_test.rb
+++ b/railties/test/test_unit/reporter_test.rb
@@ -16,7 +16,7 @@ class TestUnitReporterTest < ActiveSupport::TestCase
@reporter.record(failed_test)
@reporter.report
- assert_match %r{^bin/rails test .*test/test_unit/reporter_test.rb:\d+$}, @output.string
+ assert_match %r{^bin/rails test .*test/test_unit/reporter_test\.rb:\d+$}, @output.string
assert_rerun_snippet_count 1
end
@@ -52,7 +52,7 @@ class TestUnitReporterTest < ActiveSupport::TestCase
@reporter.record(failed_test)
@reporter.report
- assert_match %r{^bin/test .*test/test_unit/reporter_test.rb:\d+$}, @output.string
+ assert_match %r{^bin/test .*test/test_unit/reporter_test\.rb:\d+$}, @output.string
ensure
Rails::TestUnitReporter.executable = original_executable
end
@@ -62,7 +62,7 @@ class TestUnitReporterTest < ActiveSupport::TestCase
@reporter.record(failed_test)
@reporter.report
- expect = %r{\AF\n\nFailure:\nTestUnitReporterTest::ExampleTest#woot \[[^\]]+\]:\nboo\n\nbin/rails test test/test_unit/reporter_test.rb:\d+\n\n\z}
+ expect = %r{\AF\n\nFailure:\nTestUnitReporterTest::ExampleTest#woot \[[^\]]+\]:\nboo\n\nbin/rails test test/test_unit/reporter_test\.rb:\d+\n\n\z}
assert_match expect, @output.string
end
@@ -70,7 +70,7 @@ class TestUnitReporterTest < ActiveSupport::TestCase
@reporter.record(errored_test)
@reporter.report
- expect = %r{\AE\n\nError:\nTestUnitReporterTest::ExampleTest#woot:\nArgumentError: wups\n No backtrace\n\nbin/rails test .*test/test_unit/reporter_test.rb:\d+\n\n\z}
+ expect = %r{\AE\n\nError:\nTestUnitReporterTest::ExampleTest#woot:\nArgumentError: wups\n No backtrace\n\nbin/rails test .*test/test_unit/reporter_test\.rb:\d+\n\n\z}
assert_match expect, @output.string
end
@@ -79,7 +79,7 @@ class TestUnitReporterTest < ActiveSupport::TestCase
verbose.record(skipped_test)
verbose.report
- expect = %r{\ATestUnitReporterTest::ExampleTest#woot = 10\.00 s = S\n\n\nSkipped:\nTestUnitReporterTest::ExampleTest#woot \[[^\]]+\]:\nskipchurches, misstemples\n\nbin/rails test test/test_unit/reporter_test.rb:\d+\n\n\z}
+ expect = %r{\ATestUnitReporterTest::ExampleTest#woot = 10\.00 s = S\n\n\nSkipped:\nTestUnitReporterTest::ExampleTest#woot \[[^\]]+\]:\nskipchurches, misstemples\n\nbin/rails test test/test_unit/reporter_test\.rb:\d+\n\n\z}
assert_match expect, @output.string
end