aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--.rubocop.yml2
-rw-r--r--.travis.yml13
-rw-r--r--Gemfile9
-rw-r--r--Gemfile.lock74
-rw-r--r--actioncable/CHANGELOG.md6
-rw-r--r--actioncable/lib/action_cable/connection/client_socket.rb4
-rw-r--r--actioncable/lib/action_cable/connection/subscriptions.rb2
-rw-r--r--actioncable/lib/action_cable/subscription_adapter.rb1
-rw-r--r--actioncable/lib/action_cable/subscription_adapter/channel_prefix.rb26
-rw-r--r--actioncable/lib/action_cable/subscription_adapter/evented_redis.rb2
-rw-r--r--actioncable/lib/action_cable/subscription_adapter/redis.rb2
-rw-r--r--actioncable/test/channel/periodic_timers_test.rb9
-rw-r--r--actioncable/test/subscription_adapter/channel_prefix.rb36
-rw-r--r--actioncable/test/subscription_adapter/evented_redis_test.rb2
-rw-r--r--actioncable/test/subscription_adapter/redis_test.rb2
-rw-r--r--actionmailer/CHANGELOG.md9
-rw-r--r--actionmailer/lib/action_mailer.rb1
-rw-r--r--actionmailer/lib/action_mailer/base.rb15
-rw-r--r--actionmailer/lib/action_mailer/parameterized.rb152
-rw-r--r--actionmailer/lib/action_mailer/test_case.rb4
-rw-r--r--actionmailer/lib/action_mailer/test_helper.rb4
-rw-r--r--actionmailer/test/abstract_unit.rb18
-rw-r--r--actionmailer/test/mail_helper_test.rb10
-rw-r--r--actionmailer/test/mailers/params_mailer.rb11
-rw-r--r--actionmailer/test/parameterized_test.rb55
-rw-r--r--actionmailer/test/test_helper_test.rb18
-rw-r--r--actionpack/lib/abstract_controller/base.rb2
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb4
-rw-r--r--actionpack/lib/action_controller/renderer.rb3
-rw-r--r--actionpack/lib/action_controller/test_case.rb6
-rw-r--r--actionpack/lib/action_dispatch/http/mime_type.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/parameters.rb2
-rw-r--r--actionpack/lib/action_dispatch/journey/visitors.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/cookies.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/remote_ip.rb4
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/abstract_store.rb4
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb1
-rw-r--r--actionpack/lib/action_dispatch/routing/redirection.rb8
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb4
-rw-r--r--actionpack/test/abstract_unit.rb18
-rw-r--r--actionpack/test/controller/filters_test.rb2
-rw-r--r--actionpack/test/controller/parameters/nested_parameters_permit_test.rb5
-rw-r--r--actionpack/test/controller/parameters/parameters_permit_test.rb17
-rw-r--r--actionpack/test/controller/render_test.rb1
-rw-r--r--actionpack/test/controller/request/test_request_test.rb20
-rw-r--r--actionpack/test/controller/test_case_test.rb14
-rw-r--r--actionpack/test/dispatch/cookies_test.rb9
-rw-r--r--actionpack/test/dispatch/prefix_generation_test.rb86
-rw-r--r--actionpack/test/dispatch/request_test.rb8
-rw-r--r--actionpack/test/dispatch/session/cookie_store_test.rb2
-rw-r--r--actionpack/test/dispatch/ssl_test.rb8
-rw-r--r--actionpack/test/lib/controller/fake_models.rb4
-rw-r--r--actionview/CHANGELOG.md20
-rw-r--r--actionview/actionview.gemspec4
-rw-r--r--actionview/app/assets/javascripts/utils/event.coffee2
-rw-r--r--actionview/lib/action_view/base.rb2
-rw-r--r--actionview/lib/action_view/helpers/asset_tag_helper.rb2
-rw-r--r--actionview/lib/action_view/helpers/asset_url_helper.rb12
-rw-r--r--actionview/lib/action_view/helpers/cache_helper.rb2
-rw-r--r--actionview/lib/action_view/helpers/number_helper.rb2
-rw-r--r--actionview/lib/action_view/helpers/output_safety_helper.rb4
-rw-r--r--actionview/lib/action_view/helpers/sanitize_helper.rb10
-rw-r--r--actionview/lib/action_view/helpers/text_helper.rb2
-rw-r--r--actionview/lib/action_view/helpers/url_helper.rb2
-rw-r--r--actionview/lib/action_view/renderer/partial_renderer.rb8
-rw-r--r--actionview/lib/action_view/renderer/streaming_template_renderer.rb2
-rw-r--r--actionview/lib/action_view/rendering.rb6
-rw-r--r--actionview/lib/action_view/template.rb2
-rw-r--r--actionview/lib/action_view/template/handlers/builder.rb2
-rw-r--r--actionview/lib/action_view/template/handlers/erb.rb77
-rw-r--r--actionview/lib/action_view/template/handlers/erb/erubi.rb81
-rw-r--r--actionview/lib/action_view/template/handlers/erb/erubis.rb80
-rw-r--r--actionview/lib/action_view/template/resolver.rb4
-rw-r--r--actionview/test/abstract_unit.rb18
-rw-r--r--actionview/test/actionpack/controller/render_test.rb4
-rw-r--r--actionview/test/activerecord/form_helper_activerecord_test.rb2
-rw-r--r--actionview/test/activerecord/render_partial_with_record_identification_test.rb2
-rw-r--r--actionview/test/fixtures/test/render_file_instance_variable.erb1
-rw-r--r--actionview/test/lib/controller/fake_models.rb9
-rw-r--r--actionview/test/template/active_model_helper_test.rb2
-rw-r--r--actionview/test/template/atom_feed_helper_test.rb2
-rw-r--r--actionview/test/template/compiled_templates_test.rb4
-rw-r--r--actionview/test/template/erb/deprecated_erubis_implementation_test.rb11
-rw-r--r--actionview/test/template/erb/helper.rb2
-rw-r--r--actionview/test/template/erb_util_test.rb7
-rw-r--r--actionview/test/template/form_collections_helper_test.rb3
-rw-r--r--actionview/test/template/form_helper/form_with_test.rb382
-rw-r--r--actionview/test/template/form_helper_test.rb414
-rw-r--r--actionview/test/template/form_options_helper_test.rb236
-rw-r--r--actionview/test/template/output_safety_helper_test.rb27
-rw-r--r--actionview/test/template/render_test.rb10
-rw-r--r--actionview/test/template/text_test.rb16
-rw-r--r--actionview/test/template/url_helper_test.rb2
-rw-r--r--actionview/test/ujs/public/test/settings.js2
-rw-r--r--activejob/lib/active_job/queue_adapter.rb1
-rw-r--r--activejob/lib/active_job/test_helper.rb36
-rw-r--r--activejob/test/cases/test_helper_test.rb21
-rw-r--r--activejob/test/support/integration/adapters/backburner.rb4
-rw-r--r--activemodel/lib/active_model/type/decimal.rb3
-rw-r--r--activemodel/test/cases/errors_test.rb1
-rw-r--r--activemodel/test/cases/helper.rb18
-rw-r--r--activerecord/CHANGELOG.md26
-rw-r--r--activerecord/lib/active_record/associations/has_one_association.rb2
-rw-r--r--activerecord/lib/active_record/associations/join_dependency.rb4
-rw-r--r--activerecord/lib/active_record/associations/join_dependency/join_association.rb8
-rw-r--r--activerecord/lib/active_record/attribute_methods/serialization.rb2
-rw-r--r--activerecord/lib/active_record/coders/yaml_column.rb13
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/quoting.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb16
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb8
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/schema_definitions.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_definitions.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb10
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb46
-rw-r--r--activerecord/lib/active_record/core.rb2
-rw-r--r--activerecord/lib/active_record/counter_cache.rb3
-rw-r--r--activerecord/lib/active_record/migration.rb10
-rw-r--r--activerecord/lib/active_record/migration/compatibility.rb5
-rw-r--r--activerecord/lib/active_record/persistence.rb18
-rw-r--r--activerecord/lib/active_record/reflection.rb78
-rw-r--r--activerecord/lib/active_record/schema.rb2
-rw-r--r--activerecord/lib/active_record/store.rb6
-rw-r--r--activerecord/lib/active_record/tasks/database_tasks.rb4
-rw-r--r--activerecord/lib/rails/generators/active_record/migration.rb8
-rw-r--r--activerecord/lib/rails/generators/active_record/migration/migration_generator.rb2
-rw-r--r--activerecord/lib/rails/generators/active_record/model/model_generator.rb2
-rw-r--r--activerecord/test/cases/adapter_test.rb99
-rw-r--r--activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb4
-rw-r--r--activerecord/test/cases/adapters/postgresql/connection_test.rb4
-rw-r--r--activerecord/test/cases/adapters/postgresql/infinity_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/numbers_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/uuid_test.rb55
-rw-r--r--activerecord/test/cases/adapters/sqlite3/copy_table_test.rb7
-rw-r--r--activerecord/test/cases/associations/eager_test.rb29
-rw-r--r--activerecord/test/cases/associations/has_one_associations_test.rb2
-rw-r--r--activerecord/test/cases/associations/inverse_associations_test.rb2
-rw-r--r--activerecord/test/cases/attribute_methods/read_test.rb2
-rw-r--r--activerecord/test/cases/coders/yaml_column_test.rb24
-rw-r--r--activerecord/test/cases/connection_adapters/connection_handler_test.rb35
-rw-r--r--activerecord/test/cases/connection_pool_test.rb2
-rw-r--r--activerecord/test/cases/counter_cache_test.rb9
-rw-r--r--activerecord/test/cases/date_time_precision_test.rb2
-rw-r--r--activerecord/test/cases/migration/compatibility_test.rb5
-rw-r--r--activerecord/test/cases/migration/foreign_key_test.rb34
-rw-r--r--activerecord/test/cases/migration/references_foreign_key_test.rb22
-rw-r--r--activerecord/test/cases/migration_test.rb12
-rw-r--r--activerecord/test/cases/migrator_test.rb3
-rw-r--r--activerecord/test/cases/nested_attributes_with_callbacks_test.rb4
-rw-r--r--activerecord/test/cases/persistence_test.rb16
-rw-r--r--activerecord/test/cases/query_cache_test.rb4
-rw-r--r--activerecord/test/cases/reflection_test.rb20
-rw-r--r--activerecord/test/cases/relation/mutation_test.rb2
-rw-r--r--activerecord/test/cases/relation_test.rb2
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb2
-rw-r--r--activerecord/test/cases/serialized_attribute_test.rb14
-rw-r--r--activerecord/test/cases/time_precision_test.rb2
-rw-r--r--activerecord/test/cases/transactions_test.rb6
-rw-r--r--activerecord/test/cases/view_test.rb4
-rw-r--r--activerecord/test/schema/schema.rb12
-rw-r--r--activerecord/test/schema/sqlite_specific_schema.rb18
-rw-r--r--activesupport/CHANGELOG.md51
-rwxr-xr-xactivesupport/bin/generate_tables4
-rw-r--r--activesupport/lib/active_support/array_inquirer.rb4
-rw-r--r--activesupport/lib/active_support/backtrace_cleaner.rb2
-rw-r--r--activesupport/lib/active_support/cache.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/array/access.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/enumerable.rb14
-rw-r--r--activesupport/lib/active_support/core_ext/integer/time.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/load_error.rb12
-rw-r--r--activesupport/lib/active_support/core_ext/module/introspection.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/numeric/conversions.rb31
-rw-r--r--activesupport/lib/active_support/core_ext/numeric/time.rb12
-rw-r--r--activesupport/lib/active_support/core_ext/string/output_safety.rb18
-rw-r--r--activesupport/lib/active_support/deprecation/proxy_wrappers.rb5
-rw-r--r--activesupport/lib/active_support/duration.rb99
-rw-r--r--activesupport/lib/active_support/evented_file_update_checker.rb2
-rw-r--r--activesupport/lib/active_support/execution_wrapper.rb4
-rw-r--r--activesupport/lib/active_support/inflector/transliterate.rb2
-rw-r--r--activesupport/lib/active_support/multibyte/unicode.rb26
-rw-r--r--activesupport/lib/active_support/number_helper.rb2
-rw-r--r--activesupport/lib/active_support/string_inquirer.rb2
-rw-r--r--activesupport/lib/active_support/values/unicode_tables.datbin1068675 -> 1116857 bytes
-rw-r--r--activesupport/test/abstract_unit.rb20
-rw-r--r--activesupport/test/array_inquirer_test.rb20
-rw-r--r--activesupport/test/core_ext/duration_test.rb38
-rw-r--r--activesupport/test/core_ext/kernel_test.rb16
-rw-r--r--activesupport/test/core_ext/module/introspection_test.rb37
-rw-r--r--activesupport/test/core_ext/module_test.rb36
-rw-r--r--activesupport/test/core_ext/numeric_ext_test.rb14
-rw-r--r--activesupport/test/core_ext/object/duplicable_test.rb7
-rw-r--r--activesupport/test/core_ext/string_ext_test.rb2
-rw-r--r--activesupport/test/dependencies_test.rb20
-rw-r--r--activesupport/test/deprecation_test.rb10
-rw-r--r--activesupport/test/evented_file_update_checker_test.rb5
-rw-r--r--activesupport/test/inflector_test.rb10
-rw-r--r--activesupport/test/json/decoding_test.rb9
-rw-r--r--activesupport/test/json/encoding_test_cases.rb2
-rw-r--r--activesupport/test/multibyte_test_helpers.rb2
-rw-r--r--activesupport/test/number_helper_i18n_test.rb1
-rw-r--r--activesupport/test/string_inquirer_test.rb21
-rw-r--r--activesupport/test/time_travel_test.rb3
-rw-r--r--activesupport/test/transliterate_test.rb18
-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/source/action_cable_overview.md27
-rw-r--r--guides/source/action_mailer_basics.md8
-rw-r--r--guides/source/contributing_to_ruby_on_rails.md12
-rw-r--r--guides/source/debugging_rails_applications.md2
-rw-r--r--guides/source/i18n.md2
-rw-r--r--guides/source/initialization.md2
-rw-r--r--railties/CHANGELOG.md17
-rw-r--r--railties/lib/rails/application.rb8
-rw-r--r--railties/lib/rails/application/bootstrap.rb4
-rw-r--r--railties/lib/rails/application/configuration.rb2
-rw-r--r--railties/lib/rails/command.rb6
-rw-r--r--railties/lib/rails/command/actions.rb5
-rw-r--r--railties/lib/rails/command/base.rb2
-rw-r--r--railties/lib/rails/commands/help/USAGE16
-rw-r--r--railties/lib/rails/commands/server/server_command.rb8
-rw-r--r--railties/lib/rails/engine.rb8
-rw-r--r--railties/lib/rails/engine/commands.rb17
-rw-r--r--railties/lib/rails/generators.rb2
-rw-r--r--railties/lib/rails/generators/actions/create_migration.rb4
-rw-r--r--railties/lib/rails/generators/base.rb4
-rw-r--r--railties/lib/rails/generators/rails/app/app_generator.rb11
-rw-r--r--railties/lib/rails/generators/rails/app/templates/Gemfile2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/cable.yml1
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml25
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt2
-rw-r--r--railties/lib/rails/generators/rails/plugin/plugin_generator.rb7
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt1
-rw-r--r--railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb1
-rw-r--r--railties/lib/rails/generators/resource_helpers.rb2
-rw-r--r--railties/lib/rails/info.rb6
-rw-r--r--railties/lib/rails/paths.rb4
-rw-r--r--railties/lib/rails/source_annotation_extractor.rb2
-rw-r--r--railties/lib/rails/tasks.rb1
-rw-r--r--railties/lib/rails/tasks/framework.rake2
-rw-r--r--railties/lib/rails/tasks/routes.rake2
-rw-r--r--railties/lib/rails/tasks/yarn.rake11
-rw-r--r--railties/lib/rails/test_unit/minitest_plugin.rb5
-rw-r--r--railties/test/abstract_unit.rb18
-rw-r--r--railties/test/application/bin_setup_test.rb5
-rw-r--r--railties/test/application/configuration/custom_test.rb17
-rw-r--r--railties/test/application/configuration_test.rb6
-rw-r--r--railties/test/application/rake/dbs_test.rb4
-rw-r--r--railties/test/application/test_runner_test.rb11
-rw-r--r--railties/test/commands/server_test.rb6
-rw-r--r--railties/test/engine/commands_tasks_test.rb24
-rw-r--r--railties/test/engine/commands_test.rb96
-rw-r--r--railties/test/generators/app_generator_test.rb10
-rw-r--r--railties/test/generators/migration_generator_test.rb11
-rw-r--r--railties/test/generators/model_generator_test.rb11
-rw-r--r--railties/test/generators/plugin_generator_test.rb1
-rw-r--r--railties/test/generators/plugin_test_runner_test.rb11
-rw-r--r--railties/test/generators/shared_generator_tests.rb1
-rw-r--r--railties/test/rack_logger_test.rb2
266 files changed, 2638 insertions, 1507 deletions
diff --git a/.gitignore b/.gitignore
index 9268977c2f..4961ad588f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@
.Gemfile
.ruby-version
+.byebug_history
debug.log
pkg
/.bundle
diff --git a/.rubocop.yml b/.rubocop.yml
index 629f5d86ea..a9ced4c0a5 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -113,7 +113,7 @@ Style/UnneededPercentQ:
# assignments, where it should be aligned with the LHS.
Lint/EndAlignment:
Enabled: true
- AlignWith: variable
+ EnforcedStyleAlignWith: variable
# Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
Lint/RequireParentheses:
diff --git a/.travis.yml b/.travis.yml
index 0c59604ff4..ff72542025 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -17,6 +17,7 @@ addons:
bundler_args: --without test --jobs 3 --retry 3
before_install:
- "rm ${BUNDLE_GEMFILE}.lock"
+ - "gem update --system"
- "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"
@@ -63,6 +64,12 @@ matrix:
- memcached
- redis
- rabbitmq
+ - rvm: 2.4.0
+ env: "GEM=aj:integration"
+ services:
+ - memcached
+ - redis
+ - rabbitmq
- rvm: ruby-head
env: "GEM=aj:integration"
services:
@@ -74,17 +81,17 @@ matrix:
- "GEM=ar:mysql2 MYSQL=mariadb"
addons:
mariadb: 10.0
- - rvm: jruby-9.1.6.0
+ - rvm: jruby-9.1.7.0
jdk: oraclejdk8
env:
- "GEM=ap"
- - rvm: jruby-9.1.6.0
+ - rvm: jruby-9.1.7.0
jdk: oraclejdk8
env:
- "GEM=am,aj"
allow_failures:
- rvm: ruby-head
- - rvm: jruby-9.1.6.0
+ - rvm: jruby-9.1.7.0
- env: "GEM=ac:integration"
fast_finish: true
diff --git a/Gemfile b/Gemfile
index f529677fbb..073a5b9c27 100644
--- a/Gemfile
+++ b/Gemfile
@@ -37,7 +37,7 @@ gem "rb-inotify", github: "matthewd/rb-inotify", branch: "close-handling", requi
# Explicitly avoid 1.x that doesn't support Ruby 2.4+
gem "json", ">= 2.0.0"
-gem "rubocop", require: false
+gem "rubocop", ">= 0.47", require: false
group :doc do
gem "sdoc", "1.0.0.rc1"
@@ -51,13 +51,16 @@ gem "dalli", ">= 2.2.1"
gem "listen", ">= 3.0.5", "< 3.2", require: false
gem "libxml-ruby", platforms: :ruby
+# Action View. For testing Erubis handler deprecation.
+gem "erubis", "~> 2.7.0", require: false
+
# Active Job.
group :job do
gem "resque", github: "resque/resque", require: false
gem "resque-scheduler", require: false
gem "sidekiq", require: false
gem "sucker_punch", require: false
- gem "delayed_job", require: false, github: "collectiveidea/delayed_job"
+ gem "delayed_job", require: false
gem "queue_classic", github: "QueueClassic/queue_classic", branch: "master", require: false, platforms: :ruby
gem "sneakers", require: false
gem "que", require: false
@@ -65,7 +68,7 @@ group :job do
#TODO: add qu after it support Rails 5.1
# gem 'qu-rails', github: "bkeepers/qu", branch: "master", require: false
gem "qu-redis", require: false
- gem "delayed_job_active_record", require: false, github: "collectiveidea/delayed_job_active_record"
+ gem "delayed_job_active_record", require: false
gem "sequel", require: false
end
diff --git a/Gemfile.lock b/Gemfile.lock
index 2c48518802..049d7320b8 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -7,21 +7,6 @@ GIT
pg (>= 0.17, < 0.20)
GIT
- remote: https://github.com/collectiveidea/delayed_job.git
- revision: e3772d4f0c8470d0fcba00c86ca3bc4f5e876830
- specs:
- delayed_job (4.1.2)
- activesupport (>= 3.0, < 5.1)
-
-GIT
- remote: https://github.com/collectiveidea/delayed_job_active_record.git
- revision: 36f434c4fd660e8f11ce932be117e9c71dde7212
- specs:
- delayed_job_active_record (4.1.1)
- activerecord (>= 3.0, < 5.1)
- delayed_job (>= 3.0, < 5)
-
-GIT
remote: https://github.com/matthewd/rb-inotify.git
revision: 90553518d1fb79aedc98a3036c59bd2b6731ac40
branch: close-handling
@@ -40,7 +25,7 @@ GIT
GIT
remote: https://github.com/rails/arel.git
- revision: b26638ef041953992010590b31615c519fa0ea7d
+ revision: ab109d3bf1c773da5e78ddc93bb6b55aebbb1c2a
specs:
arel (8.0.0)
@@ -78,9 +63,9 @@ PATH
actionview (5.1.0.alpha)
activesupport (= 5.1.0.alpha)
builder (~> 3.1)
- erubis (~> 2.7.0)
+ erubi (~> 1.4)
rails-dom-testing (~> 2.0)
- rails-html-sanitizer (~> 1.0, >= 1.0.2)
+ rails-html-sanitizer (~> 1.0, >= 1.0.3)
activejob (5.1.0.alpha)
activesupport (= 5.1.0.alpha)
globalid (>= 0.3.6)
@@ -119,7 +104,7 @@ GEM
specs:
addressable (2.5.0)
public_suffix (~> 2.0, >= 2.0.2)
- amq-protocol (2.0.1)
+ amq-protocol (2.1.0)
ast (2.3.0)
backburner (1.3.1)
beaneater (~> 1.0)
@@ -147,7 +132,7 @@ GEM
childprocess
faraday
selenium-webdriver
- builder (3.2.2)
+ builder (3.2.3)
bunny (2.6.2)
amq-protocol (>= 2.0.1)
byebug (9.0.6)
@@ -167,6 +152,11 @@ GEM
daemons (1.2.4)
dalli (2.7.6)
dante (0.2.0)
+ delayed_job (4.1.2)
+ activesupport (>= 3.0, < 5.1)
+ delayed_job_active_record (4.1.1)
+ activerecord (>= 3.0, < 5.1)
+ delayed_job (>= 3.0, < 5)
em-hiredis (0.3.1)
eventmachine (~> 1.0)
hiredis (~> 0.6.0)
@@ -178,13 +168,14 @@ GEM
http_parser.rb (>= 0.6.0)
em-socksify (0.3.1)
eventmachine (>= 1.0.0.beta.4)
+ erubi (1.4.0)
erubis (2.7.0)
event_emitter (0.2.5)
eventmachine (1.2.1)
eventmachine (1.2.1-x64-mingw32)
eventmachine (1.2.1-x86-mingw32)
execjs (2.7.0)
- faraday (0.10.0)
+ faraday (0.11.0)
multipart-post (>= 1.2, < 3)
faye (1.2.3)
cookiejar (>= 0.3.0)
@@ -197,19 +188,17 @@ GEM
faye-websocket (0.10.5)
eventmachine (>= 0.12.0)
websocket-driver (>= 0.5.1)
- ffi (1.9.14)
- ffi (1.9.14-x64-mingw32)
- ffi (1.9.14-x86-mingw32)
+ ffi (1.9.17)
globalid (0.3.7)
activesupport (>= 4.1.0)
hiredis (0.6.1)
http_parser.rb (0.6.0)
i18n (0.7.0)
- jquery-rails (4.2.1)
+ jquery-rails (4.2.2)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
- json (2.0.2)
+ json (2.0.3)
kindlerb (1.2.0)
mustache
nokogiri
@@ -239,11 +228,11 @@ GEM
mysql2 (0.4.5-x64-mingw32)
mysql2 (0.4.5-x86-mingw32)
nio4r (2.0.0)
- nokogiri (1.7.0)
+ nokogiri (1.7.0.1)
mini_portile2 (~> 2.1.0)
- nokogiri (1.7.0-x64-mingw32)
+ nokogiri (1.7.0.1-x64-mingw32)
mini_portile2 (~> 2.1.0)
- nokogiri (1.7.0-x86-mingw32)
+ nokogiri (1.7.0.1-x86-mingw32)
mini_portile2 (~> 2.1.0)
parser (2.3.3.1)
ast (~> 2.2)
@@ -252,8 +241,8 @@ GEM
pg (0.19.0-x86-mingw32)
powerpack (0.1.1)
psych (2.2.2)
- public_suffix (2.0.4)
- puma (3.6.2)
+ public_suffix (2.0.5)
+ puma (3.7.0)
qu (0.2.0)
multi_json
qu-redis (0.2.0)
@@ -274,7 +263,7 @@ GEM
nokogiri (~> 1.6)
rails-html-sanitizer (1.0.3)
loofah (~> 2.0)
- rainbow (2.1.0)
+ rainbow (2.2.1)
rake (12.0.0)
rb-fsevent (0.9.8)
rdoc (5.0.0)
@@ -287,8 +276,8 @@ GEM
redis (~> 3.3)
resque (~> 1.26)
rufus-scheduler (~> 3.2)
- rubocop (0.46.0)
- parser (>= 2.3.1.1, < 3.0)
+ rubocop (0.47.1)
+ parser (>= 2.3.3.1, < 3.0)
powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.7)
@@ -296,7 +285,7 @@ GEM
ruby-progressbar (1.8.1)
ruby_dep (1.5.0)
rubyzip (1.2.0)
- rufus-scheduler (3.3.1)
+ rufus-scheduler (3.3.2)
tzinfo
sass (3.4.23)
sass-rails (5.0.6)
@@ -311,10 +300,10 @@ GEM
childprocess (~> 0.5)
rubyzip (~> 1.0)
websocket (~> 1.0)
- sequel (4.41.0)
+ sequel (4.42.1)
serverengine (1.5.11)
sigdump (~> 0.2.2)
- sidekiq (4.2.7)
+ sidekiq (4.2.9)
concurrent-ruby (~> 1.0)
connection_pool (~> 2.2, >= 2.2.0)
rack-protection (>= 1.5.0)
@@ -358,7 +347,7 @@ GEM
tzinfo (>= 1.0.0)
uglifier (3.0.4)
execjs (>= 0.3.0, < 3)
- unicode-display_width (1.1.2)
+ unicode-display_width (1.1.3)
useragent (0.16.8)
vegas (0.1.11)
rack (>= 1.0.0)
@@ -389,9 +378,10 @@ DEPENDENCIES
byebug
coffee-rails
dalli (>= 2.2.1)
- delayed_job!
- delayed_job_active_record!
+ delayed_job
+ delayed_job_active_record
em-hiredis
+ erubis (~> 2.7.0)
hiredis
jquery-rails
json (>= 2.0.0)
@@ -417,7 +407,7 @@ DEPENDENCIES
redis
resque!
resque-scheduler
- rubocop
+ rubocop (>= 0.47)
sass-rails
sdoc (= 1.0.0.rc1)
sequel
@@ -434,4 +424,4 @@ DEPENDENCIES
websocket-client-simple!
BUNDLED WITH
- 1.13.7
+ 1.14.3
diff --git a/actioncable/CHANGELOG.md b/actioncable/CHANGELOG.md
index 4f17274a01..7657a05077 100644
--- a/actioncable/CHANGELOG.md
+++ b/actioncable/CHANGELOG.md
@@ -1,3 +1,9 @@
+* Redis subscription adapters now support `channel_prefix` option in `cable.yml`
+
+ Avoids channel name collisions when multiple apps use the same Redis server.
+
+ *Chad Ingram*
+
* Permit same-origin connections by default.
Added new option `config.action_cable.allow_same_origin_as_host = false`
diff --git a/actioncable/lib/action_cable/connection/client_socket.rb b/actioncable/lib/action_cable/connection/client_socket.rb
index 70a2bbecb1..c7e30e78c8 100644
--- a/actioncable/lib/action_cable/connection/client_socket.rb
+++ b/actioncable/lib/action_cable/connection/client_socket.rb
@@ -90,8 +90,8 @@ module ActionCable
reason ||= ""
unless code == 1000 || (code >= 3000 && code <= 4999)
- raise ArgumentError, "Failed to execute 'close' on WebSocket: " +
- "The code must be either 1000, or between 3000 and 4999. " +
+ raise ArgumentError, "Failed to execute 'close' on WebSocket: " \
+ "The code must be either 1000, or between 3000 and 4999. " \
"#{code} is neither."
end
diff --git a/actioncable/lib/action_cable/connection/subscriptions.rb b/actioncable/lib/action_cable/connection/subscriptions.rb
index abf42c99d5..44bce1e195 100644
--- a/actioncable/lib/action_cable/connection/subscriptions.rb
+++ b/actioncable/lib/action_cable/connection/subscriptions.rb
@@ -19,7 +19,7 @@ module ActionCable
logger.error "Received unrecognized command in #{data.inspect}"
end
rescue Exception => e
- logger.error "Could not execute command from #{data.inspect}) [#{e.class} - #{e.message}]: #{e.backtrace.first(5).join(" | ")}"
+ logger.error "Could not execute command from (#{data.inspect}) [#{e.class} - #{e.message}]: #{e.backtrace.first(5).join(" | ")}"
end
def add(data)
diff --git a/actioncable/lib/action_cable/subscription_adapter.rb b/actioncable/lib/action_cable/subscription_adapter.rb
index 72e62f3daf..596269ab9b 100644
--- a/actioncable/lib/action_cable/subscription_adapter.rb
+++ b/actioncable/lib/action_cable/subscription_adapter.rb
@@ -4,5 +4,6 @@ module ActionCable
autoload :Base
autoload :SubscriberMap
+ autoload :ChannelPrefix
end
end
diff --git a/actioncable/lib/action_cable/subscription_adapter/channel_prefix.rb b/actioncable/lib/action_cable/subscription_adapter/channel_prefix.rb
new file mode 100644
index 0000000000..8b293cc785
--- /dev/null
+++ b/actioncable/lib/action_cable/subscription_adapter/channel_prefix.rb
@@ -0,0 +1,26 @@
+module ActionCable
+ module SubscriptionAdapter
+ module ChannelPrefix # :nodoc:
+ def broadcast(channel, payload)
+ channel = channel_with_prefix(channel)
+ super
+ end
+
+ def subscribe(channel, callback, success_callback = nil)
+ channel = channel_with_prefix(channel)
+ super
+ end
+
+ def unsubscribe(channel, callback)
+ channel = channel_with_prefix(channel)
+ super
+ end
+
+ private
+ # Returns the channel name, including channel_prefix specified in cable.yml
+ def channel_with_prefix(channel)
+ [@server.config.cable[:channel_prefix], channel].compact.join(":")
+ end
+ end
+ end
+end
diff --git a/actioncable/lib/action_cable/subscription_adapter/evented_redis.rb b/actioncable/lib/action_cable/subscription_adapter/evented_redis.rb
index c3018c5281..56b068976b 100644
--- a/actioncable/lib/action_cable/subscription_adapter/evented_redis.rb
+++ b/actioncable/lib/action_cable/subscription_adapter/evented_redis.rb
@@ -11,6 +11,8 @@ EventMachine.kqueue if EventMachine.kqueue?
module ActionCable
module SubscriptionAdapter
class EventedRedis < Base # :nodoc:
+ prepend ChannelPrefix
+
@@mutex = Mutex.new
# Overwrite this factory method for EventMachine Redis connections if you want to use a different Redis connection library than EM::Hiredis.
diff --git a/actioncable/lib/action_cable/subscription_adapter/redis.rb b/actioncable/lib/action_cable/subscription_adapter/redis.rb
index 62bd284a6b..41a6e55822 100644
--- a/actioncable/lib/action_cable/subscription_adapter/redis.rb
+++ b/actioncable/lib/action_cable/subscription_adapter/redis.rb
@@ -6,6 +6,8 @@ require "redis"
module ActionCable
module SubscriptionAdapter
class Redis < Base # :nodoc:
+ prepend ChannelPrefix
+
# Overwrite this factory method for redis connections if you want to use a different Redis library than Redis.
# This is needed, for example, when using Makara proxies for distributed Redis.
cattr_accessor(:redis_connector) { ->(config) { ::Redis.new(url: config[:url]) } }
diff --git a/actioncable/test/channel/periodic_timers_test.rb b/actioncable/test/channel/periodic_timers_test.rb
index 0cc4992ef6..17a8e45a35 100644
--- a/actioncable/test/channel/periodic_timers_test.rb
+++ b/actioncable/test/channel/periodic_timers_test.rb
@@ -38,23 +38,26 @@ class ActionCable::Channel::PeriodicTimersTest < ActiveSupport::TestCase
test "disallow negative and zero periods" do
[ 0, 0.0, 0.seconds, -1, -1.seconds, "foo", :foo, Object.new ].each do |invalid|
- assert_raise ArgumentError, /Expected every:/ do
+ e = assert_raise ArgumentError do
ChatChannel.periodically :send_updates, every: invalid
end
+ assert_match(/Expected every:/, e.message)
end
end
test "disallow block and arg together" do
- assert_raise ArgumentError, /not both/ do
+ e = assert_raise ArgumentError do
ChatChannel.periodically(:send_updates, every: 1) { ping }
end
+ assert_match(/not both/, e.message)
end
test "disallow unknown args" do
[ "send_updates", Object.new, nil ].each do |invalid|
- assert_raise ArgumentError, /Expected a Symbol/ do
+ e = assert_raise ArgumentError do
ChatChannel.periodically invalid, every: 1
end
+ assert_match(/Expected a Symbol/, e.message)
end
end
diff --git a/actioncable/test/subscription_adapter/channel_prefix.rb b/actioncable/test/subscription_adapter/channel_prefix.rb
new file mode 100644
index 0000000000..9ad659912e
--- /dev/null
+++ b/actioncable/test/subscription_adapter/channel_prefix.rb
@@ -0,0 +1,36 @@
+require "test_helper"
+
+class ActionCable::Server::WithIndependentConfig < ActionCable::Server::Base
+ # ActionCable::Server::Base defines config as a class variable.
+ # Need config to be an instance variable here as we're testing 2 separate configs
+ def config
+ @config ||= ActionCable::Server::Configuration.new
+ end
+end
+
+module ChannelPrefixTest
+ def test_channel_prefix
+ server2 = ActionCable::Server::WithIndependentConfig.new
+ server2.config.cable = alt_cable_config
+ server2.config.logger = Logger.new(StringIO.new).tap { |l| l.level = Logger::UNKNOWN }
+
+ adapter_klass = server2.config.pubsub_adapter
+
+ rx_adapter2 = adapter_klass.new(server2)
+ tx_adapter2 = adapter_klass.new(server2)
+
+ subscribe_as_queue("channel") do |queue|
+ subscribe_as_queue("channel", rx_adapter2) do |queue2|
+ @tx_adapter.broadcast("channel", "hello world")
+ tx_adapter2.broadcast("channel", "hello world 2")
+
+ assert_equal "hello world", queue.pop
+ assert_equal "hello world 2", queue2.pop
+ end
+ end
+ end
+
+ def alt_cable_config
+ cable_config.merge(channel_prefix: "foo")
+ end
+end
diff --git a/actioncable/test/subscription_adapter/evented_redis_test.rb b/actioncable/test/subscription_adapter/evented_redis_test.rb
index 2401950aa7..c55d35848e 100644
--- a/actioncable/test/subscription_adapter/evented_redis_test.rb
+++ b/actioncable/test/subscription_adapter/evented_redis_test.rb
@@ -1,8 +1,10 @@
require "test_helper"
require_relative "./common"
+require_relative "./channel_prefix"
class EventedRedisAdapterTest < ActionCable::TestCase
include CommonSubscriptionAdapterTest
+ include ChannelPrefixTest
def setup
super
diff --git a/actioncable/test/subscription_adapter/redis_test.rb b/actioncable/test/subscription_adapter/redis_test.rb
index 2ba5636656..4df5e0cbcd 100644
--- a/actioncable/test/subscription_adapter/redis_test.rb
+++ b/actioncable/test/subscription_adapter/redis_test.rb
@@ -1,8 +1,10 @@
require "test_helper"
require_relative "./common"
+require_relative "./channel_prefix"
class RedisAdapterTest < ActionCable::TestCase
include CommonSubscriptionAdapterTest
+ include ChannelPrefixTest
def cable_config
{ adapter: "redis", driver: "ruby", url: "redis://127.0.0.1:6379/12" }
diff --git a/actionmailer/CHANGELOG.md b/actionmailer/CHANGELOG.md
index de8abcccfe..54b07a626b 100644
--- a/actionmailer/CHANGELOG.md
+++ b/actionmailer/CHANGELOG.md
@@ -1,3 +1,12 @@
+* Add parameterized invocation of mailers as a way to share before filters and defaults between actions.
+ See ActionMailer::Parameterized for a full example of the benefit.
+
+ *DHH*
+
+* Allow lambdas to be used as lazy defaults in addition to procs.
+
+ *DHH*
+
* Mime type: allow to custom content type when setting body in headers
and attachments.
diff --git a/actionmailer/lib/action_mailer.rb b/actionmailer/lib/action_mailer.rb
index cf2c0f37e3..211190560a 100644
--- a/actionmailer/lib/action_mailer.rb
+++ b/actionmailer/lib/action_mailer.rb
@@ -42,6 +42,7 @@ module ActionMailer
autoload :DeliveryMethods
autoload :InlinePreviewInterceptor
autoload :MailHelper
+ autoload :Parameterized
autoload :Preview
autoload :Previews, "action_mailer/preview"
autoload :TestCase
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index 8205743de3..c0c030ac3e 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -288,20 +288,19 @@ module ActionMailer
# content_description: 'This is a description'
# end
#
- # Finally, Action Mailer also supports passing <tt>Proc</tt> objects into the default hash, so you
- # can define methods that evaluate as the message is being generated:
+ # Finally, Action Mailer also supports passing <tt>Proc</tt> and <tt>Lambda</tt> objects into the default hash,
+ # so you can define methods that evaluate as the message is being generated:
#
# class NotifierMailer < ApplicationMailer
- # default 'X-Special-Header' => Proc.new { my_method }
+ # default 'X-Special-Header' => Proc.new { my_method }, to: -> { @inviter.email_address }
#
# private
- #
# def my_method
# 'some complex call'
# end
# end
#
- # Note that the proc is evaluated right at the start of the mail message generation, so if you
+ # Note that the proc/lambda is evaluated right at the start of the mail message generation, so if you
# set something in the default hash using a proc, and then set the same thing inside of your
# mailer method, it will get overwritten by the mailer method.
#
@@ -324,7 +323,6 @@ module ActionMailer
# end
#
# private
- #
# def add_inline_attachment!
# attachments.inline["footer.jpg"] = File.read('/path/to/filename.jpg')
# end
@@ -434,6 +432,7 @@ module ActionMailer
class Base < AbstractController::Base
include DeliveryMethods
include Rescuable
+ include Parameterized
include Previews
abstract!
@@ -580,7 +579,7 @@ module ActionMailer
end
def respond_to_missing?(method, include_all = false)
- action_methods.include?(method.to_s)
+ action_methods.include?(method.to_s) || super
end
end
@@ -888,7 +887,7 @@ module ActionMailer
default_values = self.class.default.map do |key, value|
[
key,
- value.is_a?(Proc) ? instance_eval(&value) : value
+ value.is_a?(Proc) ? instance_exec(&value) : value
]
end.to_h
diff --git a/actionmailer/lib/action_mailer/parameterized.rb b/actionmailer/lib/action_mailer/parameterized.rb
new file mode 100644
index 0000000000..3acacc1f14
--- /dev/null
+++ b/actionmailer/lib/action_mailer/parameterized.rb
@@ -0,0 +1,152 @@
+module ActionMailer
+ # Provides the option to parameterize mailers in order to share instance variable
+ # setup, processing, and common headers.
+ #
+ # Consider this example that does not use parameterization:
+ #
+ # class InvitationsMailer < ApplicationMailer
+ # def account_invitation(inviter, invitee)
+ # @account = inviter.account
+ # @inviter = inviter
+ # @invitee = invitee
+ #
+ # subject = "#{@inviter.name} invited you to their Basecamp (#{@account.name})"
+ #
+ # mail \
+ # subject: subject,
+ # to: invitee.email_address,
+ # from: common_address(inviter),
+ # reply_to: inviter.email_address_with_name
+ # end
+ #
+ # def project_invitation(project, inviter, invitee)
+ # @account = inviter.account
+ # @project = project
+ # @inviter = inviter
+ # @invitee = invitee
+ # @summarizer = ProjectInvitationSummarizer.new(@project.bucket)
+ #
+ # subject = "#{@inviter.name.familiar} added you to a project in Basecamp (#{@account.name})"
+ #
+ # mail \
+ # subject: subject,
+ # to: invitee.email_address,
+ # from: common_address(inviter),
+ # reply_to: inviter.email_address_with_name
+ # end
+ #
+ # def bulk_project_invitation(projects, inviter, invitee)
+ # @account = inviter.account
+ # @projects = projects.sort_by(&:name)
+ # @inviter = inviter
+ # @invitee = invitee
+ #
+ # subject = "#{@inviter.name.familiar} added you to some new stuff in Basecamp (#{@account.name})"
+ #
+ # mail \
+ # subject: subject,
+ # to: invitee.email_address,
+ # from: common_address(inviter),
+ # reply_to: inviter.email_address_with_name
+ # end
+ # end
+ #
+ # InvitationsMailer.account_invitation(person_a, person_b).deliver_later
+ #
+ # Using parameterized mailers, this can be rewritten as:
+ #
+ # class InvitationsMailer < ApplicationMailer
+ # before_action { @inviter, @invitee = params[:inviter], params[:invitee] }
+ # before_action { @account = params[:inviter].account }
+ #
+ # default to: -> { @invitee.email_address },
+ # from: -> { common_address(@inviter) },
+ # reply_to: -> { @inviter.email_address_with_name }
+ #
+ # 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
+ #
+ # def bulk_project_invitation
+ # @projects = params[:projects].sort_by(&:name)
+ #
+ # mail subject: "#{@inviter.name.familiar} added you to some new stuff in Basecamp (#{@account.name})"
+ # end
+ # end
+ #
+ # InvitationsMailer.with(inviter: person_a, invitee: person_b).account_invitation.deliver_later
+ module Parameterized
+ extend ActiveSupport::Concern
+
+ included do
+ attr_accessor :params
+ end
+
+ module ClassMethods
+ # Provide the parameters to the mailer in order to use them in the instance methods and callbacks.
+ #
+ # InvitationsMailer.with(inviter: person_a, invitee: person_b).account_invitation.deliver_later
+ #
+ # See Parameterized documentation for full example.
+ def with(params)
+ ActionMailer::Parameterized::Mailer.new(self, params)
+ end
+ end
+
+ class Mailer # :nodoc:
+ def initialize(mailer, params)
+ @mailer, @params = mailer, params
+ end
+
+ private
+ def method_missing(method_name, *args)
+ if @mailer.action_methods.include?(method_name.to_s)
+ ActionMailer::Parameterized::MessageDelivery.new(@mailer, method_name, @params, *args)
+ else
+ super
+ end
+ end
+
+ def respond_to_missing?(method, include_all = false)
+ @mailer.respond_to?(method, include_all)
+ end
+ end
+
+ class MessageDelivery < ActionMailer::MessageDelivery # :nodoc:
+ def initialize(mailer_class, action, params, *args)
+ super(mailer_class, action, *args)
+ @params = params
+ end
+
+ private
+ def processed_mailer
+ @processed_mailer ||= @mailer_class.new.tap do |mailer|
+ mailer.params = @params
+ mailer.process @action, *@args
+ end
+ end
+
+ def enqueue_delivery(delivery_method, options = {})
+ if processed?
+ super
+ else
+ args = @mailer_class.name, @action.to_s, delivery_method.to_s, @params, *@args
+ ActionMailer::Parameterized::DeliveryJob.set(options).perform_later(*args)
+ end
+ end
+ end
+
+ class DeliveryJob < ActionMailer::DeliveryJob # :nodoc:
+ def perform(mailer, mail_method, delivery_method, params, *args)
+ mailer.constantize.with(params).public_send(mail_method, *args).send(delivery_method)
+ end
+ end
+ end
+end
diff --git a/actionmailer/lib/action_mailer/test_case.rb b/actionmailer/lib/action_mailer/test_case.rb
index cbd841466d..9ead03a40c 100644
--- a/actionmailer/lib/action_mailer/test_case.rb
+++ b/actionmailer/lib/action_mailer/test_case.rb
@@ -4,8 +4,8 @@ require "rails-dom-testing"
module ActionMailer
class NonInferrableMailerError < ::StandardError
def initialize(name)
- super "Unable to determine the mailer to test from #{name}. " +
- "You'll need to specify it using tests YourMailer in your " +
+ super "Unable to determine the mailer to test from #{name}. " \
+ "You'll need to specify it using tests YourMailer in your " \
"test case definition"
end
end
diff --git a/actionmailer/lib/action_mailer/test_helper.rb b/actionmailer/lib/action_mailer/test_helper.rb
index c17ecad4c6..c30fb1fc18 100644
--- a/actionmailer/lib/action_mailer/test_helper.rb
+++ b/actionmailer/lib/action_mailer/test_helper.rb
@@ -88,7 +88,7 @@ module ActionMailer
# end
# end
def assert_enqueued_emails(number, &block)
- assert_enqueued_jobs number, only: ActionMailer::DeliveryJob, &block
+ assert_enqueued_jobs number, only: [ ActionMailer::DeliveryJob, ActionMailer::Parameterized::DeliveryJob ], &block
end
# Asserts that no emails are enqueued for later delivery.
@@ -107,7 +107,7 @@ module ActionMailer
# end
# end
def assert_no_enqueued_emails(&block)
- assert_no_enqueued_jobs only: ActionMailer::DeliveryJob, &block
+ assert_no_enqueued_jobs only: [ ActionMailer::DeliveryJob, ActionMailer::Parameterized::DeliveryJob ], &block
end
end
end
diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb
index 51de03c4ce..a646cbd581 100644
--- a/actionmailer/test/abstract_unit.rb
+++ b/actionmailer/test/abstract_unit.rb
@@ -31,15 +31,15 @@ I18n.enforce_available_locales = false
FIXTURE_LOAD_PATH = File.expand_path("fixtures", File.dirname(__FILE__))
ActionMailer::Base.view_paths = FIXTURE_LOAD_PATH
-# Skips the current run on Rubinius using Minitest::Assertions#skip
-def rubinius_skip(message = "")
- skip message if RUBY_ENGINE == "rbx"
-end
-# Skips the current run on JRuby using Minitest::Assertions#skip
-def jruby_skip(message = "")
- skip message if defined?(JRUBY_VERSION)
-end
-
class ActiveSupport::TestCase
include ActiveSupport::Testing::MethodCallAssertions
+
+ # Skips the current run on Rubinius using Minitest::Assertions#skip
+ private def rubinius_skip(message = "")
+ skip message if RUBY_ENGINE == "rbx"
+ end
+ # Skips the current run on JRuby using Minitest::Assertions#skip
+ private def jruby_skip(message = "")
+ skip message if defined?(JRUBY_VERSION)
+ end
end
diff --git a/actionmailer/test/mail_helper_test.rb b/actionmailer/test/mail_helper_test.rb
index a2e04b5f48..6042548aef 100644
--- a/actionmailer/test/mail_helper_test.rb
+++ b/actionmailer/test/mail_helper_test.rb
@@ -2,11 +2,11 @@ require "abstract_unit"
class HelperMailer < ActionMailer::Base
def use_mail_helper
- @text = "But soft! What light through yonder window breaks? It is the east, " +
- "and Juliet is the sun. Arise, fair sun, and kill the envious moon, " +
- "which is sick and pale with grief that thou, her maid, art far more " +
- "fair than she. Be not her maid, for she is envious! Her vestal " +
- "livery is but sick and green, and none but fools do wear it. Cast " +
+ @text = "But soft! What light through yonder window breaks? It is the east, " \
+ "and Juliet is the sun. Arise, fair sun, and kill the envious moon, " \
+ "which is sick and pale with grief that thou, her maid, art far more " \
+ "fair than she. Be not her maid, for she is envious! Her vestal " \
+ "livery is but sick and green, and none but fools do wear it. Cast " \
"it off!"
mail_with_defaults do |format|
diff --git a/actionmailer/test/mailers/params_mailer.rb b/actionmailer/test/mailers/params_mailer.rb
new file mode 100644
index 0000000000..4c0fae6d91
--- /dev/null
+++ b/actionmailer/test/mailers/params_mailer.rb
@@ -0,0 +1,11 @@
+class ParamsMailer < ActionMailer::Base
+ before_action { @inviter, @invitee = params[:inviter], params[:invitee] }
+
+ default to: Proc.new { @invitee }, from: -> { @inviter }
+
+ def invitation
+ mail(subject: "Welcome to the project!") do |format|
+ format.text { render plain: "So says #{@inviter}" }
+ end
+ end
+end
diff --git a/actionmailer/test/parameterized_test.rb b/actionmailer/test/parameterized_test.rb
new file mode 100644
index 0000000000..914ed12312
--- /dev/null
+++ b/actionmailer/test/parameterized_test.rb
@@ -0,0 +1,55 @@
+require "abstract_unit"
+require "active_job"
+require "mailers/params_mailer"
+
+class ParameterizedTest < ActiveSupport::TestCase
+ include ActiveJob::TestHelper
+
+ setup do
+ @previous_logger = ActiveJob::Base.logger
+ ActiveJob::Base.logger = Logger.new(nil)
+
+ @previous_delivery_method = ActionMailer::Base.delivery_method
+ ActionMailer::Base.delivery_method = :test
+
+ @previous_deliver_later_queue_name = ActionMailer::Base.deliver_later_queue_name
+ ActionMailer::Base.deliver_later_queue_name = :test_queue
+ ActionMailer::Base.delivery_method = :test
+
+ @mail = ParamsMailer.with(inviter: "david@basecamp.com", invitee: "jason@basecamp.com").invitation
+ end
+
+ teardown do
+ ActiveJob::Base.logger = @previous_logger
+ ParamsMailer.deliveries.clear
+
+ ActionMailer::Base.delivery_method = @previous_delivery_method
+ ActionMailer::Base.deliver_later_queue_name = @previous_deliver_later_queue_name
+ end
+
+ test "parameterized headers" do
+ assert_equal(["jason@basecamp.com"], @mail.to)
+ assert_equal(["david@basecamp.com"], @mail.from)
+ assert_equal("So says david@basecamp.com", @mail.body.encoded)
+ end
+
+ test "enqueue the email with params" do
+ assert_performed_with(job: ActionMailer::Parameterized::DeliveryJob, args: ["ParamsMailer", "invitation", "deliver_now", { inviter: "david@basecamp.com", invitee: "jason@basecamp.com" } ]) do
+ @mail.deliver_later
+ end
+ end
+
+ test "respond_to?" do
+ mailer = ParamsMailer.with(inviter: "david@basecamp.com", invitee: "jason@basecamp.com")
+
+ assert_respond_to mailer, :invitation
+ assert_not_respond_to mailer, :anything
+
+ invitation = mailer.method(:invitation)
+ assert_equal Method, invitation.class
+
+ assert_raises(NameError) do
+ invitation = mailer.method(:anything)
+ end
+ end
+end
diff --git a/actionmailer/test/test_helper_test.rb b/actionmailer/test/test_helper_test.rb
index 31ac5a5211..876e9b0634 100644
--- a/actionmailer/test/test_helper_test.rb
+++ b/actionmailer/test/test_helper_test.rb
@@ -143,6 +143,16 @@ class TestHelperMailerTest < ActionMailer::TestCase
end
end
+ def test_assert_enqueued_parameterized_emails
+ assert_nothing_raised do
+ assert_enqueued_emails 1 do
+ silence_stream($stdout) do
+ TestHelperMailer.with(a: 1).test.deliver_later
+ end
+ end
+ end
+ end
+
def test_assert_enqueued_emails_too_few_sent
error = assert_raise ActiveSupport::TestCase::Assertion do
assert_enqueued_emails 2 do
@@ -176,6 +186,14 @@ class TestHelperMailerTest < ActionMailer::TestCase
end
end
+ def test_assert_no_enqueued_parameterized_emails
+ assert_nothing_raised do
+ assert_no_enqueued_emails do
+ TestHelperMailer.with(a: 1).test.deliver_now
+ end
+ end
+ end
+
def test_assert_no_enqueued_emails_failure
error = assert_raise ActiveSupport::TestCase::Assertion do
assert_no_enqueued_emails do
diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb
index 603c2e9ea7..e7cb6347a2 100644
--- a/actionpack/lib/abstract_controller/base.rb
+++ b/actionpack/lib/abstract_controller/base.rb
@@ -1,4 +1,3 @@
-require "erubis"
require "abstract_controller/error"
require "active_support/configurable"
require "active_support/descendants_tracker"
@@ -22,7 +21,6 @@ module AbstractController
include ActiveSupport::Configurable
extend ActiveSupport::DescendantsTracker
- undef_method :not_implemented
class << self
attr_reader :abstract
alias_method :abstract?, :abstract
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index 6e8df02fb9..d304dcf468 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -398,8 +398,7 @@ module ActionController
unpermitted_parameters!(params) if self.class.action_on_unpermitted_parameters
- params.permitted = true
- params
+ params.permit!
end
# Returns a parameter for the given +key+. If not found,
@@ -818,7 +817,6 @@ module ActionController
# Filter this one out.
end
end
- sanitized.permitted = true
end
end
diff --git a/actionpack/lib/action_controller/renderer.rb b/actionpack/lib/action_controller/renderer.rb
index 3ff80e6a39..acb400cd15 100644
--- a/actionpack/lib/action_controller/renderer.rb
+++ b/actionpack/lib/action_controller/renderer.rb
@@ -60,7 +60,8 @@ module ActionController
end
# Accepts a custom Rack environment to render templates in.
- # It will be merged with ActionController::Renderer.defaults
+ # It will be merged with the default Rack environment defined by
+ # +ActionController::Renderer::DEFAULTS+.
def initialize(controller, env, defaults)
@controller = controller
@defaults = defaults
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 57dd605b51..7229c67f30 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -389,7 +389,9 @@ module ActionController
# Note that the request method is not verified. The different methods are
# available to make the tests more expressive.
def get(action, **args)
- process(action, method: "GET", **args)
+ res = process(action, method: "GET", **args)
+ cookies.update res.cookies
+ res
end
# Simulate a POST request with the given parameters and set/volley the response.
@@ -517,7 +519,6 @@ module ActionController
unless @request.cookie_jar.committed?
@request.cookie_jar.write(@response)
cookies.update(@request.cookie_jar.instance_variable_get(:@cookies))
- cookies.update(@response.cookies)
end
end
@response.prepare!
@@ -533,6 +534,7 @@ module ActionController
@request.delete_header "HTTP_ACCEPT"
end
@request.query_string = ""
+ @request.env.delete "PATH_INFO"
@response.sent!
end
diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb
index 6b718e3682..1a65e2d1cb 100644
--- a/actionpack/lib/action_dispatch/http/mime_type.rb
+++ b/actionpack/lib/action_dispatch/http/mime_type.rb
@@ -298,7 +298,7 @@ module Mime
end
def respond_to_missing?(method, include_private = false)
- method.to_s.ends_with? "?"
+ (method.to_s.ends_with? "?") || super
end
end
diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb
index 12fc39f1aa..8f21eca440 100644
--- a/actionpack/lib/action_dispatch/http/parameters.rb
+++ b/actionpack/lib/action_dispatch/http/parameters.rb
@@ -30,7 +30,7 @@ module ActionDispatch
end
module ClassMethods
- # Configure the parameter parser for a give mime type.
+ # Configure the parameter parser for a given mime type.
#
# It accepts a hash where the key is the symbol of the mime type
# and the value is a proc.
diff --git a/actionpack/lib/action_dispatch/journey/visitors.rb b/actionpack/lib/action_dispatch/journey/visitors.rb
index cda859cba4..1c50192867 100644
--- a/actionpack/lib/action_dispatch/journey/visitors.rb
+++ b/actionpack/lib/action_dispatch/journey/visitors.rb
@@ -5,7 +5,7 @@ module ActionDispatch
ESCAPE_PATH = ->(value) { Router::Utils.escape_path(value) }
ESCAPE_SEGMENT = ->(value) { Router::Utils.escape_segment(value) }
- class Parameter < Struct.new(:name, :escaper)
+ Parameter = Struct.new(:name, :escaper) do
def escape(value); escaper.call value; end
end
diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index 956c53e813..c61cb3fd68 100644
--- a/actionpack/lib/action_dispatch/middleware/cookies.rb
+++ b/actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -572,7 +572,7 @@ module ActionDispatch
super
if ActiveSupport::LegacyKeyGenerator === key_generator
- raise "You didn't set secrets.secret_key_base, which is required for this cookie jar. " +
+ raise "You didn't set secrets.secret_key_base, which is required for this cookie jar. " \
"Read the upgrade documentation to learn more about this new config option."
end
diff --git a/actionpack/lib/action_dispatch/middleware/remote_ip.rb b/actionpack/lib/action_dispatch/middleware/remote_ip.rb
index 9f1ae80b97..8bae5bfeff 100644
--- a/actionpack/lib/action_dispatch/middleware/remote_ip.rb
+++ b/actionpack/lib/action_dispatch/middleware/remote_ip.rb
@@ -131,8 +131,8 @@ module ActionDispatch
should_check_ip = @check_ip && client_ips.last && forwarded_ips.last
if should_check_ip && !forwarded_ips.include?(client_ips.last)
# We don't know which came from the proxy, and which from the user
- raise IpSpoofAttackError, "IP spoofing attack?! " +
- "HTTP_CLIENT_IP=#{@req.client_ip.inspect} " +
+ raise IpSpoofAttackError, "IP spoofing attack?! " \
+ "HTTP_CLIENT_IP=#{@req.client_ip.inspect} " \
"HTTP_X_FORWARDED_FOR=#{@req.x_forwarded_for.inspect}"
end
diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
index 97c937b0b1..d9f018c8ac 100644
--- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
@@ -8,8 +8,8 @@ module ActionDispatch
module Session
class SessionRestoreError < StandardError #:nodoc:
def initialize
- super("Session contains objects whose class definition isn't available.\n" +
- "Remember to require the classes for all objects kept in the session.\n" +
+ super("Session contains objects whose class definition isn't available.\n" \
+ "Remember to require the classes for all objects kept in the session.\n" \
"(Original exception: #{$!.message} [#{$!.class}])\n")
set_backtrace $!.backtrace
end
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 83652bd34c..8d9f70e3c6 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -1,6 +1,7 @@
require "active_support/core_ext/hash/slice"
require "active_support/core_ext/enumerable"
require "active_support/core_ext/array/extract_options"
+require "active_support/core_ext/regexp"
require "action_dispatch/routing/redirection"
require "action_dispatch/routing/endpoint"
diff --git a/actionpack/lib/action_dispatch/routing/redirection.rb b/actionpack/lib/action_dispatch/routing/redirection.rb
index 4e2318a45e..dabc045007 100644
--- a/actionpack/lib/action_dispatch/routing/redirection.rb
+++ b/actionpack/lib/action_dispatch/routing/redirection.rb
@@ -137,6 +137,9 @@ module ActionDispatch
#
# get "/stories" => redirect("/posts")
#
+ # This will redirect the user, while ignoring certain parts of the request, including query string, etc.
+ # `/stories`, `/stories?foo=bar`, etc all redirect to `/posts`.
+ #
# You can also use interpolation in the supplied redirect argument:
#
# get 'docs/:article', to: redirect('/wiki/%{article}')
@@ -165,6 +168,11 @@ module ActionDispatch
#
# get 'stores/:name', to: redirect(subdomain: 'stores', path: '/%{name}')
# get 'stores/:name(*all)', to: redirect(subdomain: 'stores', path: '/%{name}%{all}')
+ # get '/stories', to: redirect(path: '/posts')
+ #
+ # This will redirect the user, while changing only the specified parts of the request,
+ # for example the `path` option in the last example.
+ # `/stories`, `/stories?foo=bar`, redirect to `/posts` and `/posts?foo=bar` respectively.
#
# Finally, an object which responds to call can be supplied to redirect, allowing you to reuse
# common redirect routes. The call method must accept two arguments, params and request, and return
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index 021ffec862..15f816a0ae 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -145,8 +145,8 @@ module ActionDispatch
self.host = DEFAULT_HOST
self.remote_addr = "127.0.0.1"
- self.accept = "text/xml,application/xml,application/xhtml+xml," +
- "text/html;q=0.9,text/plain;q=0.8,image/png," +
+ self.accept = "text/xml,application/xml,application/xhtml+xml," \
+ "text/html;q=0.9,text/plain;q=0.8,image/png," \
"*/*;q=0.5"
unless defined? @named_routes_configured
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index 7c113426a5..459b0d6c54 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -354,15 +354,6 @@ class CommentsController < ResourcesController; end
class AccountsController < ResourcesController; end
class ImagesController < ResourcesController; end
-# Skips the current run on Rubinius using Minitest::Assertions#skip
-def rubinius_skip(message = "")
- skip message if RUBY_ENGINE == "rbx"
-end
-# Skips the current run on JRuby using Minitest::Assertions#skip
-def jruby_skip(message = "")
- skip message if defined?(JRUBY_VERSION)
-end
-
require "active_support/testing/method_call_assertions"
class ForkingExecutor
@@ -438,4 +429,13 @@ end
class ActiveSupport::TestCase
include ActiveSupport::Testing::MethodCallAssertions
+
+ # Skips the current run on Rubinius using Minitest::Assertions#skip
+ private def rubinius_skip(message = "")
+ skip message if RUBY_ENGINE == "rbx"
+ end
+ # Skips the current run on JRuby using Minitest::Assertions#skip
+ private def jruby_skip(message = "")
+ skip message if defined?(JRUBY_VERSION)
+ end
end
diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb
index f9701585a9..90b3f7ea88 100644
--- a/actionpack/test/controller/filters_test.rb
+++ b/actionpack/test/controller/filters_test.rb
@@ -704,7 +704,7 @@ class FilterTest < ActionController::TestCase
def test_prepending_and_appending_around_action
test_process(MixedFilterController)
- assert_equal " before aroundfilter before procfilter before appended aroundfilter " +
+ assert_equal " before aroundfilter before procfilter before appended aroundfilter " \
" after appended aroundfilter after procfilter after aroundfilter ",
MixedFilterController.execution_log
end
diff --git a/actionpack/test/controller/parameters/nested_parameters_permit_test.rb b/actionpack/test/controller/parameters/nested_parameters_permit_test.rb
index 5f86901e30..00e591d5a7 100644
--- a/actionpack/test/controller/parameters/nested_parameters_permit_test.rb
+++ b/actionpack/test/controller/parameters/nested_parameters_permit_test.rb
@@ -140,6 +140,11 @@ class NestedParametersPermitTest < ActiveSupport::TestCase
assert_equal "William Shakespeare", permitted[:book][:authors_attributes]["0"][:name]
assert_equal "Unattributed Assistant", permitted[:book][:authors_attributes]["1"][:name]
+ assert_equal(
+ { "book" => { "authors_attributes" => { "0" => { "name" => "William Shakespeare" }, "1" => { "name" => "Unattributed Assistant" }, "2" => {} } } },
+ permitted.to_h
+ )
+
assert_filtered_out permitted[:book][:authors_attributes]["0"], :age_of_death
end
diff --git a/actionpack/test/controller/parameters/parameters_permit_test.rb b/actionpack/test/controller/parameters/parameters_permit_test.rb
index b62a3d6d7b..8920914af1 100644
--- a/actionpack/test/controller/parameters/parameters_permit_test.rb
+++ b/actionpack/test/controller/parameters/parameters_permit_test.rb
@@ -66,12 +66,20 @@ class ParametersPermitTest < ActiveSupport::TestCase
values.each do |value|
params = ActionController::Parameters.new(id: value)
permitted = params.permit(:id)
- assert_equal value, permitted[:id]
+ if value.nil?
+ assert_nil permitted[:id]
+ else
+ assert_equal value, permitted[:id]
+ end
@struct_fields.each do |sf|
params = ActionController::Parameters.new(sf => value)
permitted = params.permit(:sf)
- assert_equal value, permitted[sf]
+ if value.nil?
+ assert_nil permitted[sf]
+ else
+ assert_equal value, permitted[sf]
+ end
end
end
end
@@ -187,11 +195,6 @@ class ParametersPermitTest < ActiveSupport::TestCase
permitted = params.permit(:username, preferences: {}, hacked: {})
- assert permitted.permitted?
- assert permitted[:preferences].permitted?
- assert permitted[:preferences][:font].permitted?
- assert permitted[:preferences][:dubious].all?(&:permitted?)
-
assert_equal "fxn", permitted[:username]
assert_equal "Marazul", permitted[:preferences][:scheme]
assert_equal "Source Code Pro", permitted[:preferences][:font][:name]
diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb
index 0c0f18f200..3a0a0a8bde 100644
--- a/actionpack/test/controller/render_test.rb
+++ b/actionpack/test/controller/render_test.rb
@@ -313,7 +313,6 @@ class ExpiresInRenderTest < ActionController::TestCase
end
def test_permitted_dynamic_render_file_hash
- skip "FIXME: this test passes on 4-2-stable but not master. Why?"
assert File.exist?(File.join(File.dirname(__FILE__), "../../test/abstract_unit.rb"))
response = get :dynamic_render_permit, params: { id: { file: '../\\../test/abstract_unit.rb' } }
assert_equal File.read(File.join(File.dirname(__FILE__), "../../test/abstract_unit.rb")),
diff --git a/actionpack/test/controller/request/test_request_test.rb b/actionpack/test/controller/request/test_request_test.rb
index b67ae72c0a..1440db00f6 100644
--- a/actionpack/test/controller/request/test_request_test.rb
+++ b/actionpack/test/controller/request/test_request_test.rb
@@ -21,16 +21,20 @@ class ActionController::TestRequestTest < ActionController::TestCase
@request.get_header("CONTENT_LENGTH"))
end
- ActionDispatch::Session::AbstractStore::DEFAULT_OPTIONS.each_key do |option|
- test "rack default session options #{option} exists in session options and is default" do
- assert_equal(ActionDispatch::Session::AbstractStore::DEFAULT_OPTIONS[option],
- @request.session_options[option],
- "Missing rack session default option #{option} in request.session_options")
+ ActionDispatch::Session::AbstractStore::DEFAULT_OPTIONS.each_pair do |key, value|
+ test "rack default session options #{key} exists in session options and is default" do
+ if value.nil?
+ assert_nil(@request.session_options[key],
+ "Missing rack session default option #{key} in request.session_options")
+ else
+ assert_equal(value, @request.session_options[key],
+ "Missing rack session default option #{key} in request.session_options")
+ end
end
- test "rack default session options #{option} exists in session options" do
- assert(@request.session_options.has_key?(option),
- "Missing rack session option #{option} in request.session_options")
+ test "rack default session options #{key} exists in session options" do
+ assert(@request.session_options.has_key?(key),
+ "Missing rack session option #{key} in request.session_options")
end
end
end
diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb
index 874f9c3c42..ac99830208 100644
--- a/actionpack/test/controller/test_case_test.rb
+++ b/actionpack/test/controller/test_case_test.rb
@@ -728,6 +728,20 @@ XML
assert_equal "text/html", @response.body
end
+ def test_request_path_info_and_format_reset
+ get :test_format, format: "json"
+ assert_equal "application/json", @response.body
+
+ get :test_uri, format: "json"
+ assert_equal "/test_case_test/test/test_uri.json", @response.body
+
+ get :test_format
+ assert_equal "text/html", @response.body
+
+ get :test_uri
+ assert_equal "/test_case_test/test/test_uri", @response.body
+ end
+
def test_request_format_kwarg_overrides_params
get :test_format, format: "json", params: { format: "html" }
assert_equal "application/json", @response.body
diff --git a/actionpack/test/dispatch/cookies_test.rb b/actionpack/test/dispatch/cookies_test.rb
index 73ad677419..664faa31bb 100644
--- a/actionpack/test/dispatch/cookies_test.rb
+++ b/actionpack/test/dispatch/cookies_test.rb
@@ -395,15 +395,6 @@ class CookiesTest < ActionController::TestCase
assert_equal false, cookies.deleted?("another")
end
- # Ensure all HTTP methods have their cookies updated
- [:get, :post, :patch, :put, :delete, :head].each do |method|
- define_method("test_deleting_cookie_#{method}") do
- request.cookies[:user_name] = "Joe"
- public_send method, :logout
- assert_nil cookies[:user_name]
- end
- end
-
def test_deleted_cookie_predicate_with_mismatching_options
cookies[:user_name] = "Joe"
cookies.delete("user_name", path: "/path")
diff --git a/actionpack/test/dispatch/prefix_generation_test.rb b/actionpack/test/dispatch/prefix_generation_test.rb
index bb2fc53add..0e093d2188 100644
--- a/actionpack/test/dispatch/prefix_generation_test.rb
+++ b/actionpack/test/dispatch/prefix_generation_test.rb
@@ -22,8 +22,6 @@ module TestGenerationPrefix
end
class WithMountedEngine < ActionDispatch::IntegrationTest
- include Rack::Test::Methods
-
class BlogEngine < Rails::Engine
routes.draw do
get "/posts/:id", to: "inside_engine_generating#show", as: :post
@@ -153,114 +151,114 @@ module TestGenerationPrefix
# Inside Engine
test "[ENGINE] generating engine's url use SCRIPT_NAME from request" do
get "/pure-awesomeness/blog/posts/1"
- assert_equal "/pure-awesomeness/blog/posts/1", last_response.body
+ assert_equal "/pure-awesomeness/blog/posts/1", response.body
end
test "[ENGINE] generating application's url never uses SCRIPT_NAME from request" do
get "/pure-awesomeness/blog/url_to_application"
- assert_equal "/generate", last_response.body
+ assert_equal "/generate", response.body
end
test "[ENGINE] generating engine's url with polymorphic path" do
get "/pure-awesomeness/blog/polymorphic_path_for_engine"
- assert_equal "/pure-awesomeness/blog/posts/1", last_response.body
+ assert_equal "/pure-awesomeness/blog/posts/1", response.body
end
test "[ENGINE] url_helpers from engine have higher priority than application's url_helpers" do
get "/awesome/blog/conflicting_url"
- assert_equal "engine", last_response.body
+ assert_equal "engine", response.body
end
test "[ENGINE] relative path root uses SCRIPT_NAME from request" do
get "/awesome/blog/relative_path_root"
- verify_redirect "http://example.org/awesome/blog"
+ verify_redirect "http://www.example.com/awesome/blog"
end
test "[ENGINE] relative path redirect uses SCRIPT_NAME from request" do
get "/awesome/blog/relative_path_redirect"
- verify_redirect "http://example.org/awesome/blog/foo"
+ verify_redirect "http://www.example.com/awesome/blog/foo"
end
test "[ENGINE] relative option root uses SCRIPT_NAME from request" do
get "/awesome/blog/relative_option_root"
- verify_redirect "http://example.org/awesome/blog"
+ verify_redirect "http://www.example.com/awesome/blog"
end
test "[ENGINE] relative option redirect uses SCRIPT_NAME from request" do
get "/awesome/blog/relative_option_redirect"
- verify_redirect "http://example.org/awesome/blog/foo"
+ verify_redirect "http://www.example.com/awesome/blog/foo"
end
test "[ENGINE] relative custom root uses SCRIPT_NAME from request" do
get "/awesome/blog/relative_custom_root"
- verify_redirect "http://example.org/awesome/blog"
+ verify_redirect "http://www.example.com/awesome/blog"
end
test "[ENGINE] relative custom redirect uses SCRIPT_NAME from request" do
get "/awesome/blog/relative_custom_redirect"
- verify_redirect "http://example.org/awesome/blog/foo"
+ verify_redirect "http://www.example.com/awesome/blog/foo"
end
test "[ENGINE] absolute path root doesn't use SCRIPT_NAME from request" do
get "/awesome/blog/absolute_path_root"
- verify_redirect "http://example.org/"
+ verify_redirect "http://www.example.com/"
end
test "[ENGINE] absolute path redirect doesn't use SCRIPT_NAME from request" do
get "/awesome/blog/absolute_path_redirect"
- verify_redirect "http://example.org/foo"
+ verify_redirect "http://www.example.com/foo"
end
test "[ENGINE] absolute option root doesn't use SCRIPT_NAME from request" do
get "/awesome/blog/absolute_option_root"
- verify_redirect "http://example.org/"
+ verify_redirect "http://www.example.com/"
end
test "[ENGINE] absolute option redirect doesn't use SCRIPT_NAME from request" do
get "/awesome/blog/absolute_option_redirect"
- verify_redirect "http://example.org/foo"
+ verify_redirect "http://www.example.com/foo"
end
test "[ENGINE] absolute custom root doesn't use SCRIPT_NAME from request" do
get "/awesome/blog/absolute_custom_root"
- verify_redirect "http://example.org/"
+ verify_redirect "http://www.example.com/"
end
test "[ENGINE] absolute custom redirect doesn't use SCRIPT_NAME from request" do
get "/awesome/blog/absolute_custom_redirect"
- verify_redirect "http://example.org/foo"
+ verify_redirect "http://www.example.com/foo"
end
# Inside Application
test "[APP] generating engine's route includes prefix" do
get "/generate"
- assert_equal "/awesome/blog/posts/1", last_response.body
+ assert_equal "/awesome/blog/posts/1", response.body
end
test "[APP] generating engine's route includes default_url_options[:script_name]" do
RailsApplication.routes.default_url_options = { script_name: "/something" }
get "/generate"
- assert_equal "/something/awesome/blog/posts/1", last_response.body
+ assert_equal "/something/awesome/blog/posts/1", response.body
end
test "[APP] generating engine's url with polymorphic path" do
get "/polymorphic_path_for_engine"
- assert_equal "/awesome/blog/posts/1", last_response.body
+ assert_equal "/awesome/blog/posts/1", response.body
end
test "polymorphic_path_for_app" do
get "/polymorphic_path_for_app"
- assert_equal "/posts/1", last_response.body
+ assert_equal "/posts/1", response.body
end
test "[APP] generating engine's url with url_for(@post)" do
get "/polymorphic_with_url_for"
- assert_equal "http://example.org/awesome/blog/posts/1", last_response.body
+ assert_equal "http://www.example.com/awesome/blog/posts/1", response.body
end
test "[APP] instance variable with same name as engine" do
get "/ivar_usage"
- assert_equal "/awesome/blog/posts/1", last_response.body
+ assert_equal "/awesome/blog/posts/1", response.body
end
# Inside any Object
@@ -322,9 +320,9 @@ module TestGenerationPrefix
private
def verify_redirect(url, status = 301)
- assert_equal status, last_response.status
- assert_equal url, last_response.headers["Location"]
- assert_equal expected_redirect_body(url), last_response.body
+ assert_equal status, response.status
+ assert_equal url, response.headers["Location"]
+ assert_equal expected_redirect_body(url), response.body
end
def expected_redirect_body(url)
@@ -333,8 +331,6 @@ module TestGenerationPrefix
end
class EngineMountedAtRoot < ActionDispatch::IntegrationTest
- include Rack::Test::Methods
-
class BlogEngine
def self.routes
@routes ||= begin
@@ -388,74 +384,74 @@ module TestGenerationPrefix
test "generating path inside engine" do
get "/posts/1"
- assert_equal "/posts/1", last_response.body
+ assert_equal "/posts/1", response.body
end
test "[ENGINE] relative path root uses SCRIPT_NAME from request" do
get "/relative_path_root"
- verify_redirect "http://example.org/"
+ verify_redirect "http://www.example.com/"
end
test "[ENGINE] relative path redirect uses SCRIPT_NAME from request" do
get "/relative_path_redirect"
- verify_redirect "http://example.org/foo"
+ verify_redirect "http://www.example.com/foo"
end
test "[ENGINE] relative option root uses SCRIPT_NAME from request" do
get "/relative_option_root"
- verify_redirect "http://example.org/"
+ verify_redirect "http://www.example.com/"
end
test "[ENGINE] relative option redirect uses SCRIPT_NAME from request" do
get "/relative_option_redirect"
- verify_redirect "http://example.org/foo"
+ verify_redirect "http://www.example.com/foo"
end
test "[ENGINE] relative custom root uses SCRIPT_NAME from request" do
get "/relative_custom_root"
- verify_redirect "http://example.org/"
+ verify_redirect "http://www.example.com/"
end
test "[ENGINE] relative custom redirect uses SCRIPT_NAME from request" do
get "/relative_custom_redirect"
- verify_redirect "http://example.org/foo"
+ verify_redirect "http://www.example.com/foo"
end
test "[ENGINE] absolute path root doesn't use SCRIPT_NAME from request" do
get "/absolute_path_root"
- verify_redirect "http://example.org/"
+ verify_redirect "http://www.example.com/"
end
test "[ENGINE] absolute path redirect doesn't use SCRIPT_NAME from request" do
get "/absolute_path_redirect"
- verify_redirect "http://example.org/foo"
+ verify_redirect "http://www.example.com/foo"
end
test "[ENGINE] absolute option root doesn't use SCRIPT_NAME from request" do
get "/absolute_option_root"
- verify_redirect "http://example.org/"
+ verify_redirect "http://www.example.com/"
end
test "[ENGINE] absolute option redirect doesn't use SCRIPT_NAME from request" do
get "/absolute_option_redirect"
- verify_redirect "http://example.org/foo"
+ verify_redirect "http://www.example.com/foo"
end
test "[ENGINE] absolute custom root doesn't use SCRIPT_NAME from request" do
get "/absolute_custom_root"
- verify_redirect "http://example.org/"
+ verify_redirect "http://www.example.com/"
end
test "[ENGINE] absolute custom redirect doesn't use SCRIPT_NAME from request" do
get "/absolute_custom_redirect"
- verify_redirect "http://example.org/foo"
+ verify_redirect "http://www.example.com/foo"
end
private
def verify_redirect(url, status = 301)
- assert_equal status, last_response.status
- assert_equal url, last_response.headers["Location"]
- assert_equal expected_redirect_body(url), last_response.body
+ assert_equal status, response.status
+ assert_equal url, response.headers["Location"]
+ assert_equal expected_redirect_body(url), response.body
end
def expected_redirect_body(url)
diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb
index e11b93b4f0..2f9228a62d 100644
--- a/actionpack/test/dispatch/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -760,8 +760,8 @@ class RequestMethod < BaseRequestTest
end
test "post uneffected by local inflections" do
- existing_acrnoyms = ActiveSupport::Inflector.inflections.acronyms.dup
- existing_acrnoym_regex = ActiveSupport::Inflector.inflections.acronym_regex.dup
+ existing_acronyms = ActiveSupport::Inflector.inflections.acronyms.dup
+ existing_acronym_regex = ActiveSupport::Inflector.inflections.acronym_regex.dup
begin
ActiveSupport::Inflector.inflections do |inflect|
inflect.acronym "POS"
@@ -774,8 +774,8 @@ class RequestMethod < BaseRequestTest
ensure
# Reset original acronym set
ActiveSupport::Inflector.inflections do |inflect|
- inflect.send(:instance_variable_set, "@acronyms", existing_acrnoyms)
- inflect.send(:instance_variable_set, "@acronym_regex", existing_acrnoym_regex)
+ inflect.send(:instance_variable_set, "@acronyms", existing_acronyms)
+ inflect.send(:instance_variable_set, "@acronym_regex", existing_acronym_regex)
end
end
end
diff --git a/actionpack/test/dispatch/session/cookie_store_test.rb b/actionpack/test/dispatch/session/cookie_store_test.rb
index 2a1053be16..63dfc07c0d 100644
--- a/actionpack/test/dispatch/session/cookie_store_test.rb
+++ b/actionpack/test/dispatch/session/cookie_store_test.rb
@@ -175,7 +175,7 @@ class CookieStoreTest < ActionDispatch::IntegrationTest
def test_doesnt_write_session_cookie_if_session_is_unchanged
with_test_route_set do
- cookies[SessionKey] = "BAh7BjoIZm9vIghiYXI%3D--" +
+ cookies[SessionKey] = "BAh7BjoIZm9vIghiYXI%3D--" \
"fef868465920f415f2c0652d6910d3af288a0367"
get "/no_session_access"
assert_response :success
diff --git a/actionpack/test/dispatch/ssl_test.rb b/actionpack/test/dispatch/ssl_test.rb
index e29ffa750c..757e26973f 100644
--- a/actionpack/test/dispatch/ssl_test.rb
+++ b/actionpack/test/dispatch/ssl_test.rb
@@ -102,7 +102,11 @@ class StrictTransportSecurityTest < SSLTest
def assert_hsts(expected, url: "https://example.org", hsts: { subdomains: true }, headers: {})
self.app = build_app ssl_options: { hsts: hsts }, headers: headers
get url
- assert_equal expected, response.headers["Strict-Transport-Security"]
+ if expected.nil?
+ assert_nil response.headers["Strict-Transport-Security"]
+ else
+ assert_equal expected, response.headers["Strict-Transport-Security"]
+ end
end
test "enabled by default" do
@@ -130,7 +134,7 @@ class StrictTransportSecurityTest < SSLTest
end
test ":expires supports AS::Duration arguments" do
- assert_hsts "max-age=31557600; includeSubDomains", hsts: { expires: 1.year }
+ assert_hsts "max-age=31556952; includeSubDomains", hsts: { expires: 1.year }
end
test "include subdomains" do
diff --git a/actionpack/test/lib/controller/fake_models.rb b/actionpack/test/lib/controller/fake_models.rb
index 046b4167bb..b768553e7a 100644
--- a/actionpack/test/lib/controller/fake_models.rb
+++ b/actionpack/test/lib/controller/fake_models.rb
@@ -1,6 +1,6 @@
require "active_model"
-class Customer < Struct.new(:name, :id)
+Customer = Struct.new(:name, :id) do
extend ActiveModel::Naming
include ActiveModel::Conversion
@@ -28,7 +28,7 @@ class Customer < Struct.new(:name, :id)
end
end
-class Post < Struct.new(:title, :author_name, :body, :secret, :persisted, :written_on, :cost)
+Post = Struct.new(:title, :author_name, :body, :secret, :persisted, :written_on, :cost) do
extend ActiveModel::Naming
include ActiveModel::Conversion
extend ActiveModel::Translation
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index 59afed1f98..b071b260c9 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -1,3 +1,23 @@
+* Change the ERB handler from Erubis to Erubi.
+
+ Erubi is an Erubis fork that's svelte, simple, and currently maintained.
+ Plus it supports `--enable-frozen-string-literal` in Ruby 2.3+.
+
+ Compatibility: Drops support for `<%===` tags for debug output.
+ These were an unused, undocumented side effect of the Erubis
+ implementation.
+
+ Deprecation: The Erubis handler will be removed in Rails 5.2, for the
+ handful of folks using it directly.
+
+ *Jeremy Evans*
+
+* Allow render locals to be assigned to instance variables in a view.
+
+ Fixes #27480.
+
+ *Andrew White*
+
* Add `check_parameters` option to `current_page?` which makes it more strict.
*Maksym Pugach*
diff --git a/actionview/actionview.gemspec b/actionview/actionview.gemspec
index 7bfdfbe29a..cfaa5007a1 100644
--- a/actionview/actionview.gemspec
+++ b/actionview/actionview.gemspec
@@ -22,8 +22,8 @@ Gem::Specification.new do |s|
s.add_dependency "activesupport", version
s.add_dependency "builder", "~> 3.1"
- s.add_dependency "erubis", "~> 2.7.0"
- s.add_dependency "rails-html-sanitizer", "~> 1.0", ">= 1.0.2"
+ s.add_dependency "erubi", "~> 1.4"
+ s.add_dependency "rails-html-sanitizer", "~> 1.0", ">= 1.0.3"
s.add_dependency "rails-dom-testing", "~> 2.0"
s.add_development_dependency "actionpack", version
diff --git a/actionview/app/assets/javascripts/utils/event.coffee b/actionview/app/assets/javascripts/utils/event.coffee
index 049b2a3ecd..d25fe8e546 100644
--- a/actionview/app/assets/javascripts/utils/event.coffee
+++ b/actionview/app/assets/javascripts/utils/event.coffee
@@ -13,7 +13,7 @@ if typeof CustomEvent is 'function'
evt
CustomEvent.prototype = window.Event.prototype
-# Triggers an custom event on an element and returns false if the event result is false
+# Triggers a custom event on an element and returns false if the event result is false
fire = Rails.fire = (obj, name, data) ->
event = new CustomEvent(
name,
diff --git a/actionview/lib/action_view/base.rb b/actionview/lib/action_view/base.rb
index b7c05fdb88..5387174467 100644
--- a/actionview/lib/action_view/base.rb
+++ b/actionview/lib/action_view/base.rb
@@ -11,7 +11,7 @@ module ActionView #:nodoc:
# = Action View Base
#
# Action View templates can be written in several ways.
- # If the template file has a <tt>.erb</tt> extension, then it uses the erubis[https://rubygems.org/gems/erubis]
+ # If the template file has a <tt>.erb</tt> extension, then it uses the erubi[https://rubygems.org/gems/erubi]
# template system which can embed Ruby into an HTML document.
# If the template file has a <tt>.builder</tt> extension, then Jim Weirich's Builder::XmlMarkup library is used.
#
diff --git a/actionview/lib/action_view/helpers/asset_tag_helper.rb b/actionview/lib/action_view/helpers/asset_tag_helper.rb
index 72a094c629..750f96f29e 100644
--- a/actionview/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionview/lib/action_view/helpers/asset_tag_helper.rb
@@ -40,7 +40,7 @@ module ActionView
# When the last parameter is a hash you can add HTML attributes using that
# parameter. The following options are supported:
#
- # * <tt>:extname</tt> - Append a extention to the generated url unless the extension
+ # * <tt>:extname</tt> - Append an extension to the generated url unless the extension
# already exists. This only applies for relative urls.
# * <tt>:protocol</tt> - Sets the protocol of the generated url, this option only
# applies when a relative url and +host+ options are provided.
diff --git a/actionview/lib/action_view/helpers/asset_url_helper.rb b/actionview/lib/action_view/helpers/asset_url_helper.rb
index c6a5e04aba..03bd1eb008 100644
--- a/actionview/lib/action_view/helpers/asset_url_helper.rb
+++ b/actionview/lib/action_view/helpers/asset_url_helper.rb
@@ -237,7 +237,11 @@ module ActionView
def compute_asset_extname(source, options = {})
return if options[:extname] == false
extname = options[:extname] || ASSET_EXTENSIONS[options[:type]]
- extname if extname && File.extname(source) != extname
+ if extname && File.extname(source) != extname
+ extname
+ else
+ nil
+ end
end
# Maps asset types to public directory.
@@ -406,7 +410,7 @@ module ActionView
def video_url(source, options = {})
url_to_asset(source, { type: :video }.merge!(options))
end
- alias_method :url_to_video, :video_url # aliased to avoid conflicts with an video_url named route
+ alias_method :url_to_video, :video_url # aliased to avoid conflicts with a video_url named route
# Computes the path to an audio asset in the public audios directory.
# Full paths from the document root will be passed through.
@@ -445,7 +449,7 @@ module ActionView
def font_path(source, options = {})
path_to_asset(source, { type: :font }.merge!(options))
end
- alias_method :path_to_font, :font_path # aliased to avoid conflicts with an font_path named route
+ alias_method :path_to_font, :font_path # aliased to avoid conflicts with a font_path named route
# Computes the full URL to a font asset.
# This will use +font_path+ internally, so most of their behaviors will be the same.
@@ -457,7 +461,7 @@ module ActionView
def font_url(source, options = {})
url_to_asset(source, { type: :font }.merge!(options))
end
- alias_method :url_to_font, :font_url # aliased to avoid conflicts with an font_url named route
+ alias_method :url_to_font, :font_url # aliased to avoid conflicts with a font_url named route
end
end
end
diff --git a/actionview/lib/action_view/helpers/cache_helper.rb b/actionview/lib/action_view/helpers/cache_helper.rb
index 7fdf0fd0e1..15ab7e304f 100644
--- a/actionview/lib/action_view/helpers/cache_helper.rb
+++ b/actionview/lib/action_view/helpers/cache_helper.rb
@@ -241,8 +241,6 @@ module ActionView
end
def write_fragment_for(name, options)
- # VIEW TODO: Make #capture usable outside of ERB
- # This dance is needed because Builder can't use capture
pos = output_buffer.length
yield
output_safe = output_buffer.html_safe?
diff --git a/actionview/lib/action_view/helpers/number_helper.rb b/actionview/lib/action_view/helpers/number_helper.rb
index 9e80f0b2ee..b6bc5f4f6f 100644
--- a/actionview/lib/action_view/helpers/number_helper.rb
+++ b/actionview/lib/action_view/helpers/number_helper.rb
@@ -92,7 +92,7 @@ module ActionView
# (defaults to "%u%n"). Fields are <tt>%u</tt> for the
# currency, and <tt>%n</tt> for the number.
# * <tt>:negative_format</tt> - Sets the format for negative
- # numbers (defaults to prepending an hyphen to the formatted
+ # numbers (defaults to prepending a hyphen to the formatted
# number given by <tt>:format</tt>). Accepts the same fields
# than <tt>:format</tt>, except <tt>%n</tt> is here the
# absolute value of the number.
diff --git a/actionview/lib/action_view/helpers/output_safety_helper.rb b/actionview/lib/action_view/helpers/output_safety_helper.rb
index 9f1a890f6a..25defd1276 100644
--- a/actionview/lib/action_view/helpers/output_safety_helper.rb
+++ b/actionview/lib/action_view/helpers/output_safety_helper.rb
@@ -25,7 +25,7 @@ module ActionView #:nodoc:
# safe_join([raw("<p>foo</p>"), "<p>bar</p>"], "<br />")
# # => "<p>foo</p>&lt;br /&gt;&lt;p&gt;bar&lt;/p&gt;"
#
- # safe_join([raw("<p>foo</p>"), raw("<p>bar</p>")], raw("<br />")
+ # safe_join([raw("<p>foo</p>"), raw("<p>bar</p>")], raw("<br />"))
# # => "<p>foo</p><br /><p>bar</p>"
#
def safe_join(array, sep = $,)
@@ -60,7 +60,7 @@ module ActionView #:nodoc:
when 2
safe_join([array[0], array[1]], options[:two_words_connector])
else
- safe_join([safe_join(array[0...-1], options[:words_connector]), options[:last_word_connector], array[-1]])
+ safe_join([safe_join(array[0...-1], options[:words_connector]), options[:last_word_connector], array[-1]], nil)
end
end
end
diff --git a/actionview/lib/action_view/helpers/sanitize_helper.rb b/actionview/lib/action_view/helpers/sanitize_helper.rb
index 3d6ff598ee..1e9b813d3d 100644
--- a/actionview/lib/action_view/helpers/sanitize_helper.rb
+++ b/actionview/lib/action_view/helpers/sanitize_helper.rb
@@ -45,17 +45,15 @@ module ActionView
# Providing a custom Rails::Html scrubber:
#
# class CommentScrubber < Rails::Html::PermitScrubber
- # def allowed_node?(node)
- # !%w(form script comment blockquote).include?(node.name)
+ # def initialize
+ # super
+ # self.tags = %w( form script comment blockquote )
+ # self.attributes = %w( style )
# end
#
# def skip_node?(node)
# node.text?
# end
- #
- # def scrub_attribute?(name)
- # name == 'style'
- # end
# end
#
# <%= sanitize @comment.body, scrubber: CommentScrubber.new %>
diff --git a/actionview/lib/action_view/helpers/text_helper.rb b/actionview/lib/action_view/helpers/text_helper.rb
index 07dccf5b41..bc922f9ce8 100644
--- a/actionview/lib/action_view/helpers/text_helper.rb
+++ b/actionview/lib/action_view/helpers/text_helper.rb
@@ -187,7 +187,7 @@ module ActionView
unless separator.empty?
text.split(separator).each do |value|
if value.match(regex)
- regex = phrase = value
+ phrase = value
break
end
end
diff --git a/actionview/lib/action_view/helpers/url_helper.rb b/actionview/lib/action_view/helpers/url_helper.rb
index 1f753bccd6..a306903c60 100644
--- a/actionview/lib/action_view/helpers/url_helper.rb
+++ b/actionview/lib/action_view/helpers/url_helper.rb
@@ -35,7 +35,7 @@ module ActionView
when :back
_back_url
else
- raise ArgumentError, "arguments passed to url_for can't be handled. Please require " +
+ raise ArgumentError, "arguments passed to url_for can't be handled. Please require " \
"routes or provide your own implementation"
end
end
diff --git a/actionview/lib/action_view/renderer/partial_renderer.rb b/actionview/lib/action_view/renderer/partial_renderer.rb
index b8a79da97f..2bb4465131 100644
--- a/actionview/lib/action_view/renderer/partial_renderer.rb
+++ b/actionview/lib/action_view/renderer/partial_renderer.rb
@@ -99,7 +99,7 @@ module ActionView
# <%= render partial: "ad", collection: @advertisements, spacer_template: "ad_divider" %>
#
# If the given <tt>:collection</tt> is +nil+ or empty, <tt>render</tt> will return nil. This will allow you
- # to specify a text which will displayed instead by using this form:
+ # to specify a text which will be displayed instead by using this form:
#
# <%= render(partial: "ad", collection: @advertisements) || "There's no ad to be displayed" %>
#
@@ -532,11 +532,11 @@ module ActionView
[variable, variable_counter, variable_iteration]
end
- IDENTIFIER_ERROR_MESSAGE = "The partial name (%s) is not a valid Ruby identifier; " +
+ IDENTIFIER_ERROR_MESSAGE = "The partial name (%s) is not a valid Ruby identifier; " \
"make sure your partial name starts with underscore."
- OPTION_AS_ERROR_MESSAGE = "The value (%s) of the option `as` is not a valid Ruby identifier; " +
- "make sure it starts with lowercase letter, " +
+ OPTION_AS_ERROR_MESSAGE = "The value (%s) of the option `as` is not a valid Ruby identifier; " \
+ "make sure it starts with lowercase letter, " \
"and is followed by any combination of letters, numbers and underscores."
def raise_invalid_identifier(path)
diff --git a/actionview/lib/action_view/renderer/streaming_template_renderer.rb b/actionview/lib/action_view/renderer/streaming_template_renderer.rb
index 7ede034492..62ce985243 100644
--- a/actionview/lib/action_view/renderer/streaming_template_renderer.rb
+++ b/actionview/lib/action_view/renderer/streaming_template_renderer.rb
@@ -4,7 +4,6 @@ module ActionView
# == TODO
#
# * Support streaming from child templates, partials and so on.
- # * Integrate exceptions with exceptron
# * Rack::Cache needs to support streaming bodies
class StreamingTemplateRenderer < TemplateRenderer #:nodoc:
# A valid Rack::Body (i.e. it responds to each).
@@ -28,7 +27,6 @@ module ActionView
private
# This is the same logging logic as in ShowExceptions middleware.
- # TODO Once "exceptron" is in, refactor this piece to simply re-use exceptron.
def log_error(exception)
logger = ActionView::Base.logger
return unless logger
diff --git a/actionview/lib/action_view/rendering.rb b/actionview/lib/action_view/rendering.rb
index 0e72316eb7..cf18562c45 100644
--- a/actionview/lib/action_view/rendering.rb
+++ b/actionview/lib/action_view/rendering.rb
@@ -124,7 +124,11 @@ module ActionView
key = action.include?(?/) ? :template : :action
options[key] = action
else
- options[:partial] = action
+ if action.respond_to?(:permitted?) && action.permitted?
+ options = action
+ else
+ options[:partial] = action
+ end
end
options
diff --git a/actionview/lib/action_view/template.rb b/actionview/lib/action_view/template.rb
index 4b793c3b16..c067031d2d 100644
--- a/actionview/lib/action_view/template.rb
+++ b/actionview/lib/action_view/template.rb
@@ -326,7 +326,7 @@ module ActionView
# Only locals with valid variable names get set directly. Others will
# still be available in local_assigns.
locals = @locals - Module::RUBY_RESERVED_KEYWORDS
- locals = locals.grep(/\A(?![A-Z0-9])(?:[[:alnum:]_]|[^\0-\177])+\z/)
+ locals = locals.grep(/\A@?(?![A-Z0-9])(?:[[:alnum:]_]|[^\0-\177])+\z/)
# Double assign to suppress the dreaded 'assigned but unused variable' warning
locals.each_with_object("") { |key, code| code << "#{key} = #{key} = local_assigns[:#{key}];" }
diff --git a/actionview/lib/action_view/template/handlers/builder.rb b/actionview/lib/action_view/template/handlers/builder.rb
index 494b543152..e99b921cb7 100644
--- a/actionview/lib/action_view/template/handlers/builder.rb
+++ b/actionview/lib/action_view/template/handlers/builder.rb
@@ -7,7 +7,7 @@ module ActionView
def call(template)
require_engine
- "xml = ::Builder::XmlMarkup.new(:indent => 2);" +
+ "xml = ::Builder::XmlMarkup.new(:indent => 2);" \
"self.output_buffer = xml.target!;" +
template.source +
";xml.target!;"
diff --git a/actionview/lib/action_view/template/handlers/erb.rb b/actionview/lib/action_view/template/handlers/erb.rb
index 5d047a6991..cee5408aa9 100644
--- a/actionview/lib/action_view/template/handlers/erb.rb
+++ b/actionview/lib/action_view/template/handlers/erb.rb
@@ -1,79 +1,12 @@
-require "erubis"
-
module ActionView
class Template
module Handlers
- class Erubis < ::Erubis::Eruby
- def add_preamble(src)
- @newline_pending = 0
- src << "@output_buffer = output_buffer || ActionView::OutputBuffer.new;"
- end
-
- def add_text(src, text)
- return if text.empty?
-
- if text == "\n"
- @newline_pending += 1
- else
- src << "@output_buffer.safe_append='"
- src << "\n" * @newline_pending if @newline_pending > 0
- src << escape_text(text)
- src << "'.freeze;"
-
- @newline_pending = 0
- end
- end
-
- # Erubis toggles <%= and <%== behavior when escaping is enabled.
- # We override to always treat <%== as escaped.
- def add_expr(src, code, indicator)
- case indicator
- when "=="
- add_expr_escaped(src, code)
- else
- super
- end
- end
-
- BLOCK_EXPR = /\s*((\s+|\))do|\{)(\s*\|[^|]*\|)?\s*\Z/
-
- def add_expr_literal(src, code)
- flush_newline_if_pending(src)
- if BLOCK_EXPR.match?(code)
- src << "@output_buffer.append= " << code
- else
- src << "@output_buffer.append=(" << code << ");"
- end
- end
-
- def add_expr_escaped(src, code)
- flush_newline_if_pending(src)
- if BLOCK_EXPR.match?(code)
- src << "@output_buffer.safe_expr_append= " << code
- else
- src << "@output_buffer.safe_expr_append=(" << code << ");"
- end
- end
-
- def add_stmt(src, code)
- flush_newline_if_pending(src)
- super
- end
-
- def add_postamble(src)
- flush_newline_if_pending(src)
- src << "@output_buffer.to_s"
- end
-
- def flush_newline_if_pending(src)
- if @newline_pending > 0
- src << "@output_buffer.safe_append='#{"\n" * @newline_pending}'.freeze;"
- @newline_pending = 0
- end
- end
- end
+ Erubis = ActiveSupport::Deprecation::DeprecatedConstantProxy.new("Erubis", "ActionView::Template::Handlers::ERB::Erubis", message: "ActionView::Template::Handlers::Erubis is deprecated and will be removed from Rails 5.2. Switch to ActionView::Template::Handlers::ERB::Erubi instead.")
class ERB
+ autoload :Erubi, "action_view/template/handlers/erb/erubi"
+ autoload :Erubis, "action_view/template/handlers/erb/erubis"
+
# Specify trim mode for the ERB compiler. Defaults to '-'.
# See ERB documentation for suitable values.
class_attribute :erb_trim_mode
@@ -81,7 +14,7 @@ module ActionView
# Default implementation used.
class_attribute :erb_implementation
- self.erb_implementation = Erubis
+ self.erb_implementation = Erubi
# Do not escape templates of these mime types.
class_attribute :escape_whitelist
diff --git a/actionview/lib/action_view/template/handlers/erb/erubi.rb b/actionview/lib/action_view/template/handlers/erb/erubi.rb
new file mode 100644
index 0000000000..755cc84015
--- /dev/null
+++ b/actionview/lib/action_view/template/handlers/erb/erubi.rb
@@ -0,0 +1,81 @@
+require "erubi"
+
+module ActionView
+ class Template
+ module Handlers
+ class ERB
+ class Erubi < ::Erubi::Engine
+ # :nodoc: all
+ def initialize(input, properties = {})
+ @newline_pending = 0
+
+ # Dup properties so that we don't modify argument
+ properties = Hash[properties]
+ properties[:preamble] = "@output_buffer = output_buffer || ActionView::OutputBuffer.new;"
+ properties[:postamble] = "@output_buffer.to_s"
+ properties[:bufvar] = "@output_buffer"
+ properties[:escapefunc] = ""
+
+ super
+ end
+
+ def evaluate(action_view_erb_handler_context)
+ pr = eval("proc { #{@src} }", binding, @filename || "(erubi)")
+ action_view_erb_handler_context.instance_eval(&pr)
+ end
+
+ private
+ def add_text(text)
+ return if text.empty?
+
+ if text == "\n"
+ @newline_pending += 1
+ else
+ src << "@output_buffer.safe_append='"
+ src << "\n" * @newline_pending if @newline_pending > 0
+ src << text.gsub(/['\\]/, '\\\\\&')
+ src << "'.freeze;"
+
+ @newline_pending = 0
+ end
+ end
+
+ BLOCK_EXPR = /\s*((\s+|\))do|\{)(\s*\|[^|]*\|)?\s*\Z/
+
+ def add_expression(indicator, code)
+ flush_newline_if_pending(src)
+
+ if (indicator == "==") || @escape
+ src << "@output_buffer.safe_expr_append="
+ else
+ src << "@output_buffer.append="
+ end
+
+ if BLOCK_EXPR.match?(code)
+ src << " " << code
+ else
+ src << "(" << code << ");"
+ end
+ end
+
+ def add_code(code)
+ flush_newline_if_pending(src)
+ super
+ end
+
+ def add_postamble(_)
+ flush_newline_if_pending(src)
+ super
+ end
+
+ def flush_newline_if_pending(src)
+ if @newline_pending > 0
+ src << "@output_buffer.safe_append='#{"\n" * @newline_pending}'.freeze;"
+ @newline_pending = 0
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/actionview/lib/action_view/template/handlers/erb/erubis.rb b/actionview/lib/action_view/template/handlers/erb/erubis.rb
new file mode 100644
index 0000000000..bf316ceec5
--- /dev/null
+++ b/actionview/lib/action_view/template/handlers/erb/erubis.rb
@@ -0,0 +1,80 @@
+require "erubis"
+
+module ActionView
+ class Template
+ module Handlers
+ class ERB
+ class Erubis < ::Erubis::Eruby
+ # :nodoc: all
+ def add_preamble(src)
+ @newline_pending = 0
+ src << "@output_buffer = output_buffer || ActionView::OutputBuffer.new;"
+ end
+
+ def add_text(src, text)
+ return if text.empty?
+
+ if text == "\n"
+ @newline_pending += 1
+ else
+ src << "@output_buffer.safe_append='"
+ src << "\n" * @newline_pending if @newline_pending > 0
+ src << escape_text(text)
+ src << "'.freeze;"
+
+ @newline_pending = 0
+ end
+ end
+
+ # Erubis toggles <%= and <%== behavior when escaping is enabled.
+ # We override to always treat <%== as escaped.
+ def add_expr(src, code, indicator)
+ case indicator
+ when "=="
+ add_expr_escaped(src, code)
+ else
+ super
+ end
+ end
+
+ BLOCK_EXPR = /\s*((\s+|\))do|\{)(\s*\|[^|]*\|)?\s*\Z/
+
+ def add_expr_literal(src, code)
+ flush_newline_if_pending(src)
+ if BLOCK_EXPR.match?(code)
+ src << "@output_buffer.append= " << code
+ else
+ src << "@output_buffer.append=(" << code << ");"
+ end
+ end
+
+ def add_expr_escaped(src, code)
+ flush_newline_if_pending(src)
+ if BLOCK_EXPR.match?(code)
+ src << "@output_buffer.safe_expr_append= " << code
+ else
+ src << "@output_buffer.safe_expr_append=(" << code << ");"
+ end
+ end
+
+ def add_stmt(src, code)
+ flush_newline_if_pending(src)
+ super
+ end
+
+ def add_postamble(src)
+ flush_newline_if_pending(src)
+ src << "@output_buffer.to_s"
+ end
+
+ def flush_newline_if_pending(src)
+ if @newline_pending > 0
+ src << "@output_buffer.safe_append='#{"\n" * @newline_pending}'.freeze;"
+ @newline_pending = 0
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/actionview/lib/action_view/template/resolver.rb b/actionview/lib/action_view/template/resolver.rb
index 9da13663d7..924de3da06 100644
--- a/actionview/lib/action_view/template/resolver.rb
+++ b/actionview/lib/action_view/template/resolver.rb
@@ -164,8 +164,8 @@ module ActionView
# This is what child classes implement. No defaults are needed
# because Resolver guarantees that the arguments are present and
# normalized.
- def find_templates(name, prefix, partial, details)
- raise NotImplementedError, "Subclasses must implement a find_templates(name, prefix, partial, details) method"
+ def find_templates(name, prefix, partial, details, outside_app_allowed = false)
+ raise NotImplementedError, "Subclasses must implement a find_templates(name, prefix, partial, details, outside_app_allowed = false) method"
end
# Helpers that builds a path. Useful for building virtual paths.
diff --git a/actionview/test/abstract_unit.rb b/actionview/test/abstract_unit.rb
index fbdaa07fb0..dde66a7ba0 100644
--- a/actionview/test/abstract_unit.rb
+++ b/actionview/test/abstract_unit.rb
@@ -271,15 +271,15 @@ module ActionDispatch
end
end
-# Skips the current run on Rubinius using Minitest::Assertions#skip
-def rubinius_skip(message = "")
- skip message if RUBY_ENGINE == "rbx"
-end
-# Skips the current run on JRuby using Minitest::Assertions#skip
-def jruby_skip(message = "")
- skip message if defined?(JRUBY_VERSION)
-end
-
class ActiveSupport::TestCase
include ActiveSupport::Testing::MethodCallAssertions
+
+ # Skips the current run on Rubinius using Minitest::Assertions#skip
+ private def rubinius_skip(message = "")
+ skip message if RUBY_ENGINE == "rbx"
+ end
+ # Skips the current run on JRuby using Minitest::Assertions#skip
+ private def jruby_skip(message = "")
+ skip message if defined?(JRUBY_VERSION)
+ end
end
diff --git a/actionview/test/actionpack/controller/render_test.rb b/actionview/test/actionpack/controller/render_test.rb
index b4a757d6b8..890041914c 100644
--- a/actionview/test/actionpack/controller/render_test.rb
+++ b/actionview/test/actionpack/controller/render_test.rb
@@ -5,7 +5,7 @@ class ApplicationController < ActionController::Base
self.view_paths = File.join(FIXTURE_LOAD_PATH, "actionpack")
end
-class Customer < Struct.new(:name, :id)
+Customer = Struct.new(:name, :id) do
extend ActiveModel::Naming
include ActiveModel::Conversion
@@ -39,7 +39,7 @@ end
module Quiz
#Models
- class Question < Struct.new(:name, :id)
+ Question = Struct.new(:name, :id) do
extend ActiveModel::Naming
include ActiveModel::Conversion
diff --git a/actionview/test/activerecord/form_helper_activerecord_test.rb b/actionview/test/activerecord/form_helper_activerecord_test.rb
index 0f7960b408..3b314588c7 100644
--- a/actionview/test/activerecord/form_helper_activerecord_test.rb
+++ b/actionview/test/activerecord/form_helper_activerecord_test.rb
@@ -45,7 +45,7 @@ class FormHelperActiveRecordTest < ActionView::TestCase
end
expected = whole_form("/developers/123", "edit_developer_123", "edit_developer", method: "patch") do
- '<input id="developer_projects_attributes_abc_name" name="developer[projects_attributes][abc][name]" type="text" value="project #321" />' +
+ '<input id="developer_projects_attributes_abc_name" name="developer[projects_attributes][abc][name]" type="text" value="project #321" />' \
'<input id="developer_projects_attributes_abc_id" name="developer[projects_attributes][abc][id]" type="hidden" value="321" />'
end
diff --git a/actionview/test/activerecord/render_partial_with_record_identification_test.rb b/actionview/test/activerecord/render_partial_with_record_identification_test.rb
index 55886da30f..60c3ab3045 100644
--- a/actionview/test/activerecord/render_partial_with_record_identification_test.rb
+++ b/actionview/test/activerecord/render_partial_with_record_identification_test.rb
@@ -87,7 +87,7 @@ class RenderPartialWithRecordIdentificationTest < ActiveRecordTestCase
end
end
-class Game < Struct.new(:name, :id)
+Game = Struct.new(:name, :id) do
extend ActiveModel::Naming
include ActiveModel::Conversion
def to_param
diff --git a/actionview/test/fixtures/test/render_file_instance_variable.erb b/actionview/test/fixtures/test/render_file_instance_variable.erb
new file mode 100644
index 0000000000..5344ac8a66
--- /dev/null
+++ b/actionview/test/fixtures/test/render_file_instance_variable.erb
@@ -0,0 +1 @@
+<%= @foo %> \ No newline at end of file
diff --git a/actionview/test/lib/controller/fake_models.rb b/actionview/test/lib/controller/fake_models.rb
index ddc915895d..8db52ccbe1 100644
--- a/actionview/test/lib/controller/fake_models.rb
+++ b/actionview/test/lib/controller/fake_models.rb
@@ -1,6 +1,6 @@
require "active_model"
-class Customer < Struct.new(:name, :id)
+Customer = Struct.new(:name, :id) do
extend ActiveModel::Naming
include ActiveModel::Conversion
@@ -31,7 +31,7 @@ end
class GoodCustomer < Customer
end
-class Post < Struct.new(:title, :author_name, :body, :secret, :persisted, :written_on, :cost)
+Post = Struct.new(:title, :author_name, :body, :secret, :persisted, :written_on, :cost) do
extend ActiveModel::Naming
include ActiveModel::Conversion
extend ActiveModel::Translation
@@ -163,7 +163,7 @@ module Blog
true
end
- class Post < Struct.new(:title, :id)
+ Post = Struct.new(:title, :id) do
extend ActiveModel::Naming
include ActiveModel::Conversion
@@ -183,8 +183,7 @@ class ArelLike
end
end
-class Car < Struct.new(:color)
-end
+Car = Struct.new(:color)
class Plane
attr_reader :to_key
diff --git a/actionview/test/template/active_model_helper_test.rb b/actionview/test/template/active_model_helper_test.rb
index 8b8f686f96..6b63aa25a5 100644
--- a/actionview/test/template/active_model_helper_test.rb
+++ b/actionview/test/template/active_model_helper_test.rb
@@ -4,7 +4,7 @@ class ActiveModelHelperTest < ActionView::TestCase
tests ActionView::Helpers::ActiveModelHelper
silence_warnings do
- class Post < Struct.new(:author_name, :body, :updated_at)
+ Post = Struct.new(:author_name, :body, :updated_at) do
include ActiveModel::Conversion
include ActiveModel::Validations
diff --git a/actionview/test/template/atom_feed_helper_test.rb b/actionview/test/template/atom_feed_helper_test.rb
index e9a923dd72..1245a1a966 100644
--- a/actionview/test/template/atom_feed_helper_test.rb
+++ b/actionview/test/template/atom_feed_helper_test.rb
@@ -1,6 +1,6 @@
require "abstract_unit"
-class Scroll < Struct.new(:id, :to_param, :title, :body, :updated_at, :created_at)
+Scroll = Struct.new(:id, :to_param, :title, :body, :updated_at, :created_at) do
extend ActiveModel::Naming
include ActiveModel::Conversion
diff --git a/actionview/test/template/compiled_templates_test.rb b/actionview/test/template/compiled_templates_test.rb
index 40ac867b38..adb2be9be4 100644
--- a/actionview/test/template/compiled_templates_test.rb
+++ b/actionview/test/template/compiled_templates_test.rb
@@ -38,6 +38,10 @@ class CompiledTemplatesTest < ActiveSupport::TestCase
assert_equal "🎂", render(file: "test/render_file_unicode_local", locals: { 🎃: "🎂" })
end
+ def test_template_with_instance_variable_identifier
+ assert_equal "bar", render(file: "test/render_file_instance_variable", locals: { "@foo": "bar" })
+ end
+
def test_template_gets_recompiled_when_using_different_keys_in_local_assigns
assert_equal "one", render(file: "test/render_file_with_locals_and_default")
assert_equal "two", render(file: "test/render_file_with_locals_and_default", locals: { secret: "two" })
diff --git a/actionview/test/template/erb/deprecated_erubis_implementation_test.rb b/actionview/test/template/erb/deprecated_erubis_implementation_test.rb
new file mode 100644
index 0000000000..4a130e6c33
--- /dev/null
+++ b/actionview/test/template/erb/deprecated_erubis_implementation_test.rb
@@ -0,0 +1,11 @@
+require "abstract_unit"
+
+module ERBTest
+ class DeprecatedErubisImplementationTest < ActionView::TestCase
+ test "Erubis implementation is deprecated" do
+ assert_deprecated "ActionView::Template::Handlers::Erubis is deprecated and will be removed from Rails 5.2. Switch to ActionView::Template::Handlers::ERB::Erubi instead." do
+ assert_equal "ActionView::Template::Handlers::ERB::Erubis", ActionView::Template::Handlers::Erubis.to_s
+ end
+ end
+ end
+end
diff --git a/actionview/test/template/erb/helper.rb b/actionview/test/template/erb/helper.rb
index a1973068d5..bc1eedc15f 100644
--- a/actionview/test/template/erb/helper.rb
+++ b/actionview/test/template/erb/helper.rb
@@ -14,7 +14,7 @@ module ERBTest
class BlockTestCase < ActiveSupport::TestCase
def render_content(start, inside)
template = block_helper(start, inside)
- ActionView::Template::Handlers::Erubis.new(template).evaluate(ViewContext.new)
+ ActionView::Template::Handlers::ERB.erb_implementation.new(template).evaluate(ViewContext.new)
end
def block_helper(str, rest)
diff --git a/actionview/test/template/erb_util_test.rb b/actionview/test/template/erb_util_test.rb
index 0a16364ed3..4412ea37fa 100644
--- a/actionview/test/template/erb_util_test.rb
+++ b/actionview/test/template/erb_util_test.rb
@@ -51,7 +51,12 @@ class ErbUtilTest < ActiveSupport::TestCase
def test_json_escape_does_not_alter_json_string_meaning
JSON_ESCAPE_TEST_CASES.each do |(raw, _)|
- assert_equal ActiveSupport::JSON.decode(raw), ActiveSupport::JSON.decode(json_escape(raw))
+ expected = ActiveSupport::JSON.decode(raw)
+ if expected.nil?
+ assert_nil ActiveSupport::JSON.decode(json_escape(raw))
+ else
+ assert_equal expected, ActiveSupport::JSON.decode(json_escape(raw))
+ end
end
end
diff --git a/actionview/test/template/form_collections_helper_test.rb b/actionview/test/template/form_collections_helper_test.rb
index 3774dcf872..6160524eb3 100644
--- a/actionview/test/template/form_collections_helper_test.rb
+++ b/actionview/test/template/form_collections_helper_test.rb
@@ -1,7 +1,6 @@
require "abstract_unit"
-class Category < Struct.new(:id, :name)
-end
+Category = Struct.new(:id, :name)
class FormCollectionsHelperTest < ActionView::TestCase
def assert_no_select(selector, value = nil)
diff --git a/actionview/test/template/form_helper/form_with_test.rb b/actionview/test/template/form_helper/form_with_test.rb
index 3a91c7dce7..a4a2966ff9 100644
--- a/actionview/test/template/form_helper/form_with_test.rb
+++ b/actionview/test/template/form_helper/form_with_test.rb
@@ -310,13 +310,13 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", "create-post", method: "patch") do
- "<label for='post_title'>The Title</label>" +
- "<input name='post[title]' type='text' value='Hello World' />" +
- "<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' />" +
- "<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />" +
- "<button name='button' type='submit'>Create post</button>" +
+ "<label for='post_title'>The Title</label>" \
+ "<input name='post[title]' type='text' value='Hello World' />" \
+ "<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' />" \
+ "<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>"
end
@@ -330,7 +330,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts") do
- '<label for="title">Label me</label>' +
+ '<label for="title">Label me</label>' \
'<input type="text" name="title">'
end
@@ -344,7 +344,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123") do
- '<label for="title">Label me</label>' +
+ '<label for="title">Label me</label>' \
'<input type="text" name="title">'
end
@@ -400,10 +400,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts") do
- "<input type='hidden' name='post[active]' value='' />" +
- "<input name='post[active]' type='radio' value='true' />" +
- "<label for='post_active_true'>true</label>" +
- "<input checked='checked' name='post[active]' type='radio' value='false' />" +
+ "<input type='hidden' name='post[active]' value='' />" \
+ "<input name='post[active]' type='radio' value='true' />" \
+ "<label for='post_active_true'>true</label>" \
+ "<input checked='checked' name='post[active]' type='radio' value='false' />" \
"<label for='post_active_false'>false</label>"
end
@@ -422,12 +422,12 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts") do
- "<input type='hidden' name='post[active]' value='' />" +
- "<label for='post_active_true'>" +
- "<input name='post[active]' type='radio' value='true' />" +
- "true</label>" +
- "<label for='post_active_false'>" +
- "<input checked='checked' name='post[active]' type='radio' value='false' />" +
+ "<input type='hidden' name='post[active]' value='' />" \
+ "<label for='post_active_true'>" \
+ "<input name='post[active]' type='radio' value='true' />" \
+ "true</label>" \
+ "<label for='post_active_false'>" \
+ "<input checked='checked' name='post[active]' type='radio' value='false' />" \
"false</label>"
end
@@ -448,13 +448,13 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts") do
- "<input type='hidden' name='post[active]' value='' />" +
- "<label for='post_active_true'>" +
- "<input name='post[active]' type='radio' value='true' />" +
- "true</label>" +
- "<label for='post_active_false'>" +
- "<input checked='checked' name='post[active]' type='radio' value='false' />" +
- "false</label>" +
+ "<input type='hidden' name='post[active]' value='' />" \
+ "<label for='post_active_true'>" \
+ "<input name='post[active]' type='radio' value='true' />" \
+ "true</label>" \
+ "<label for='post_active_false'>" \
+ "<input checked='checked' name='post[active]' type='radio' value='false' />" \
+ "false</label>" \
"<input name='post[id]' type='hidden' value='1' />"
end
@@ -470,10 +470,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts") do
- "<input type='hidden' name='post[1][active]' value='' />" +
- "<input name='post[1][active]' type='radio' value='true' />" +
- "<label for='post_1_active_true'>true</label>" +
- "<input checked='checked' name='post[1][active]' type='radio' value='false' />" +
+ "<input type='hidden' name='post[1][active]' value='' />" \
+ "<input name='post[1][active]' type='radio' value='true' />" \
+ "<label for='post_1_active_true'>true</label>" \
+ "<input checked='checked' name='post[1][active]' type='radio' value='false' />" \
"<label for='post_1_active_false'>false</label>"
end
@@ -489,12 +489,12 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts") do
- "<input name='post[tag_ids][]' type='hidden' value='' />" +
- "<input checked='checked' name='post[tag_ids][]' type='checkbox' value='1' />" +
- "<label for='post_tag_ids_1'>Tag 1</label>" +
- "<input name='post[tag_ids][]' type='checkbox' value='2' />" +
- "<label for='post_tag_ids_2'>Tag 2</label>" +
- "<input checked='checked' name='post[tag_ids][]' type='checkbox' value='3' />" +
+ "<input name='post[tag_ids][]' type='hidden' value='' />" \
+ "<input checked='checked' name='post[tag_ids][]' type='checkbox' value='1' />" \
+ "<label for='post_tag_ids_1'>Tag 1</label>" \
+ "<input name='post[tag_ids][]' type='checkbox' value='2' />" \
+ "<label for='post_tag_ids_2'>Tag 2</label>" \
+ "<input checked='checked' name='post[tag_ids][]' type='checkbox' value='3' />" \
"<label for='post_tag_ids_3'>Tag 3</label>"
end
@@ -513,15 +513,15 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts") do
- "<input name='post[tag_ids][]' type='hidden' value='' />" +
- "<label for='post_tag_ids_1'>" +
- "<input checked='checked' name='post[tag_ids][]' type='checkbox' value='1' />" +
- "Tag 1</label>" +
- "<label for='post_tag_ids_2'>" +
- "<input name='post[tag_ids][]' type='checkbox' value='2' />" +
- "Tag 2</label>" +
- "<label for='post_tag_ids_3'>" +
- "<input checked='checked' name='post[tag_ids][]' type='checkbox' value='3' />" +
+ "<input name='post[tag_ids][]' type='hidden' value='' />" \
+ "<label for='post_tag_ids_1'>" \
+ "<input checked='checked' name='post[tag_ids][]' type='checkbox' value='1' />" \
+ "Tag 1</label>" \
+ "<label for='post_tag_ids_2'>" \
+ "<input name='post[tag_ids][]' type='checkbox' value='2' />" \
+ "Tag 2</label>" \
+ "<label for='post_tag_ids_3'>" \
+ "<input checked='checked' name='post[tag_ids][]' type='checkbox' value='3' />" \
"Tag 3</label>"
end
@@ -543,16 +543,16 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts") do
- "<input name='post[tag_ids][]' type='hidden' value='' />" +
- "<label for='post_tag_ids_1'>" +
- "<input checked='checked' name='post[tag_ids][]' type='checkbox' value='1' />" +
- "Tag 1</label>" +
- "<label for='post_tag_ids_2'>" +
- "<input name='post[tag_ids][]' type='checkbox' value='2' />" +
- "Tag 2</label>" +
- "<label for='post_tag_ids_3'>" +
- "<input checked='checked' name='post[tag_ids][]' type='checkbox' value='3' />" +
- "Tag 3</label>" +
+ "<input name='post[tag_ids][]' type='hidden' value='' />" \
+ "<label for='post_tag_ids_1'>" \
+ "<input checked='checked' name='post[tag_ids][]' type='checkbox' value='1' />" \
+ "Tag 1</label>" \
+ "<label for='post_tag_ids_2'>" \
+ "<input name='post[tag_ids][]' type='checkbox' value='2' />" \
+ "Tag 2</label>" \
+ "<label for='post_tag_ids_3'>" \
+ "<input checked='checked' name='post[tag_ids][]' type='checkbox' value='3' />" \
+ "Tag 3</label>" \
"<input name='post[id]' type='hidden' value='1' />"
end
@@ -569,8 +569,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts") do
- "<input name='post[1][tag_ids][]' type='hidden' value='' />" +
- "<input checked='checked' name='post[1][tag_ids][]' type='checkbox' value='1' />" +
+ "<input name='post[1][tag_ids][]' type='hidden' value='' />" \
+ "<input checked='checked' name='post[1][tag_ids][]' type='checkbox' value='1' />" \
"<label for='post_1_tag_ids_1'>Tag 1</label>"
end
@@ -636,7 +636,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/44", method: "patch") do
- "<input name='post[title]' type='text' value='And his name will be forty and four.' />" +
+ "<input name='post[title]' type='text' value='And his name will be forty and four.' />" \
"<input name='commit' data-disable-with='Edit post' type='submit' value='Edit post' />"
end
@@ -653,11 +653,11 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", "create-post", method: "patch") do
- "<label for='other_name_title' class='post_title'>Title</label>" +
- "<input name='other_name[title]' value='Hello World' type='text' />" +
- "<textarea name='other_name[body]'>\nBack to the hill and over it again!</textarea>" +
- "<input name='other_name[secret]' value='0' type='hidden' />" +
- "<input name='other_name[secret]' checked='checked' value='1' type='checkbox' />" +
+ "<label for='other_name_title' class='post_title'>Title</label>" \
+ "<input name='other_name[title]' value='Hello World' type='text' />" \
+ "<textarea name='other_name[body]'>\nBack to the hill and over it again!</textarea>" \
+ "<input name='other_name[secret]' value='0' type='hidden' />" \
+ "<input name='other_name[secret]' checked='checked' value='1' type='checkbox' />" \
"<input name='commit' value='Create post' data-disable-with='Create post' type='submit' />"
end
@@ -672,9 +672,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/", "create-post", method: "delete") do
- "<input name='post[title]' type='text' value='Hello World' />" +
- "<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[title]' type='text' value='Hello World' />" \
+ "<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' />"
end
@@ -689,9 +689,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/", "create-post", method: "delete") do
- "<input name='post[title]' type='text' value='Hello World' />" +
- "<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[title]' type='text' value='Hello World' />" \
+ "<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' />"
end
@@ -720,9 +720,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/", "create-post", method: "patch") do
- "<input name='post[title]' type='text' value='Hello World' />" +
- "<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[title]' type='text' value='Hello World' />" \
+ "<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' />"
end
@@ -761,9 +761,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/", "create-post") do
- "<input name='post[title]' type='text' value='Hello World' />" +
- "<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[title]' type='text' value='Hello World' />" \
+ "<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' />"
end
@@ -779,10 +779,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<label for='post_123_title'>Title</label>" +
- "<input name='post[123][title]' type='text' value='Hello World' />" +
- "<textarea name='post[123][body]'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[123][secret]' type='hidden' value='0' />" +
+ "<label for='post_123_title'>Title</label>" \
+ "<input name='post[123][title]' type='text' value='Hello World' />" \
+ "<textarea name='post[123][body]'>\nBack to the hill and over it again!</textarea>" \
+ "<input name='post[123][secret]' type='hidden' value='0' />" \
"<input name='post[123][secret]' checked='checked' type='checkbox' value='1' />"
end
@@ -797,9 +797,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[][title]' type='text' value='Hello World' />" +
- "<textarea name='post[][body]'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[][secret]' type='hidden' value='0' />" +
+ "<input name='post[][title]' type='text' value='Hello World' />" \
+ "<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' />"
end
@@ -814,8 +814,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<div class='field_with_errors'><label for='post_author_name' class='label'>Author name</label></div>" +
- "<div class='field_with_errors'><input name='post[author_name]' type='text' value='' /></div>" +
+ "<div class='field_with_errors'><label for='post_author_name' class='label'>Author name</label></div>" \
+ "<div class='field_with_errors'><input name='post[author_name]' type='text' value='' /></div>" \
"<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />"
end
@@ -832,8 +832,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<div class='field_with_errors'><label for='post_author_name' class='label'>Author name</label></div>" +
- "<div class='field_with_errors'><input name='post[author_name]' type='text' value='' /></div>" +
+ "<div class='field_with_errors'><label for='post_author_name' class='label'>Author name</label></div>" \
+ "<div class='field_with_errors'><input name='post[author_name]' type='text' value='' /></div>" \
"<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />"
end
@@ -847,7 +847,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<div class='field_with_errors'><label for='post_author_name' class='label'>Name</label></div>" +
+ "<div class='field_with_errors'><label for='post_author_name' class='label'>Name</label></div>" \
"<div class='field_with_errors'><label for='post_author_name' class='label'>Name</label></div>"
end
@@ -863,9 +863,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", "namespace_edit_post_123", "edit_post", method: "patch") do
- "<input name='post[title]' type='text' value='Hello World' />" +
- "<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[title]' type='text' value='Hello World' />" \
+ "<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' />"
end
@@ -1009,7 +1009,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[123][title]' type='text' value='Hello World' />" +
+ "<input name='post[123][title]' type='text' value='Hello World' />" \
"<input name='post[123][comment][][name]' type='text' value='new comment' />"
end
@@ -1025,7 +1025,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[1][title]' type='text' value='Hello World' />" +
+ "<input name='post[1][title]' type='text' value='Hello World' />" \
"<input name='post[1][comment][1][name]' type='text' value='new comment' />"
end
@@ -1135,7 +1135,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" value="Hello World" />' +
+ '<input name="post[title]" type="text" value="Hello World" />' \
'<input name="post[author_attributes][name]" type="text" value="new author" />'
end
@@ -1162,8 +1162,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" value="Hello World" />' +
- '<input name="post[author_attributes][name]" type="text" value="author #321" />' +
+ '<input name="post[title]" type="text" value="Hello World" />' \
+ '<input name="post[author_attributes][name]" type="text" value="author #321" />' \
'<input name="post[author_attributes][id]" type="hidden" value="321" />'
end
@@ -1181,8 +1181,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" value="Hello World" />' +
- '<input name="post[author_attributes][name]" type="text" value="author #321" />' +
+ '<input name="post[title]" type="text" value="Hello World" />' \
+ '<input name="post[author_attributes][name]" type="text" value="author #321" />' \
'<input name="post[author_attributes][id]" type="hidden" value="321" />'
end
@@ -1200,7 +1200,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" value="Hello World" />' +
+ '<input name="post[title]" type="text" value="Hello World" />' \
'<input name="post[author_attributes][name]" type="text" value="author #321" />'
end
@@ -1218,7 +1218,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" value="Hello World" />' +
+ '<input name="post[title]" type="text" value="Hello World" />' \
'<input name="post[author_attributes][name]" type="text" value="author #321" />'
end
@@ -1236,8 +1236,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" value="Hello World" />' +
- '<input name="post[author_attributes][name]" type="text" value="author #321" />' +
+ '<input name="post[title]" type="text" value="Hello World" />' \
+ '<input name="post[author_attributes][name]" type="text" value="author #321" />' \
'<input name="post[author_attributes][id]" type="hidden" value="321" />'
end
@@ -1256,8 +1256,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" value="Hello World" />' +
- '<input name="post[author_attributes][id]" type="hidden" value="321" />' +
+ '<input name="post[title]" type="text" value="Hello World" />' \
+ '<input name="post[author_attributes][id]" type="hidden" value="321" />' \
'<input name="post[author_attributes][name]" type="text" value="author #321" />'
end
@@ -1277,10 +1277,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" value="Hello World" />' +
- '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
- '<input name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
- '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" />' +
+ '<input name="post[title]" type="text" value="Hello World" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' \
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="1" />' \
+ '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" />' \
'<input name="post[comments_attributes][1][id]" type="hidden" value="2" />'
end
@@ -1304,10 +1304,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" value="Hello World" />' +
- '<input name="post[author_attributes][name]" type="text" value="author #321" />' +
- '<input name="post[author_attributes][id]" type="hidden" value="321" />' +
- '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
+ '<input name="post[title]" type="text" value="Hello World" />' \
+ '<input name="post[author_attributes][name]" type="text" value="author #321" />' \
+ '<input name="post[author_attributes][id]" type="hidden" value="321" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' \
'<input name="post[comments_attributes][1][name]" type="text" value="comment #2" />'
end
@@ -1331,9 +1331,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" value="Hello World" />' +
- '<input name="post[author_attributes][name]" type="text" value="author #321" />' +
- '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
+ '<input name="post[title]" type="text" value="Hello World" />' \
+ '<input name="post[author_attributes][name]" type="text" value="author #321" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' \
'<input name="post[comments_attributes][1][name]" type="text" value="comment #2" />'
end
@@ -1357,10 +1357,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" value="Hello World" />' +
- '<input name="post[author_attributes][name]" type="text" value="author #321" />' +
- '<input name="post[author_attributes][id]" type="hidden" value="321" />' +
- '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
+ '<input name="post[title]" type="text" value="Hello World" />' \
+ '<input name="post[author_attributes][name]" type="text" value="author #321" />' \
+ '<input name="post[author_attributes][id]" type="hidden" value="321" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' \
'<input name="post[comments_attributes][1][name]" type="text" value="comment #2" />'
end
@@ -1380,10 +1380,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" value="Hello World" />' +
- '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
- '<input name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
- '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" />' +
+ '<input name="post[title]" type="text" value="Hello World" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' \
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="1" />' \
+ '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" />' \
'<input name="post[comments_attributes][1][id]" type="hidden" value="2" />'
end
@@ -1404,10 +1404,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" value="Hello World" />' +
- '<input name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
- '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
- '<input name="post[comments_attributes][1][id]" type="hidden" value="2" />' +
+ '<input name="post[title]" type="text" value="Hello World" />' \
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="1" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' \
+ '<input name="post[comments_attributes][1][id]" type="hidden" value="2" />' \
'<input name="post[comments_attributes][1][name]" type="text" value="comment #2" />'
end
@@ -1427,8 +1427,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" value="Hello World" />' +
- '<input name="post[comments_attributes][0][name]" type="text" value="new comment" />' +
+ '<input name="post[title]" type="text" value="Hello World" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="new comment" />' \
'<input name="post[comments_attributes][1][name]" type="text" value="new comment" />'
end
@@ -1448,9 +1448,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" value="Hello World" />' +
- '<input name="post[comments_attributes][0][name]" type="text" value="comment #321" />' +
- '<input name="post[comments_attributes][0][id]" type="hidden" value="321" />' +
+ '<input name="post[title]" type="text" value="Hello World" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #321" />' \
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="321" />' \
'<input name="post[comments_attributes][1][name]" type="text" value="new comment" />'
end
@@ -1483,10 +1483,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" value="Hello World" />' +
- '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
- '<input name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
- '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" />' +
+ '<input name="post[title]" type="text" value="Hello World" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' \
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="1" />' \
+ '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" />' \
'<input name="post[comments_attributes][1][id]" type="hidden" value="2" />'
end
@@ -1504,10 +1504,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" value="Hello World" />' +
- '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
- '<input name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
- '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" />' +
+ '<input name="post[title]" type="text" value="Hello World" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' \
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="1" />' \
+ '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" />' \
'<input name="post[comments_attributes][1][id]" type="hidden" value="2" />'
end
@@ -1539,10 +1539,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" value="Hello World" />' +
- '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
- '<input name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
- '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" />' +
+ '<input name="post[title]" type="text" value="Hello World" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' \
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="1" />' \
+ '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" />' \
'<input name="post[comments_attributes][1][id]" type="hidden" value="2" />'
end
@@ -1562,9 +1562,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" value="Hello World" />' +
- '<input name="post[comments_attributes][0][name]" type="text" value="comment #321" />' +
- '<input name="post[comments_attributes][0][id]" type="hidden" value="321" />' +
+ '<input name="post[title]" type="text" value="Hello World" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #321" />' \
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="321" />' \
'<input name="post[comments_attributes][1][name]" type="text" value="new comment" />'
end
@@ -1582,7 +1582,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' +
+ '<input name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' \
'<input name="post[comments_attributes][abc][id]" type="hidden" value="321" />'
end
@@ -1599,7 +1599,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' +
+ '<input name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' \
'<input name="post[comments_attributes][abc][id]" type="hidden" value="321" />'
end
@@ -1622,7 +1622,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' +
+ '<input name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' \
'<input name="post[comments_attributes][abc][id]" type="hidden" value="321" />'
end
@@ -1708,17 +1708,17 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[comments_attributes][0][name]" type="text" value="comment #321" />' +
- '<input name="post[comments_attributes][0][relevances_attributes][0][value]" type="text" value="commentrelevance #314" />' +
- '<input name="post[comments_attributes][0][relevances_attributes][0][id]" type="hidden" value="314" />' +
- '<input name="post[comments_attributes][0][id]" type="hidden" value="321" />' +
- '<input name="post[tags_attributes][0][value]" type="text" value="tag #123" />' +
- '<input name="post[tags_attributes][0][relevances_attributes][0][value]" type="text" value="tagrelevance #3141" />' +
- '<input name="post[tags_attributes][0][relevances_attributes][0][id]" type="hidden" value="3141" />' +
- '<input name="post[tags_attributes][0][id]" type="hidden" value="123" />' +
- '<input name="post[tags_attributes][1][value]" type="text" value="tag #456" />' +
- '<input name="post[tags_attributes][1][relevances_attributes][0][value]" type="text" value="tagrelevance #31415" />' +
- '<input name="post[tags_attributes][1][relevances_attributes][0][id]" type="hidden" value="31415" />' +
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #321" />' \
+ '<input name="post[comments_attributes][0][relevances_attributes][0][value]" type="text" value="commentrelevance #314" />' \
+ '<input name="post[comments_attributes][0][relevances_attributes][0][id]" type="hidden" value="314" />' \
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="321" />' \
+ '<input name="post[tags_attributes][0][value]" type="text" value="tag #123" />' \
+ '<input name="post[tags_attributes][0][relevances_attributes][0][value]" type="text" value="tagrelevance #3141" />' \
+ '<input name="post[tags_attributes][0][relevances_attributes][0][id]" type="hidden" value="3141" />' \
+ '<input name="post[tags_attributes][0][id]" type="hidden" value="123" />' \
+ '<input name="post[tags_attributes][1][value]" type="text" value="tag #456" />' \
+ '<input name="post[tags_attributes][1][relevances_attributes][0][value]" type="text" value="tagrelevance #31415" />' \
+ '<input name="post[tags_attributes][1][relevances_attributes][0][id]" type="hidden" value="31415" />' \
'<input name="post[tags_attributes][1][id]" type="hidden" value="456" />'
end
@@ -1749,9 +1749,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected =
- "<input name='post[title]' type='text' value='Hello World' />" +
- "<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[title]' type='text' value='Hello World' />" \
+ "<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' />"
assert_dom_equal expected, output_buffer
@@ -1765,9 +1765,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected =
- "<input name='post[123][title]' type='text' value='Hello World' />" +
- "<textarea name='post[123][body]'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[123][secret]' type='hidden' value='0' />" +
+ "<input name='post[123][title]' type='text' value='Hello World' />" \
+ "<textarea name='post[123][body]'>\nBack to the hill and over it again!</textarea>" \
+ "<input name='post[123][secret]' type='hidden' value='0' />" \
"<input name='post[123][secret]' checked='checked' type='checkbox' value='1' />"
assert_dom_equal expected, output_buffer
@@ -1781,9 +1781,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected =
- "<input name='post[][title]' type='text' value='Hello World' />" +
- "<textarea name='post[][body]'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[][secret]' type='hidden' value='0' />" +
+ "<input name='post[][title]' type='text' value='Hello World' />" \
+ "<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' />"
assert_dom_equal expected, output_buffer
@@ -1797,9 +1797,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected =
- "<input name='post[abc][title]' type='text' value='Hello World' />" +
- "<textarea name='post[abc][body]'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[abc][secret]' type='hidden' value='0' />" +
+ "<input name='post[abc][title]' type='text' value='Hello World' />" \
+ "<textarea name='post[abc][body]'>\nBack to the hill and over it again!</textarea>" \
+ "<input name='post[abc][secret]' type='hidden' value='0' />" \
"<input name='post[abc][secret]' checked='checked' type='checkbox' value='1' />"
assert_dom_equal expected, output_buffer
@@ -1813,9 +1813,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected =
- "<input name='post[title]' type='text' value='Hello World' />" +
- "<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[title]' type='text' value='Hello World' />" \
+ "<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' />"
assert_dom_equal expected, output_buffer
@@ -1829,9 +1829,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected =
- "<input name='post[title]' type='text' value='Hello World' />" +
- "<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[title]' type='text' value='Hello World' />" \
+ "<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' />"
assert_dom_equal expected, output_buffer
@@ -1843,7 +1843,7 @@ class FormWithActsLikeFormForTest < FormWithTest
concat f.text_field(:title)
end
- assert_dom_equal "<label for=\"author_post_title\">Title</label>" +
+ assert_dom_equal "<label for=\"author_post_title\">Title</label>" \
"<input name='author[post][title]' type='text' value='Hello World' />",
output_buffer
end
@@ -1854,7 +1854,7 @@ class FormWithActsLikeFormForTest < FormWithTest
concat f.text_field(:title)
end
- assert_dom_equal "<label for=\"author_post_1_title\">Title</label>" +
+ assert_dom_equal "<label for=\"author_post_1_title\">Title</label>" \
"<input name='author[post][1][title]' type='text' value='Hello World' />",
output_buffer
end
@@ -1874,9 +1874,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", "create-post", method: "patch") do
- "<input name='post[title]' type='text' value='Hello World' />" +
- "<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" +
- "<input name='parent_post[secret]' type='hidden' value='0' />" +
+ "<input name='post[title]' type='text' value='Hello World' />" \
+ "<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" \
+ "<input name='parent_post[secret]' type='hidden' value='0' />" \
"<input name='parent_post[secret]' checked='checked' type='checkbox' value='1' />"
end
@@ -1894,8 +1894,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", "create-post", method: "patch") do
- "<input name='post[title]' type='text' value='Hello World' />" +
- "<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" +
+ "<input name='post[title]' type='text' value='Hello World' />" \
+ "<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" \
"<input name='post[comment][name]' type='text' value='new comment' />"
end
@@ -1934,8 +1934,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<label for='title'>Title:</label> <input name='post[title]' type='text' value='Hello World' /><br/>" +
- "<label for='body'>Body:</label> <textarea name='post[body]'>\nBack to the hill and over it again!</textarea><br/>" +
+ "<label for='title'>Title:</label> <input name='post[title]' type='text' value='Hello World' /><br/>" \
+ "<label for='body'>Body:</label> <textarea name='post[body]'>\nBack to the hill and over it again!</textarea><br/>" \
"<label for='secret'>Secret:</label> <input name='post[secret]' type='hidden' value='0' /><input name='post[secret]' checked='checked' type='checkbox' value='1' /><br/>"
end
@@ -1953,8 +1953,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<label for='title'>Title:</label> <input name='post[title]' type='text' value='Hello World' /><br/>" +
- "<label for='body'>Body:</label> <textarea name='post[body]'>\nBack to the hill and over it again!</textarea><br/>" +
+ "<label for='title'>Title:</label> <input name='post[title]' type='text' value='Hello World' /><br/>" \
+ "<label for='body'>Body:</label> <textarea name='post[body]'>\nBack to the hill and over it again!</textarea><br/>" \
"<label for='secret'>Secret:</label> <input name='post[secret]' type='hidden' value='0' /><input name='post[secret]' checked='checked' type='checkbox' value='1' /><br/>"
end
@@ -2012,8 +2012,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected =
- "<label for='title'>Title:</label> <input name='post[title]' type='text' value='Hello World' /><br/>" +
- "<label for='body'>Body:</label> <textarea name='post[body]'>\nBack to the hill and over it again!</textarea><br/>" +
+ "<label for='title'>Title:</label> <input name='post[title]' type='text' value='Hello World' /><br/>" \
+ "<label for='body'>Body:</label> <textarea name='post[body]'>\nBack to the hill and over it again!</textarea><br/>" \
"<label for='secret'>Secret:</label> <input name='post[secret]' type='hidden' value='0' /><input name='post[secret]' checked='checked' type='checkbox' value='1' /><br/>"
assert_dom_equal expected, output_buffer
diff --git a/actionview/test/template/form_helper_test.rb b/actionview/test/template/form_helper_test.rb
index 2bc0434771..83231d5277 100644
--- a/actionview/test/template/form_helper_test.rb
+++ b/actionview/test/template/form_helper_test.rb
@@ -1515,13 +1515,13 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "create-post", "edit_post", method: "patch") do
- "<label for='post_title'>The Title</label>" +
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='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' id='post_secret' value='1' />" +
- "<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />" +
- "<button name='button' type='submit'>Create post</button>" +
+ "<label for='post_title'>The Title</label>" \
+ "<input name='post[title]' type='text' id='post_title' value='Hello World' />" \
+ "<textarea name='post[body]' id='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' id='post_secret' value='1' />" \
+ "<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>"
end
@@ -1536,10 +1536,10 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts", "new_post", "new_post") do
- "<input type='hidden' name='post[active]' value='' />" +
- "<input id='post_active_true' name='post[active]' type='radio' value='true' />" +
- "<label for='post_active_true'>true</label>" +
- "<input checked='checked' id='post_active_false' name='post[active]' type='radio' value='false' />" +
+ "<input type='hidden' name='post[active]' value='' />" \
+ "<input id='post_active_true' name='post[active]' type='radio' value='true' />" \
+ "<label for='post_active_true'>true</label>" \
+ "<input checked='checked' id='post_active_false' name='post[active]' type='radio' value='false' />" \
"<label for='post_active_false'>false</label>"
end
@@ -1558,12 +1558,12 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts", "new_post", "new_post") do
- "<input type='hidden' name='post[active]' value='' />" +
- "<label for='post_active_true'>" +
- "<input id='post_active_true' name='post[active]' type='radio' value='true' />" +
- "true</label>" +
- "<label for='post_active_false'>" +
- "<input checked='checked' id='post_active_false' name='post[active]' type='radio' value='false' />" +
+ "<input type='hidden' name='post[active]' value='' />" \
+ "<label for='post_active_true'>" \
+ "<input id='post_active_true' name='post[active]' type='radio' value='true' />" \
+ "true</label>" \
+ "<label for='post_active_false'>" \
+ "<input checked='checked' id='post_active_false' name='post[active]' type='radio' value='false' />" \
"false</label>"
end
@@ -1584,13 +1584,13 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts", "new_post_1", "new_post") do
- "<input type='hidden' name='post[active]' value='' />" +
- "<label for='post_active_true'>" +
- "<input id='post_active_true' name='post[active]' type='radio' value='true' />" +
- "true</label>" +
- "<label for='post_active_false'>" +
- "<input checked='checked' id='post_active_false' name='post[active]' type='radio' value='false' />" +
- "false</label>" +
+ "<input type='hidden' name='post[active]' value='' />" \
+ "<label for='post_active_true'>" \
+ "<input id='post_active_true' name='post[active]' type='radio' value='true' />" \
+ "true</label>" \
+ "<label for='post_active_false'>" \
+ "<input checked='checked' id='post_active_false' name='post[active]' type='radio' value='false' />" \
+ "false</label>" \
"<input id='post_id' name='post[id]' type='hidden' value='1' />"
end
@@ -1606,10 +1606,10 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts", "foo_new_post", "new_post") do
- "<input type='hidden' name='post[active]' value='' />" +
- "<input id='foo_post_active_true' name='post[active]' type='radio' value='true' />" +
- "<label for='foo_post_active_true'>true</label>" +
- "<input checked='checked' id='foo_post_active_false' name='post[active]' type='radio' value='false' />" +
+ "<input type='hidden' name='post[active]' value='' />" \
+ "<input id='foo_post_active_true' name='post[active]' type='radio' value='true' />" \
+ "<label for='foo_post_active_true'>true</label>" \
+ "<input checked='checked' id='foo_post_active_false' name='post[active]' type='radio' value='false' />" \
"<label for='foo_post_active_false'>false</label>"
end
@@ -1625,10 +1625,10 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts", "new_post", "new_post") do
- "<input type='hidden' name='post[1][active]' value='' />" +
- "<input id='post_1_active_true' name='post[1][active]' type='radio' value='true' />" +
- "<label for='post_1_active_true'>true</label>" +
- "<input checked='checked' id='post_1_active_false' name='post[1][active]' type='radio' value='false' />" +
+ "<input type='hidden' name='post[1][active]' value='' />" \
+ "<input id='post_1_active_true' name='post[1][active]' type='radio' value='true' />" \
+ "<label for='post_1_active_true'>true</label>" \
+ "<input checked='checked' id='post_1_active_false' name='post[1][active]' type='radio' value='false' />" \
"<label for='post_1_active_false'>false</label>"
end
@@ -1644,12 +1644,12 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts", "new_post", "new_post") do
- "<input name='post[tag_ids][]' type='hidden' value='' />" +
- "<input checked='checked' id='post_tag_ids_1' name='post[tag_ids][]' type='checkbox' value='1' />" +
- "<label for='post_tag_ids_1'>Tag 1</label>" +
- "<input id='post_tag_ids_2' name='post[tag_ids][]' type='checkbox' value='2' />" +
- "<label for='post_tag_ids_2'>Tag 2</label>" +
- "<input checked='checked' id='post_tag_ids_3' name='post[tag_ids][]' type='checkbox' value='3' />" +
+ "<input name='post[tag_ids][]' type='hidden' value='' />" \
+ "<input checked='checked' id='post_tag_ids_1' name='post[tag_ids][]' type='checkbox' value='1' />" \
+ "<label for='post_tag_ids_1'>Tag 1</label>" \
+ "<input id='post_tag_ids_2' name='post[tag_ids][]' type='checkbox' value='2' />" \
+ "<label for='post_tag_ids_2'>Tag 2</label>" \
+ "<input checked='checked' id='post_tag_ids_3' name='post[tag_ids][]' type='checkbox' value='3' />" \
"<label for='post_tag_ids_3'>Tag 3</label>"
end
@@ -1668,15 +1668,15 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts", "new_post", "new_post") do
- "<input name='post[tag_ids][]' type='hidden' value='' />" +
- "<label for='post_tag_ids_1'>" +
- "<input checked='checked' id='post_tag_ids_1' name='post[tag_ids][]' type='checkbox' value='1' />" +
- "Tag 1</label>" +
- "<label for='post_tag_ids_2'>" +
- "<input id='post_tag_ids_2' name='post[tag_ids][]' type='checkbox' value='2' />" +
- "Tag 2</label>" +
- "<label for='post_tag_ids_3'>" +
- "<input checked='checked' id='post_tag_ids_3' name='post[tag_ids][]' type='checkbox' value='3' />" +
+ "<input name='post[tag_ids][]' type='hidden' value='' />" \
+ "<label for='post_tag_ids_1'>" \
+ "<input checked='checked' id='post_tag_ids_1' name='post[tag_ids][]' type='checkbox' value='1' />" \
+ "Tag 1</label>" \
+ "<label for='post_tag_ids_2'>" \
+ "<input id='post_tag_ids_2' name='post[tag_ids][]' type='checkbox' value='2' />" \
+ "Tag 2</label>" \
+ "<label for='post_tag_ids_3'>" \
+ "<input checked='checked' id='post_tag_ids_3' name='post[tag_ids][]' type='checkbox' value='3' />" \
"Tag 3</label>"
end
@@ -1698,16 +1698,16 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts", "new_post_1", "new_post") do
- "<input name='post[tag_ids][]' type='hidden' value='' />" +
- "<label for='post_tag_ids_1'>" +
- "<input checked='checked' id='post_tag_ids_1' name='post[tag_ids][]' type='checkbox' value='1' />" +
- "Tag 1</label>" +
- "<label for='post_tag_ids_2'>" +
- "<input id='post_tag_ids_2' name='post[tag_ids][]' type='checkbox' value='2' />" +
- "Tag 2</label>" +
- "<label for='post_tag_ids_3'>" +
- "<input checked='checked' id='post_tag_ids_3' name='post[tag_ids][]' type='checkbox' value='3' />" +
- "Tag 3</label>" +
+ "<input name='post[tag_ids][]' type='hidden' value='' />" \
+ "<label for='post_tag_ids_1'>" \
+ "<input checked='checked' id='post_tag_ids_1' name='post[tag_ids][]' type='checkbox' value='1' />" \
+ "Tag 1</label>" \
+ "<label for='post_tag_ids_2'>" \
+ "<input id='post_tag_ids_2' name='post[tag_ids][]' type='checkbox' value='2' />" \
+ "Tag 2</label>" \
+ "<label for='post_tag_ids_3'>" \
+ "<input checked='checked' id='post_tag_ids_3' name='post[tag_ids][]' type='checkbox' value='3' />" \
+ "Tag 3</label>" \
"<input id='post_id' name='post[id]' type='hidden' value='1' />"
end
@@ -1724,8 +1724,8 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts", "foo_new_post", "new_post") do
- "<input name='post[tag_ids][]' type='hidden' value='' />" +
- "<input checked='checked' id='foo_post_tag_ids_1' name='post[tag_ids][]' type='checkbox' value='1' />" +
+ "<input name='post[tag_ids][]' type='hidden' value='' />" \
+ "<input checked='checked' id='foo_post_tag_ids_1' name='post[tag_ids][]' type='checkbox' value='1' />" \
"<label for='foo_post_tag_ids_1'>Tag 1</label>"
end
@@ -1742,8 +1742,8 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts", "new_post", "new_post") do
- "<input name='post[1][tag_ids][]' type='hidden' value='' />" +
- "<input checked='checked' id='post_1_tag_ids_1' name='post[1][tag_ids][]' type='checkbox' value='1' />" +
+ "<input name='post[1][tag_ids][]' type='hidden' value='' />" \
+ "<input checked='checked' id='post_1_tag_ids_1' name='post[1][tag_ids][]' type='checkbox' value='1' />" \
"<label for='post_1_tag_ids_1'>Tag 1</label>"
end
@@ -1797,7 +1797,7 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/44", "edit_post_44", "edit_post", method: "patch") do
- "<input name='post[title]' type='text' id='post_title' value='And his name will be forty and four.' />" +
+ "<input name='post[title]' type='text' id='post_title' value='And his name will be forty and four.' />" \
"<input name='commit' data-disable-with='Edit post' type='submit' value='Edit post' />"
end
@@ -1814,11 +1814,11 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "create-post", "edit_other_name", method: "patch") do
- "<label for='other_name_title' class='post_title'>Title</label>" +
- "<input name='other_name[title]' id='other_name_title' value='Hello World' type='text' />" +
- "<textarea name='other_name[body]' id='other_name_body'>\nBack to the hill and over it again!</textarea>" +
- "<input name='other_name[secret]' value='0' type='hidden' />" +
- "<input name='other_name[secret]' checked='checked' id='other_name_secret' value='1' type='checkbox' />" +
+ "<label for='other_name_title' class='post_title'>Title</label>" \
+ "<input name='other_name[title]' id='other_name_title' value='Hello World' type='text' />" \
+ "<textarea name='other_name[body]' id='other_name_body'>\nBack to the hill and over it again!</textarea>" \
+ "<input name='other_name[secret]' value='0' type='hidden' />" \
+ "<input name='other_name[secret]' checked='checked' id='other_name_secret' value='1' type='checkbox' />" \
"<input name='commit' value='Create post' data-disable-with='Create post' type='submit' />"
end
@@ -1847,9 +1847,9 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/", "create-post", "edit_post", method: "delete") do
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[title]' type='text' id='post_title' value='Hello World' />" \
+ "<textarea name='post[body]' id='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' id='post_secret' value='1' />"
end
@@ -1864,9 +1864,9 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/", "create-post", "edit_post", method: "delete") do
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[title]' type='text' id='post_title' value='Hello World' />" \
+ "<textarea name='post[body]' id='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' id='post_secret' value='1' />"
end
@@ -1895,9 +1895,9 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/", "create-post", "edit_post", method: "patch", remote: true) do
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[title]' type='text' id='post_title' value='Hello World' />" \
+ "<textarea name='post[body]' id='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' id='post_secret' value='1' />"
end
@@ -1936,9 +1936,9 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/", "create-post", "edit_post", method: "patch", remote: true) do
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[title]' type='text' id='post_title' value='Hello World' />" \
+ "<textarea name='post[body]' id='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' id='post_secret' value='1' />"
end
@@ -1955,9 +1955,9 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts", "new_post", "new_post", remote: true) do
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[title]' type='text' id='post_title' value='Hello World' />" \
+ "<textarea name='post[body]' id='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' id='post_secret' value='1' />"
end
@@ -1973,9 +1973,9 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/", "create-post") do
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[title]' type='text' id='post_title' value='Hello World' />" \
+ "<textarea name='post[body]' id='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' id='post_secret' value='1' />"
end
@@ -1991,10 +1991,10 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post[]", "edit_post[]", method: "patch") do
- "<label for='post_123_title'>Title</label>" +
- "<input name='post[123][title]' type='text' id='post_123_title' value='Hello World' />" +
- "<textarea name='post[123][body]' id='post_123_body'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[123][secret]' type='hidden' value='0' />" +
+ "<label for='post_123_title'>Title</label>" \
+ "<input name='post[123][title]' type='text' id='post_123_title' value='Hello World' />" \
+ "<textarea name='post[123][body]' id='post_123_body'>\nBack to the hill and over it again!</textarea>" \
+ "<input name='post[123][secret]' type='hidden' value='0' />" \
"<input name='post[123][secret]' checked='checked' type='checkbox' id='post_123_secret' value='1' />"
end
@@ -2009,9 +2009,9 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post[]", "edit_post[]", method: "patch") do
- "<input name='post[][title]' type='text' id='post__title' value='Hello World' />" +
- "<textarea name='post[][body]' id='post__body'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[][secret]' type='hidden' value='0' />" +
+ "<input name='post[][title]' type='text' id='post__title' value='Hello World' />" \
+ "<textarea name='post[][body]' id='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' id='post__secret' value='1' />"
end
@@ -2026,8 +2026,8 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- "<div class='field_with_errors'><label for='post_author_name' class='label'>Author name</label></div>" +
- "<div class='field_with_errors'><input name='post[author_name]' type='text' id='post_author_name' value='' /></div>" +
+ "<div class='field_with_errors'><label for='post_author_name' class='label'>Author name</label></div>" \
+ "<div class='field_with_errors'><input name='post[author_name]' type='text' id='post_author_name' value='' /></div>" \
"<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />"
end
@@ -2044,8 +2044,8 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- "<div class='field_with_errors'><label for='post_author_name' class='label'>Author name</label></div>" +
- "<div class='field_with_errors'><input name='post[author_name]' type='text' id='post_author_name' value='' /></div>" +
+ "<div class='field_with_errors'><label for='post_author_name' class='label'>Author name</label></div>" \
+ "<div class='field_with_errors'><input name='post[author_name]' type='text' id='post_author_name' value='' /></div>" \
"<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />"
end
@@ -2059,7 +2059,7 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- "<div class='field_with_errors'><label for='post_author_name' class='label'>Name</label></div>" +
+ "<div class='field_with_errors'><label for='post_author_name' class='label'>Name</label></div>" \
"<div class='field_with_errors'><label for='post_author_name' class='label'>Name</label></div>"
end
@@ -2074,9 +2074,9 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "namespace_edit_post_123", "edit_post", method: "patch") do
- "<input name='post[title]' type='text' id='namespace_post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='namespace_post_body'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[title]' type='text' id='namespace_post_title' value='Hello World' />" \
+ "<textarea name='post[body]' id='namespace_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' id='namespace_post_secret' value='1' />"
end
@@ -2098,7 +2098,7 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "namespace_edit_post_123", "edit_post", method: "patch") do
- "<label for='namespace_post_title'>Title</label>" +
+ "<label for='namespace_post_title'>Title</label>" \
"<input name='post[title]' type='text' id='namespace_post_title' value='Hello World' />"
end
@@ -2124,7 +2124,7 @@ class FormHelperTest < ActionView::TestCase
end
expected_1 = whole_form("/posts/123", "namespace_1_edit_post_123", "edit_post", method: "patch") do
- "<label for='namespace_1_post_title'>Title</label>" +
+ "<label for='namespace_1_post_title'>Title</label>" \
"<input name='post[title]' type='text' id='namespace_1_post_title' value='Hello World' />"
end
@@ -2136,7 +2136,7 @@ class FormHelperTest < ActionView::TestCase
end
expected_2 = whole_form("/posts/123", "namespace_2_edit_post_123", "edit_post", method: "patch") do
- "<label for='namespace_2_post_title'>Title</label>" +
+ "<label for='namespace_2_post_title'>Title</label>" \
"<input name='post[title]' type='text' id='namespace_2_post_title' value='Hello World' />"
end
@@ -2154,8 +2154,8 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "namespace_edit_post_123", "edit_post", method: "patch") do
- "<input name='post[title]' type='text' id='namespace_post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='namespace_post_body'>\nBack to the hill and over it again!</textarea>" +
+ "<input name='post[title]' type='text' id='namespace_post_title' value='Hello World' />" \
+ "<textarea name='post[body]' id='namespace_post_body'>\nBack to the hill and over it again!</textarea>" \
"<input name='post[comment][body]' type='text' id='namespace_post_comment_body' value='Hello World' />"
end
@@ -2266,8 +2266,8 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post[]", "edit_post[]", method: "patch") do
- "<input name='post[123][title]' type='text' id='post_123_title' value='Hello World' />" +
- "<input name='post[123][comment][][name]' type='text' id='post_123_comment__name' value='new comment' />" +
+ "<input name='post[123][title]' type='text' id='post_123_title' value='Hello World' />" \
+ "<input name='post[123][comment][][name]' type='text' id='post_123_comment__name' value='new comment' />" \
"<input name='post[123][body]' type='text' id='post_123_body' value='Back to the hill and over it again!' />"
end
@@ -2283,7 +2283,7 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- "<input name='post[1][title]' type='text' id='post_1_title' value='Hello World' />" +
+ "<input name='post[1][title]' type='text' id='post_1_title' value='Hello World' />" \
"<input name='post[1][comment][1][name]' type='text' id='post_1_comment_1_name' value='new comment' />"
end
@@ -2393,7 +2393,7 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
+ '<input name="post[title]" type="text" id="post_title" value="Hello World" />' \
'<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="new author" />'
end
@@ -2420,8 +2420,8 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' +
+ '<input name="post[title]" type="text" id="post_title" value="Hello World" />' \
+ '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' \
'<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />'
end
@@ -2439,8 +2439,8 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' +
+ '<input name="post[title]" type="text" id="post_title" value="Hello World" />' \
+ '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' \
'<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />'
end
@@ -2458,7 +2458,7 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
+ '<input name="post[title]" type="text" id="post_title" value="Hello World" />' \
'<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />'
end
@@ -2476,7 +2476,7 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
+ '<input name="post[title]" type="text" id="post_title" value="Hello World" />' \
'<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />'
end
@@ -2494,8 +2494,8 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' +
+ '<input name="post[title]" type="text" id="post_title" value="Hello World" />' \
+ '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' \
'<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />'
end
@@ -2514,8 +2514,8 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />' +
+ '<input name="post[title]" type="text" id="post_title" value="Hello World" />' \
+ '<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />' \
'<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />'
end
@@ -2535,10 +2535,10 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
- '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
- '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="comment #2" />' +
+ '<input name="post[title]" type="text" id="post_title" value="Hello World" />' \
+ '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' \
+ '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' \
+ '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="comment #2" />' \
'<input id="post_comments_attributes_1_id" name="post[comments_attributes][1][id]" type="hidden" value="2" />'
end
@@ -2562,10 +2562,10 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' +
- '<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
+ '<input name="post[title]" type="text" id="post_title" value="Hello World" />' \
+ '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' \
+ '<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />' \
+ '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' \
'<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="comment #2" />'
end
@@ -2589,9 +2589,9 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
+ '<input name="post[title]" type="text" id="post_title" value="Hello World" />' \
+ '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' \
+ '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' \
'<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="comment #2" />'
end
@@ -2615,10 +2615,10 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' +
- '<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
+ '<input name="post[title]" type="text" id="post_title" value="Hello World" />' \
+ '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' \
+ '<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />' \
+ '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' \
'<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="comment #2" />'
end
@@ -2638,10 +2638,10 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
- '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
- '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="comment #2" />' +
+ '<input name="post[title]" type="text" id="post_title" value="Hello World" />' \
+ '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' \
+ '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' \
+ '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="comment #2" />' \
'<input id="post_comments_attributes_1_id" name="post[comments_attributes][1][id]" type="hidden" value="2" />'
end
@@ -2662,10 +2662,10 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
- '<input id="post_comments_attributes_1_id" name="post[comments_attributes][1][id]" type="hidden" value="2" />' +
+ '<input name="post[title]" type="text" id="post_title" value="Hello World" />' \
+ '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' \
+ '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' \
+ '<input id="post_comments_attributes_1_id" name="post[comments_attributes][1][id]" type="hidden" value="2" />' \
'<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="comment #2" />'
end
@@ -2685,8 +2685,8 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="new comment" />' +
+ '<input name="post[title]" type="text" id="post_title" value="Hello World" />' \
+ '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="new comment" />' \
'<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="new comment" />'
end
@@ -2706,9 +2706,9 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #321" />' +
- '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="321" />' +
+ '<input name="post[title]" type="text" id="post_title" value="Hello World" />' \
+ '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #321" />' \
+ '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="321" />' \
'<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="new comment" />'
end
@@ -2741,10 +2741,10 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
- '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
- '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="comment #2" />' +
+ '<input name="post[title]" type="text" id="post_title" value="Hello World" />' \
+ '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' \
+ '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' \
+ '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="comment #2" />' \
'<input id="post_comments_attributes_1_id" name="post[comments_attributes][1][id]" type="hidden" value="2" />'
end
@@ -2762,10 +2762,10 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
- '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
- '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="comment #2" />' +
+ '<input name="post[title]" type="text" id="post_title" value="Hello World" />' \
+ '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' \
+ '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' \
+ '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="comment #2" />' \
'<input id="post_comments_attributes_1_id" name="post[comments_attributes][1][id]" type="hidden" value="2" />'
end
@@ -2797,10 +2797,10 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
- '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
- '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="comment #2" />' +
+ '<input name="post[title]" type="text" id="post_title" value="Hello World" />' \
+ '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' \
+ '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' \
+ '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="comment #2" />' \
'<input id="post_comments_attributes_1_id" name="post[comments_attributes][1][id]" type="hidden" value="2" />'
end
@@ -2820,9 +2820,9 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #321" />' +
- '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="321" />' +
+ '<input name="post[title]" type="text" id="post_title" value="Hello World" />' \
+ '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #321" />' \
+ '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="321" />' \
'<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="new comment" />'
end
@@ -2840,7 +2840,7 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- '<input id="post_comments_attributes_abc_name" name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' +
+ '<input id="post_comments_attributes_abc_name" name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' \
'<input id="post_comments_attributes_abc_id" name="post[comments_attributes][abc][id]" type="hidden" value="321" />'
end
@@ -2857,7 +2857,7 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- '<input id="post_comments_attributes_abc_name" name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' +
+ '<input id="post_comments_attributes_abc_name" name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' \
'<input id="post_comments_attributes_abc_id" name="post[comments_attributes][abc][id]" type="hidden" value="321" />'
end
@@ -2880,7 +2880,7 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- '<input id="post_comments_attributes_abc_name" name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' +
+ '<input id="post_comments_attributes_abc_name" name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' \
'<input id="post_comments_attributes_abc_id" name="post[comments_attributes][abc][id]" type="hidden" value="321" />'
end
@@ -2966,17 +2966,17 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #321" />' +
- '<input id="post_comments_attributes_0_relevances_attributes_0_value" name="post[comments_attributes][0][relevances_attributes][0][value]" type="text" value="commentrelevance #314" />' +
- '<input id="post_comments_attributes_0_relevances_attributes_0_id" name="post[comments_attributes][0][relevances_attributes][0][id]" type="hidden" value="314" />' +
- '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="321" />' +
- '<input id="post_tags_attributes_0_value" name="post[tags_attributes][0][value]" type="text" value="tag #123" />' +
- '<input id="post_tags_attributes_0_relevances_attributes_0_value" name="post[tags_attributes][0][relevances_attributes][0][value]" type="text" value="tagrelevance #3141" />' +
- '<input id="post_tags_attributes_0_relevances_attributes_0_id" name="post[tags_attributes][0][relevances_attributes][0][id]" type="hidden" value="3141" />' +
- '<input id="post_tags_attributes_0_id" name="post[tags_attributes][0][id]" type="hidden" value="123" />' +
- '<input id="post_tags_attributes_1_value" name="post[tags_attributes][1][value]" type="text" value="tag #456" />' +
- '<input id="post_tags_attributes_1_relevances_attributes_0_value" name="post[tags_attributes][1][relevances_attributes][0][value]" type="text" value="tagrelevance #31415" />' +
- '<input id="post_tags_attributes_1_relevances_attributes_0_id" name="post[tags_attributes][1][relevances_attributes][0][id]" type="hidden" value="31415" />' +
+ '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #321" />' \
+ '<input id="post_comments_attributes_0_relevances_attributes_0_value" name="post[comments_attributes][0][relevances_attributes][0][value]" type="text" value="commentrelevance #314" />' \
+ '<input id="post_comments_attributes_0_relevances_attributes_0_id" name="post[comments_attributes][0][relevances_attributes][0][id]" type="hidden" value="314" />' \
+ '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="321" />' \
+ '<input id="post_tags_attributes_0_value" name="post[tags_attributes][0][value]" type="text" value="tag #123" />' \
+ '<input id="post_tags_attributes_0_relevances_attributes_0_value" name="post[tags_attributes][0][relevances_attributes][0][value]" type="text" value="tagrelevance #3141" />' \
+ '<input id="post_tags_attributes_0_relevances_attributes_0_id" name="post[tags_attributes][0][relevances_attributes][0][id]" type="hidden" value="3141" />' \
+ '<input id="post_tags_attributes_0_id" name="post[tags_attributes][0][id]" type="hidden" value="123" />' \
+ '<input id="post_tags_attributes_1_value" name="post[tags_attributes][1][value]" type="text" value="tag #456" />' \
+ '<input id="post_tags_attributes_1_relevances_attributes_0_value" name="post[tags_attributes][1][relevances_attributes][0][value]" type="text" value="tagrelevance #31415" />' \
+ '<input id="post_tags_attributes_1_relevances_attributes_0_id" name="post[tags_attributes][1][relevances_attributes][0][id]" type="hidden" value="31415" />' \
'<input id="post_tags_attributes_1_id" name="post[tags_attributes][1][id]" type="hidden" value="456" />'
end
@@ -3007,9 +3007,9 @@ class FormHelperTest < ActionView::TestCase
end
expected =
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[title]' type='text' id='post_title' value='Hello World' />" \
+ "<textarea name='post[body]' id='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' id='post_secret' value='1' />"
assert_dom_equal expected, output_buffer
@@ -3023,9 +3023,9 @@ class FormHelperTest < ActionView::TestCase
end
expected =
- "<input name='post[123][title]' type='text' id='post_123_title' value='Hello World' />" +
- "<textarea name='post[123][body]' id='post_123_body'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[123][secret]' type='hidden' value='0' />" +
+ "<input name='post[123][title]' type='text' id='post_123_title' value='Hello World' />" \
+ "<textarea name='post[123][body]' id='post_123_body'>\nBack to the hill and over it again!</textarea>" \
+ "<input name='post[123][secret]' type='hidden' value='0' />" \
"<input name='post[123][secret]' checked='checked' type='checkbox' id='post_123_secret' value='1' />"
assert_dom_equal expected, output_buffer
@@ -3039,9 +3039,9 @@ class FormHelperTest < ActionView::TestCase
end
expected =
- "<input name='post[][title]' type='text' id='post__title' value='Hello World' />" +
- "<textarea name='post[][body]' id='post__body'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[][secret]' type='hidden' value='0' />" +
+ "<input name='post[][title]' type='text' id='post__title' value='Hello World' />" \
+ "<textarea name='post[][body]' id='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' id='post__secret' value='1' />"
assert_dom_equal expected, output_buffer
@@ -3055,9 +3055,9 @@ class FormHelperTest < ActionView::TestCase
end
expected =
- "<input name='post[abc][title]' type='text' id='post_abc_title' value='Hello World' />" +
- "<textarea name='post[abc][body]' id='post_abc_body'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[abc][secret]' type='hidden' value='0' />" +
+ "<input name='post[abc][title]' type='text' id='post_abc_title' value='Hello World' />" \
+ "<textarea name='post[abc][body]' id='post_abc_body'>\nBack to the hill and over it again!</textarea>" \
+ "<input name='post[abc][secret]' type='hidden' value='0' />" \
"<input name='post[abc][secret]' checked='checked' type='checkbox' id='post_abc_secret' value='1' />"
assert_dom_equal expected, output_buffer
@@ -3071,9 +3071,9 @@ class FormHelperTest < ActionView::TestCase
end
expected =
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[title]' type='text' id='post_title' value='Hello World' />" \
+ "<textarea name='post[body]' id='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' id='post_secret' value='1' />"
assert_dom_equal expected, output_buffer
@@ -3087,9 +3087,9 @@ class FormHelperTest < ActionView::TestCase
end
expected =
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[title]' type='text' id='post_title' value='Hello World' />" \
+ "<textarea name='post[body]' id='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' id='post_secret' value='1' />"
assert_dom_equal expected, output_buffer
@@ -3101,7 +3101,7 @@ class FormHelperTest < ActionView::TestCase
concat f.text_field(:title)
end
- assert_dom_equal "<label for=\"author_post_title\">Title</label>" +
+ assert_dom_equal "<label for=\"author_post_title\">Title</label>" \
"<input name='author[post][title]' type='text' id='author_post_title' value='Hello World' />",
output_buffer
end
@@ -3112,7 +3112,7 @@ class FormHelperTest < ActionView::TestCase
concat f.text_field(:title)
end
- assert_dom_equal "<label for=\"author_post_1_title\">Title</label>" +
+ assert_dom_equal "<label for=\"author_post_1_title\">Title</label>" \
"<input name='author[post][1][title]' type='text' id='author_post_1_title' value='Hello World' />",
output_buffer
end
@@ -3132,9 +3132,9 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "create-post", "edit_post", method: "patch") do
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
- "<input name='parent_post[secret]' type='hidden' value='0' />" +
+ "<input name='post[title]' type='text' id='post_title' value='Hello World' />" \
+ "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" \
+ "<input name='parent_post[secret]' type='hidden' value='0' />" \
"<input name='parent_post[secret]' checked='checked' type='checkbox' id='parent_post_secret' value='1' />"
end
@@ -3152,8 +3152,8 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "create-post", "edit_post", method: "patch") do
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
+ "<input name='post[title]' type='text' id='post_title' value='Hello World' />" \
+ "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" \
"<input name='post[comment][name]' type='text' id='post_comment_name' value='new comment' />"
end
@@ -3192,8 +3192,8 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- "<label for='title'>Title:</label> <input name='post[title]' type='text' id='post_title' value='Hello World' /><br/>" +
- "<label for='body'>Body:</label> <textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea><br/>" +
+ "<label for='title'>Title:</label> <input name='post[title]' type='text' id='post_title' value='Hello World' /><br/>" \
+ "<label for='body'>Body:</label> <textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea><br/>" \
"<label for='secret'>Secret:</label> <input name='post[secret]' type='hidden' value='0' /><input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' /><br/>"
end
@@ -3211,8 +3211,8 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do
- "<label for='title'>Title:</label> <input name='post[title]' type='text' id='post_title' value='Hello World' /><br/>" +
- "<label for='body'>Body:</label> <textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea><br/>" +
+ "<label for='title'>Title:</label> <input name='post[title]' type='text' id='post_title' value='Hello World' /><br/>" \
+ "<label for='body'>Body:</label> <textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea><br/>" \
"<label for='secret'>Secret:</label> <input name='post[secret]' type='hidden' value='0' /><input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' /><br/>"
end
@@ -3270,8 +3270,8 @@ class FormHelperTest < ActionView::TestCase
end
expected =
- "<label for='title'>Title:</label> <input name='post[title]' type='text' id='post_title' value='Hello World' /><br/>" +
- "<label for='body'>Body:</label> <textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea><br/>" +
+ "<label for='title'>Title:</label> <input name='post[title]' type='text' id='post_title' value='Hello World' /><br/>" \
+ "<label for='body'>Body:</label> <textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea><br/>" \
"<label for='secret'>Secret:</label> <input name='post[secret]' type='hidden' value='0' /><input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' /><br/>"
assert_dom_equal expected, output_buffer
diff --git a/actionview/test/template/form_options_helper_test.rb b/actionview/test/template/form_options_helper_test.rb
index 51f5d25958..258dcdb806 100644
--- a/actionview/test/template/form_options_helper_test.rb
+++ b/actionview/test/template/form_options_helper_test.rb
@@ -393,30 +393,30 @@ class FormOptionsHelperTest < ActionView::TestCase
def test_time_zone_options_no_params
opts = time_zone_options_for_select
- assert_dom_equal "<option value=\"A\">A</option>\n" +
- "<option value=\"B\">B</option>\n" +
- "<option value=\"C\">C</option>\n" +
- "<option value=\"D\">D</option>\n" +
+ assert_dom_equal "<option value=\"A\">A</option>\n" \
+ "<option value=\"B\">B</option>\n" \
+ "<option value=\"C\">C</option>\n" \
+ "<option value=\"D\">D</option>\n" \
"<option value=\"E\">E</option>",
opts
end
def test_time_zone_options_with_selected
opts = time_zone_options_for_select("D")
- assert_dom_equal "<option value=\"A\">A</option>\n" +
- "<option value=\"B\">B</option>\n" +
- "<option value=\"C\">C</option>\n" +
- "<option value=\"D\" selected=\"selected\">D</option>\n" +
+ assert_dom_equal "<option value=\"A\">A</option>\n" \
+ "<option value=\"B\">B</option>\n" \
+ "<option value=\"C\">C</option>\n" \
+ "<option value=\"D\" selected=\"selected\">D</option>\n" \
"<option value=\"E\">E</option>",
opts
end
def test_time_zone_options_with_unknown_selected
opts = time_zone_options_for_select("K")
- assert_dom_equal "<option value=\"A\">A</option>\n" +
- "<option value=\"B\">B</option>\n" +
- "<option value=\"C\">C</option>\n" +
- "<option value=\"D\">D</option>\n" +
+ assert_dom_equal "<option value=\"A\">A</option>\n" \
+ "<option value=\"B\">B</option>\n" \
+ "<option value=\"C\">C</option>\n" \
+ "<option value=\"D\">D</option>\n" \
"<option value=\"E\">E</option>",
opts
end
@@ -424,11 +424,11 @@ class FormOptionsHelperTest < ActionView::TestCase
def test_time_zone_options_with_priority_zones
zones = [ ActiveSupport::TimeZone.new("B"), ActiveSupport::TimeZone.new("E") ]
opts = time_zone_options_for_select(nil, zones)
- assert_dom_equal "<option value=\"B\">B</option>\n" +
- "<option value=\"E\">E</option>" +
- "<option value=\"\" disabled=\"disabled\">-------------</option>\n" +
- "<option value=\"A\">A</option>\n" +
- "<option value=\"C\">C</option>\n" +
+ assert_dom_equal "<option value=\"B\">B</option>\n" \
+ "<option value=\"E\">E</option>" \
+ "<option value=\"\" disabled=\"disabled\">-------------</option>\n" \
+ "<option value=\"A\">A</option>\n" \
+ "<option value=\"C\">C</option>\n" \
"<option value=\"D\">D</option>",
opts
end
@@ -436,11 +436,11 @@ class FormOptionsHelperTest < ActionView::TestCase
def test_time_zone_options_with_selected_priority_zones
zones = [ ActiveSupport::TimeZone.new("B"), ActiveSupport::TimeZone.new("E") ]
opts = time_zone_options_for_select("E", zones)
- assert_dom_equal "<option value=\"B\">B</option>\n" +
- "<option value=\"E\" selected=\"selected\">E</option>" +
- "<option value=\"\" disabled=\"disabled\">-------------</option>\n" +
- "<option value=\"A\">A</option>\n" +
- "<option value=\"C\">C</option>\n" +
+ assert_dom_equal "<option value=\"B\">B</option>\n" \
+ "<option value=\"E\" selected=\"selected\">E</option>" \
+ "<option value=\"\" disabled=\"disabled\">-------------</option>\n" \
+ "<option value=\"A\">A</option>\n" \
+ "<option value=\"C\">C</option>\n" \
"<option value=\"D\">D</option>",
opts
end
@@ -448,11 +448,11 @@ class FormOptionsHelperTest < ActionView::TestCase
def test_time_zone_options_with_unselected_priority_zones
zones = [ ActiveSupport::TimeZone.new("B"), ActiveSupport::TimeZone.new("E") ]
opts = time_zone_options_for_select("C", zones)
- assert_dom_equal "<option value=\"B\">B</option>\n" +
- "<option value=\"E\">E</option>" +
- "<option value=\"\" disabled=\"disabled\">-------------</option>\n" +
- "<option value=\"A\">A</option>\n" +
- "<option value=\"C\" selected=\"selected\">C</option>\n" +
+ assert_dom_equal "<option value=\"B\">B</option>\n" \
+ "<option value=\"E\">E</option>" \
+ "<option value=\"\" disabled=\"disabled\">-------------</option>\n" \
+ "<option value=\"A\">A</option>\n" \
+ "<option value=\"C\" selected=\"selected\">C</option>\n" \
"<option value=\"D\">D</option>",
opts
end
@@ -1031,12 +1031,12 @@ class FormOptionsHelperTest < ActionView::TestCase
def test_time_zone_select
@firm = Firm.new("D")
html = time_zone_select("firm", "time_zone")
- assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" +
- "<option value=\"A\">A</option>\n" +
- "<option value=\"B\">B</option>\n" +
- "<option value=\"C\">C</option>\n" +
- "<option value=\"D\" selected=\"selected\">D</option>\n" +
- "<option value=\"E\">E</option>" +
+ assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" \
+ "<option value=\"A\">A</option>\n" \
+ "<option value=\"B\">B</option>\n" \
+ "<option value=\"C\">C</option>\n" \
+ "<option value=\"D\" selected=\"selected\">D</option>\n" \
+ "<option value=\"E\">E</option>" \
"</select>",
html
end
@@ -1049,12 +1049,12 @@ class FormOptionsHelperTest < ActionView::TestCase
end
assert_dom_equal(
- "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" +
- "<option value=\"A\">A</option>\n" +
- "<option value=\"B\">B</option>\n" +
- "<option value=\"C\">C</option>\n" +
- "<option value=\"D\" selected=\"selected\">D</option>\n" +
- "<option value=\"E\">E</option>" +
+ "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" \
+ "<option value=\"A\">A</option>\n" \
+ "<option value=\"B\">B</option>\n" \
+ "<option value=\"C\">C</option>\n" \
+ "<option value=\"D\" selected=\"selected\">D</option>\n" \
+ "<option value=\"E\">E</option>" \
"</select>",
output_buffer
)
@@ -1068,12 +1068,12 @@ class FormOptionsHelperTest < ActionView::TestCase
end
assert_dom_equal(
- "<select id=\"firm_305_time_zone\" name=\"firm[305][time_zone]\">" +
- "<option value=\"A\">A</option>\n" +
- "<option value=\"B\">B</option>\n" +
- "<option value=\"C\">C</option>\n" +
- "<option value=\"D\" selected=\"selected\">D</option>\n" +
- "<option value=\"E\">E</option>" +
+ "<select id=\"firm_305_time_zone\" name=\"firm[305][time_zone]\">" \
+ "<option value=\"A\">A</option>\n" \
+ "<option value=\"B\">B</option>\n" \
+ "<option value=\"C\">C</option>\n" \
+ "<option value=\"D\" selected=\"selected\">D</option>\n" \
+ "<option value=\"E\">E</option>" \
"</select>",
output_buffer
)
@@ -1088,12 +1088,12 @@ class FormOptionsHelperTest < ActionView::TestCase
end
assert_dom_equal(
- "<select id=\"firm_305_time_zone\" name=\"firm[305][time_zone]\">" +
- "<option value=\"A\">A</option>\n" +
- "<option value=\"B\">B</option>\n" +
- "<option value=\"C\">C</option>\n" +
- "<option value=\"D\" selected=\"selected\">D</option>\n" +
- "<option value=\"E\">E</option>" +
+ "<select id=\"firm_305_time_zone\" name=\"firm[305][time_zone]\">" \
+ "<option value=\"A\">A</option>\n" \
+ "<option value=\"B\">B</option>\n" \
+ "<option value=\"C\">C</option>\n" \
+ "<option value=\"D\" selected=\"selected\">D</option>\n" \
+ "<option value=\"E\">E</option>" \
"</select>",
output_buffer
)
@@ -1102,13 +1102,13 @@ class FormOptionsHelperTest < ActionView::TestCase
def test_time_zone_select_with_blank
@firm = Firm.new("D")
html = time_zone_select("firm", "time_zone", nil, include_blank: true)
- assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" +
- "<option value=\"\"></option>\n" +
- "<option value=\"A\">A</option>\n" +
- "<option value=\"B\">B</option>\n" +
- "<option value=\"C\">C</option>\n" +
- "<option value=\"D\" selected=\"selected\">D</option>\n" +
- "<option value=\"E\">E</option>" +
+ assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" \
+ "<option value=\"\"></option>\n" \
+ "<option value=\"A\">A</option>\n" \
+ "<option value=\"B\">B</option>\n" \
+ "<option value=\"C\">C</option>\n" \
+ "<option value=\"D\" selected=\"selected\">D</option>\n" \
+ "<option value=\"E\">E</option>" \
"</select>",
html
end
@@ -1116,13 +1116,13 @@ class FormOptionsHelperTest < ActionView::TestCase
def test_time_zone_select_with_blank_as_string
@firm = Firm.new("D")
html = time_zone_select("firm", "time_zone", nil, include_blank: "No Zone")
- assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" +
- "<option value=\"\">No Zone</option>\n" +
- "<option value=\"A\">A</option>\n" +
- "<option value=\"B\">B</option>\n" +
- "<option value=\"C\">C</option>\n" +
- "<option value=\"D\" selected=\"selected\">D</option>\n" +
- "<option value=\"E\">E</option>" +
+ assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" \
+ "<option value=\"\">No Zone</option>\n" \
+ "<option value=\"A\">A</option>\n" \
+ "<option value=\"B\">B</option>\n" \
+ "<option value=\"C\">C</option>\n" \
+ "<option value=\"D\" selected=\"selected\">D</option>\n" \
+ "<option value=\"E\">E</option>" \
"</select>",
html
end
@@ -1131,12 +1131,12 @@ class FormOptionsHelperTest < ActionView::TestCase
@firm = Firm.new("D")
html = time_zone_select("firm", "time_zone", nil, {},
"style" => "color: red")
- assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\" style=\"color: red\">" +
- "<option value=\"A\">A</option>\n" +
- "<option value=\"B\">B</option>\n" +
- "<option value=\"C\">C</option>\n" +
- "<option value=\"D\" selected=\"selected\">D</option>\n" +
- "<option value=\"E\">E</option>" +
+ assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\" style=\"color: red\">" \
+ "<option value=\"A\">A</option>\n" \
+ "<option value=\"B\">B</option>\n" \
+ "<option value=\"C\">C</option>\n" \
+ "<option value=\"D\" selected=\"selected\">D</option>\n" \
+ "<option value=\"E\">E</option>" \
"</select>",
html
assert_dom_equal html, time_zone_select("firm", "time_zone", nil, {},
@@ -1147,13 +1147,13 @@ class FormOptionsHelperTest < ActionView::TestCase
@firm = Firm.new("D")
html = time_zone_select("firm", "time_zone", nil,
{ include_blank: true }, "style" => "color: red")
- assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\" style=\"color: red\">" +
- "<option value=\"\"></option>\n" +
- "<option value=\"A\">A</option>\n" +
- "<option value=\"B\">B</option>\n" +
- "<option value=\"C\">C</option>\n" +
- "<option value=\"D\" selected=\"selected\">D</option>\n" +
- "<option value=\"E\">E</option>" +
+ assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\" style=\"color: red\">" \
+ "<option value=\"\"></option>\n" \
+ "<option value=\"A\">A</option>\n" \
+ "<option value=\"B\">B</option>\n" \
+ "<option value=\"C\">C</option>\n" \
+ "<option value=\"D\" selected=\"selected\">D</option>\n" \
+ "<option value=\"E\">E</option>" \
"</select>",
html
assert_dom_equal html, time_zone_select("firm", "time_zone", nil,
@@ -1164,13 +1164,13 @@ class FormOptionsHelperTest < ActionView::TestCase
@firm = Firm.new("D")
html = time_zone_select("firm", "time_zone", nil,
{ include_blank: "No Zone" }, "style" => "color: red")
- assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\" style=\"color: red\">" +
- "<option value=\"\">No Zone</option>\n" +
- "<option value=\"A\">A</option>\n" +
- "<option value=\"B\">B</option>\n" +
- "<option value=\"C\">C</option>\n" +
- "<option value=\"D\" selected=\"selected\">D</option>\n" +
- "<option value=\"E\">E</option>" +
+ assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\" style=\"color: red\">" \
+ "<option value=\"\">No Zone</option>\n" \
+ "<option value=\"A\">A</option>\n" \
+ "<option value=\"B\">B</option>\n" \
+ "<option value=\"C\">C</option>\n" \
+ "<option value=\"D\" selected=\"selected\">D</option>\n" \
+ "<option value=\"E\">E</option>" \
"</select>",
html
assert_dom_equal html, time_zone_select("firm", "time_zone", nil,
@@ -1181,13 +1181,13 @@ class FormOptionsHelperTest < ActionView::TestCase
@firm = Firm.new("D")
zones = [ ActiveSupport::TimeZone.new("A"), ActiveSupport::TimeZone.new("D") ]
html = time_zone_select("firm", "time_zone", zones)
- assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" +
- "<option value=\"A\">A</option>\n" +
- "<option value=\"D\" selected=\"selected\">D</option>" +
- "<option value=\"\" disabled=\"disabled\">-------------</option>\n" +
- "<option value=\"B\">B</option>\n" +
- "<option value=\"C\">C</option>\n" +
- "<option value=\"E\">E</option>" +
+ assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" \
+ "<option value=\"A\">A</option>\n" \
+ "<option value=\"D\" selected=\"selected\">D</option>" \
+ "<option value=\"\" disabled=\"disabled\">-------------</option>\n" \
+ "<option value=\"B\">B</option>\n" \
+ "<option value=\"C\">C</option>\n" \
+ "<option value=\"E\">E</option>" \
"</select>",
html
end
@@ -1200,13 +1200,13 @@ class FormOptionsHelperTest < ActionView::TestCase
end
html = time_zone_select("firm", "time_zone", /A|D/)
- assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" +
- "<option value=\"A\">A</option>\n" +
- "<option value=\"D\" selected=\"selected\">D</option>" +
- "<option value=\"\" disabled=\"disabled\">-------------</option>\n" +
- "<option value=\"B\">B</option>\n" +
- "<option value=\"C\">C</option>\n" +
- "<option value=\"E\">E</option>" +
+ assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" \
+ "<option value=\"A\">A</option>\n" \
+ "<option value=\"D\" selected=\"selected\">D</option>" \
+ "<option value=\"\" disabled=\"disabled\">-------------</option>\n" \
+ "<option value=\"B\">B</option>\n" \
+ "<option value=\"C\">C</option>\n" \
+ "<option value=\"E\">E</option>" \
"</select>",
html
end
@@ -1221,13 +1221,13 @@ class FormOptionsHelperTest < ActionView::TestCase
end
html = time_zone_select("firm", "time_zone", /A|D/)
- assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" +
- "<option value=\"\" disabled=\"disabled\">-------------</option>\n" +
- "<option value=\"A\">A</option>\n" +
- "<option value=\"B\">B</option>\n" +
- "<option value=\"C\">C</option>\n" +
- "<option value=\"D\" selected=\"selected\">D</option>\n" +
- "<option value=\"E\">E</option>" +
+ assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" \
+ "<option value=\"\" disabled=\"disabled\">-------------</option>\n" \
+ "<option value=\"A\">A</option>\n" \
+ "<option value=\"B\">B</option>\n" \
+ "<option value=\"C\">C</option>\n" \
+ "<option value=\"D\" selected=\"selected\">D</option>\n" \
+ "<option value=\"E\">E</option>" \
"</select>",
html
end
@@ -1237,12 +1237,12 @@ class FormOptionsHelperTest < ActionView::TestCase
@firm.time_zone = nil
html = time_zone_select("firm", "time_zone", nil, default: "B")
- assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" +
- "<option value=\"A\">A</option>\n" +
- "<option value=\"B\" selected=\"selected\">B</option>\n" +
- "<option value=\"C\">C</option>\n" +
- "<option value=\"D\">D</option>\n" +
- "<option value=\"E\">E</option>" +
+ assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" \
+ "<option value=\"A\">A</option>\n" \
+ "<option value=\"B\" selected=\"selected\">B</option>\n" \
+ "<option value=\"C\">C</option>\n" \
+ "<option value=\"D\">D</option>\n" \
+ "<option value=\"E\">E</option>" \
"</select>",
html
end
@@ -1251,12 +1251,12 @@ class FormOptionsHelperTest < ActionView::TestCase
@firm = Firm.new("D")
html = time_zone_select("firm", "time_zone", nil, default: "B")
- assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" +
- "<option value=\"A\">A</option>\n" +
- "<option value=\"B\">B</option>\n" +
- "<option value=\"C\">C</option>\n" +
- "<option value=\"D\" selected=\"selected\">D</option>\n" +
- "<option value=\"E\">E</option>" +
+ assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" \
+ "<option value=\"A\">A</option>\n" \
+ "<option value=\"B\">B</option>\n" \
+ "<option value=\"C\">C</option>\n" \
+ "<option value=\"D\" selected=\"selected\">D</option>\n" \
+ "<option value=\"E\">E</option>" \
"</select>",
html
end
diff --git a/actionview/test/template/output_safety_helper_test.rb b/actionview/test/template/output_safety_helper_test.rb
index 8691bb11ee..537b4393ee 100644
--- a/actionview/test/template/output_safety_helper_test.rb
+++ b/actionview/test/template/output_safety_helper_test.rb
@@ -33,6 +33,22 @@ class OutputSafetyHelperTest < ActionView::TestCase
assert_equal "&quot;a&quot; &lt;br/&gt; &lt;b&gt; &lt;br/&gt; &lt;c&gt;", joined
end
+ test "safe_join should return the safe string separated by $, when second argument is not passed" do
+ default_delimeter = $,
+
+ begin
+ $, = nil
+ joined = safe_join(["a", "b"])
+ assert_equal "ab", joined
+
+ $, = "|"
+ joined = safe_join(["a", "b"])
+ assert_equal "a|b", joined
+ ensure
+ $, = default_delimeter
+ end
+ end
+
test "to_sentence should escape non-html_safe values" do
actual = to_sentence(%w(< > & ' "))
assert actual.html_safe?
@@ -87,4 +103,15 @@ class OutputSafetyHelperTest < ActionView::TestCase
assert_equal "one, two three", to_sentence(["one", "two", "three"], last_word_connector: " ")
assert_equal "one, two and three", to_sentence(["one", "two", "three"], last_word_connector: " and ")
end
+
+ test "to_sentence is not affected by $," do
+ separator_was = $,
+ $, = "|"
+ begin
+ assert_equal "one and two", to_sentence(["one", "two"])
+ assert_equal "one, two, and three", to_sentence(["one", "two", "three"])
+ ensure
+ $, = separator_was
+ end
+ end
end
diff --git a/actionview/test/template/render_test.rb b/actionview/test/template/render_test.rb
index 2651d6ff73..d189b2aa87 100644
--- a/actionview/test/template/render_test.rb
+++ b/actionview/test/template/render_test.rb
@@ -220,15 +220,15 @@ module RenderTestCases
def test_render_partial_with_invalid_option_as
e = assert_raises(ArgumentError) { @view.render(partial: "test/partial_only", as: "a-in") }
- assert_equal "The value (a-in) of the option `as` is not a valid Ruby identifier; " +
- "make sure it starts with lowercase letter, " +
+ assert_equal "The value (a-in) of the option `as` is not a valid Ruby identifier; " \
+ "make sure it starts with lowercase letter, " \
"and is followed by any combination of letters, numbers and underscores.", e.message
end
def test_render_partial_with_hyphen_and_invalid_option_as
e = assert_raises(ArgumentError) { @view.render(partial: "test/a-in", as: "a-in") }
- assert_equal "The value (a-in) of the option `as` is not a valid Ruby identifier; " +
- "make sure it starts with lowercase letter, " +
+ assert_equal "The value (a-in) of the option `as` is not a valid Ruby identifier; " \
+ "make sure it starts with lowercase letter, " \
"and is followed by any combination of letters, numbers and underscores.", e.message
end
@@ -424,7 +424,7 @@ module RenderTestCases
end
CustomHandler = lambda do |template|
- "@output_buffer = ''\n" +
+ "@output_buffer = ''\n" \
"@output_buffer << 'source: #{template.source.inspect}'\n"
end
diff --git a/actionview/test/template/text_test.rb b/actionview/test/template/text_test.rb
index ee526dc367..72ffd5f3be 100644
--- a/actionview/test/template/text_test.rb
+++ b/actionview/test/template/text_test.rb
@@ -4,4 +4,20 @@ class TextTest < ActiveSupport::TestCase
test "formats always return :text" do
assert_equal [:text], ActionView::Template::Text.new("").formats
end
+
+ test "identifier should return 'text template'" do
+ assert_equal "text template", ActionView::Template::Text.new("").identifier
+ end
+
+ test "inspect should return 'text template'" do
+ assert_equal "text template", ActionView::Template::Text.new("").inspect
+ end
+
+ test "to_str should return a given string" do
+ assert_equal "a cat", ActionView::Template::Text.new("a cat").to_str
+ end
+
+ test "render should return a given string" do
+ assert_equal "a dog", ActionView::Template::Text.new("a dog").render
+ end
end
diff --git a/actionview/test/template/url_helper_test.rb b/actionview/test/template/url_helper_test.rb
index 95bea21c8f..09454b32cc 100644
--- a/actionview/test/template/url_helper_test.rb
+++ b/actionview/test/template/url_helper_test.rb
@@ -821,7 +821,7 @@ class TasksController < ActionController::Base
private
def render_default
- render inline: "<%= link_to_unless_current('tasks', tasks_path) %>\n" +
+ render inline: "<%= link_to_unless_current('tasks', tasks_path) %>\n" \
"<%= link_to_unless_current('tasks', tasks_url) %>"
end
end
diff --git a/actionview/test/ujs/public/test/settings.js b/actionview/test/ujs/public/test/settings.js
index 3375456f11..c68ca24d6a 100644
--- a/actionview/test/ujs/public/test/settings.js
+++ b/actionview/test/ujs/public/test/settings.js
@@ -76,7 +76,7 @@ try {
}
$.fn.extend({
- // trigger an native click event
+ // trigger a native click event
triggerNative: function(type, options) {
var el = this[0],
event,
diff --git a/activejob/lib/active_job/queue_adapter.rb b/activejob/lib/active_job/queue_adapter.rb
index bcc555d33e..9dae80ffc2 100644
--- a/activejob/lib/active_job/queue_adapter.rb
+++ b/activejob/lib/active_job/queue_adapter.rb
@@ -1,4 +1,3 @@
-require "active_job/queue_adapters/inline_adapter"
require "active_support/core_ext/string/inflections"
module ActiveJob
diff --git a/activejob/lib/active_job/test_helper.rb b/activejob/lib/active_job/test_helper.rb
index d01795f0c5..f7085c87c5 100644
--- a/activejob/lib/active_job/test_helper.rb
+++ b/activejob/lib/active_job/test_helper.rb
@@ -55,7 +55,7 @@ module ActiveJob
# assert_enqueued_jobs 2
# end
#
- # If a block is passed, that block should cause the specified number of
+ # If a block is passed, that block will cause the specified number of
# jobs to be enqueued.
#
# def test_jobs_again
@@ -77,14 +77,23 @@ module ActiveJob
# HelloJob.perform_later('jeremy')
# end
# end
- def assert_enqueued_jobs(number, only: nil)
+ #
+ # The number of times a job is enqueued to a specific queue can also be asserted.
+ #
+ # def test_logging_job
+ # assert_enqueued_jobs 2, queue: 'default' do
+ # LoggingJob.perform_later
+ # HelloJob.perform_later('elfassy')
+ # end
+ # end
+ def assert_enqueued_jobs(number, only: nil, queue: nil)
if block_given?
- original_count = enqueued_jobs_size(only: only)
+ original_count = enqueued_jobs_size(only: only, queue: queue)
yield
- new_count = enqueued_jobs_size(only: only)
+ new_count = enqueued_jobs_size(only: only, queue: queue)
assert_equal number, new_count - original_count, "#{number} jobs expected, but #{new_count - original_count} were enqueued"
else
- actual_count = enqueued_jobs_size(only: only)
+ actual_count = enqueued_jobs_size(only: only, queue: queue)
assert_equal number, actual_count, "#{number} jobs expected, but #{actual_count} were enqueued"
end
end
@@ -284,7 +293,7 @@ module ActiveJob
# def test_perform_enqueued_jobs_with_only
# perform_enqueued_jobs(only: MyJob) do
# MyJob.perform_later(1, 2, 3) # will be performed
- # HelloJob.perform_later(1, 2, 3) # will not be perfomed
+ # HelloJob.perform_later(1, 2, 3) # will not be performed
# end
# assert_performed_jobs 1
# end
@@ -323,11 +332,16 @@ module ActiveJob
performed_jobs.clear
end
- def enqueued_jobs_size(only: nil)
- if only
- enqueued_jobs.count { |job| Array(only).include?(job.fetch(:job)) }
- else
- enqueued_jobs.count
+ def enqueued_jobs_size(only: nil, queue: nil)
+ enqueued_jobs.count do |job|
+ job_class = job.fetch(:job)
+ if only
+ next false unless Array(only).include?(job_class)
+ end
+ if queue
+ next false unless queue.to_s == job.fetch(:queue, job_class.queue_name)
+ end
+ true
end
end
diff --git a/activejob/test/cases/test_helper_test.rb b/activejob/test/cases/test_helper_test.rb
index 51fc6cc0c4..5488ce3d58 100644
--- a/activejob/test/cases/test_helper_test.rb
+++ b/activejob/test/cases/test_helper_test.rb
@@ -110,6 +110,27 @@ class EnqueuedJobsTest < ActiveJob::TestCase
end
end
+ def test_assert_enqueued_jobs_with_only_and_queue_option
+ assert_nothing_raised do
+ assert_enqueued_jobs 1, only: HelloJob, queue: :some_queue do
+ HelloJob.set(queue: :some_queue).perform_later
+ HelloJob.set(queue: :other_queue).perform_later
+ LoggingJob.perform_later
+ end
+ end
+ end
+
+ def test_assert_enqueued_jobs_with_queue_option
+ assert_nothing_raised do
+ assert_enqueued_jobs 2, queue: :default do
+ HelloJob.perform_later
+ LoggingJob.perform_later
+ HelloJob.set(queue: :other_queue).perform_later
+ LoggingJob.set(queue: :other_queue).perform_later
+ end
+ end
+ end
+
def test_assert_enqueued_jobs_with_only_option_and_none_sent
error = assert_raise ActiveSupport::TestCase::Assertion do
assert_enqueued_jobs 1, only: HelloJob do
diff --git a/activejob/test/support/integration/adapters/backburner.rb b/activejob/test/support/integration/adapters/backburner.rb
index 263097c792..2e194933a1 100644
--- a/activejob/test/support/integration/adapters/backburner.rb
+++ b/activejob/test/support/integration/adapters/backburner.rb
@@ -23,12 +23,12 @@ module BackburnerJobsManager
end
def tube
- @tube ||= Beaneater::Tube.new(Backburner::Worker.connection, "backburner.worker.queue.integration-tests") # backburner dasherizes the queue name
+ @tube ||= Beaneater::Tube.new(@worker.connection, "backburner.worker.queue.integration-tests") # backburner dasherizes the queue name
end
def can_run?
begin
- Backburner::Worker.connection.send :connect!
+ @worker = Backburner::Worker.new
rescue
return false
end
diff --git a/activemodel/lib/active_model/type/decimal.rb b/activemodel/lib/active_model/type/decimal.rb
index 6c5c0451c6..541a12c8a1 100644
--- a/activemodel/lib/active_model/type/decimal.rb
+++ b/activemodel/lib/active_model/type/decimal.rb
@@ -4,6 +4,7 @@ module ActiveModel
module Type
class Decimal < Value # :nodoc:
include Helpers::Numeric
+ BIGDECIMAL_PRECISION = 18
def type
:decimal
@@ -21,7 +22,7 @@ module ActiveModel
when ::Float
convert_float_to_big_decimal(value)
when ::Numeric, ::String
- BigDecimal(value, precision.to_i)
+ BigDecimal(value, precision || BIGDECIMAL_PRECISION)
else
if value.respond_to?(:to_d)
value.to_d
diff --git a/activemodel/test/cases/errors_test.rb b/activemodel/test/cases/errors_test.rb
index e6ba06301d..0872084cf5 100644
--- a/activemodel/test/cases/errors_test.rb
+++ b/activemodel/test/cases/errors_test.rb
@@ -1,4 +1,5 @@
require "cases/helper"
+require "active_support/core_ext/string/strip"
require "yaml"
class ErrorsTest < ActiveModel::TestCase
diff --git a/activemodel/test/cases/helper.rb b/activemodel/test/cases/helper.rb
index 4e9f43ad86..40dfb8e589 100644
--- a/activemodel/test/cases/helper.rb
+++ b/activemodel/test/cases/helper.rb
@@ -9,15 +9,15 @@ I18n.enforce_available_locales = false
require "active_support/testing/autorun"
require "active_support/testing/method_call_assertions"
-# Skips the current run on Rubinius using Minitest::Assertions#skip
-def rubinius_skip(message = "")
- skip message if RUBY_ENGINE == "rbx"
-end
-# Skips the current run on JRuby using Minitest::Assertions#skip
-def jruby_skip(message = "")
- skip message if defined?(JRUBY_VERSION)
-end
-
class ActiveModel::TestCase
include ActiveSupport::Testing::MethodCallAssertions
+
+ # Skips the current run on Rubinius using Minitest::Assertions#skip
+ private def rubinius_skip(message = "")
+ skip message if RUBY_ENGINE == "rbx"
+ end
+ # Skips the current run on JRuby using Minitest::Assertions#skip
+ private def jruby_skip(message = "")
+ skip message if defined?(JRUBY_VERSION)
+ end
end
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 18c9a248b2..acdf7d40f8 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,11 +1,31 @@
+* Deprecate `initialize_schema_migrations_table` and `initialize_internal_metadata_table`.
+
+ *Ryuta Kamizono*
+
+* Support foreign key creation for SQLite3.
+
+ *Ryuta Kamizono*
+
+* Place generated migrations into the path set by `config.paths["db/migrate"]`.
+
+ *Kevin Glowacz*
+
+* Raise `ActiveRecord::InvalidForeignKey` when a foreign key constraint fails on SQLite3.
+
+ *Ryuta Kamizono*
+
+* Add the touch option to ActiveRecord#increment! and decrement!.
+
+ *Hiroaki Izu*
+
* Deprecate passing a class to the `class_name` because it eagerloads more classes than
necessary and potentially creates circular dependencies.
*Kir Shatrov*
-* Raise error when has_many through is defined before through association
+* Raise error when has_many through is defined before through association.
- Fixes #26834
+ Fixes #26834.
*Chris Holmes*
@@ -416,7 +436,7 @@
*Ryuta Kamizono*
-* Sqlite3 migrations to add a column to an existing table can now be
+* SQLite3 migrations to add a column to an existing table can now be
successfully rolled back when the column was given and invalid column
type.
diff --git a/activerecord/lib/active_record/associations/has_one_association.rb b/activerecord/lib/active_record/associations/has_one_association.rb
index b624154def..8458253ff8 100644
--- a/activerecord/lib/active_record/associations/has_one_association.rb
+++ b/activerecord/lib/active_record/associations/has_one_association.rb
@@ -85,7 +85,7 @@ module ActiveRecord
if target.persisted? && owner.persisted? && !target.save
set_owner_attributes(target)
- raise RecordNotSaved, "Failed to remove the existing associated #{reflection.name}. " +
+ raise RecordNotSaved, "Failed to remove the existing associated #{reflection.name}. " \
"The record failed to save after its foreign key was set to nil."
end
end
diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb
index 4cd1e64c3d..87e0847ec1 100644
--- a/activerecord/lib/active_record/associations/join_dependency.rb
+++ b/activerecord/lib/active_record/associations/join_dependency.rb
@@ -32,7 +32,7 @@ module ActiveRecord
@alias_cache[node][column]
end
- class Table < Struct.new(:node, :columns) # :nodoc:
+ Table = Struct.new(:node, :columns) do # :nodoc:
def table
Arel::Nodes::TableAlias.new node.table, node.aliased_table_name
end
@@ -171,7 +171,7 @@ module ActiveRecord
chain = child.reflection.chain
foreign_table = parent.table
foreign_klass = parent.base_klass
- child.join_constraints(foreign_table, foreign_klass, child, join_type, tables, child.reflection.scope_chain, chain)
+ child.join_constraints(foreign_table, foreign_klass, child, join_type, tables, chain)
end
def make_outer_joins(parent, child)
diff --git a/activerecord/lib/active_record/associations/join_dependency/join_association.rb b/activerecord/lib/active_record/associations/join_dependency/join_association.rb
index a5705951f3..f5fcba1236 100644
--- a/activerecord/lib/active_record/associations/join_dependency/join_association.rb
+++ b/activerecord/lib/active_record/associations/join_dependency/join_association.rb
@@ -23,14 +23,11 @@ module ActiveRecord
JoinInformation = Struct.new :joins, :binds
- def join_constraints(foreign_table, foreign_klass, node, join_type, tables, scope_chain, chain)
+ def join_constraints(foreign_table, foreign_klass, node, join_type, tables, chain)
joins = []
binds = []
tables = tables.reverse
- scope_chain_index = 0
- scope_chain = scope_chain.reverse
-
# The chain starts with the target table, but we want to end with it here (makes
# more sense in this context), so we reverse
chain.reverse_each do |reflection|
@@ -44,7 +41,7 @@ module ActiveRecord
constraint = build_constraint(klass, table, key, foreign_table, foreign_key)
predicate_builder = PredicateBuilder.new(TableMetadata.new(klass, table))
- scope_chain_items = scope_chain[scope_chain_index].map do |item|
+ scope_chain_items = reflection.scopes.map do |item|
if item.is_a?(Relation)
item
else
@@ -52,7 +49,6 @@ module ActiveRecord
.instance_exec(node, &item)
end
end
- scope_chain_index += 1
klass_scope =
if klass.current_scope
diff --git a/activerecord/lib/active_record/attribute_methods/serialization.rb b/activerecord/lib/active_record/attribute_methods/serialization.rb
index 945192fe04..4d9aff76cc 100644
--- a/activerecord/lib/active_record/attribute_methods/serialization.rb
+++ b/activerecord/lib/active_record/attribute_methods/serialization.rb
@@ -54,7 +54,7 @@ module ActiveRecord
elsif [:load, :dump].all? { |x| class_name_or_coder.respond_to?(x) }
class_name_or_coder
else
- Coders::YAMLColumn.new(class_name_or_coder)
+ Coders::YAMLColumn.new(attr_name, class_name_or_coder)
end
decorate_attribute_type(attr_name, :serialize) do |type|
diff --git a/activerecord/lib/active_record/coders/yaml_column.rb b/activerecord/lib/active_record/coders/yaml_column.rb
index 3a04a10fc9..2136da43fe 100644
--- a/activerecord/lib/active_record/coders/yaml_column.rb
+++ b/activerecord/lib/active_record/coders/yaml_column.rb
@@ -5,7 +5,8 @@ module ActiveRecord
class YAMLColumn # :nodoc:
attr_accessor :object_class
- def initialize(object_class = Object)
+ def initialize(attr_name, object_class = Object)
+ @attr_name = attr_name
@object_class = object_class
check_arity_of_constructor
end
@@ -31,18 +32,16 @@ module ActiveRecord
def assert_valid_value(obj)
unless obj.nil? || obj.is_a?(object_class)
raise SerializationTypeMismatch,
- "Attribute was supposed to be a #{object_class}, but was a #{obj.class}. -- #{obj.inspect}"
+ "Attribute `#{@attr_name}` was supposed to be a #{object_class}, but was a #{obj.class}. -- #{obj.inspect}"
end
end
private
def check_arity_of_constructor
- begin
- load(nil)
- rescue ArgumentError
- raise ArgumentError, "Cannot serialize #{object_class}. Classes passed to `serialize` must have a 0 argument constructor."
- end
+ load(nil)
+ rescue ArgumentError
+ raise ArgumentError, "Cannot serialize #{object_class}. Classes passed to `serialize` must have a 0 argument constructor."
end
end
end
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 5ec2fc073e..ce4721c99d 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -967,7 +967,7 @@ module ActiveRecord
end
def pool_from_any_process_for(spec_name)
- owner_to_pool = @owner_to_pool.values.find { |v| v[spec_name] }
+ owner_to_pool = @owner_to_pool.values.reverse.find { |v| v[spec_name] }
owner_to_pool && owner_to_pool[spec_name]
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
index 0c6bc16e6f..437e7c6510 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
@@ -1,4 +1,5 @@
require "active_support/core_ext/big_decimal/conversions"
+require "active_support/multibyte/chars"
module ActiveRecord
module ConnectionAdapters # :nodoc:
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb
index 322684672f..807df2184a 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb
@@ -15,9 +15,9 @@ module ActiveRecord
end
delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
- :options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?, :foreign_key_options, to: :@conn
+ :options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys_in_create?, :foreign_key_options, to: :@conn
private :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
- :options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?, :foreign_key_options
+ :options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys_in_create?, :foreign_key_options
private
@@ -49,7 +49,7 @@ module ActiveRecord
statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
end
- if supports_foreign_keys?
+ if supports_foreign_keys_in_create?
statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
index 9b324c090b..b518ef760b 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -3,29 +3,25 @@ module ActiveRecord
# Abstract representation of an index definition on a table. Instances of
# this type are typically created and returned by methods in database
# adapters. e.g. ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter#indexes
- class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths, :orders, :where, :type, :using, :comment) #:nodoc:
- end
+ IndexDefinition = Struct.new(:table, :name, :unique, :columns, :lengths, :orders, :where, :type, :using, :comment) #:nodoc:
# Abstract representation of a column definition. Instances of this type
# are typically created by methods in TableDefinition, and added to the
# +columns+ attribute of said TableDefinition object, in order to be used
# for generating a number of table creation or table changing SQL statements.
- class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :auto_increment, :primary_key, :collation, :sql_type, :comment) #:nodoc:
+ ColumnDefinition = Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :auto_increment, :primary_key, :collation, :sql_type, :comment) do #:nodoc:
def primary_key?
primary_key || type.to_sym == :primary_key
end
end
- class AddColumnDefinition < Struct.new(:column) # :nodoc:
- end
+ AddColumnDefinition = Struct.new(:column) # :nodoc:
- class ChangeColumnDefinition < Struct.new(:column, :name) #:nodoc:
- end
+ ChangeColumnDefinition = Struct.new(:column, :name) #:nodoc:
- class PrimaryKeyDefinition < Struct.new(:name) # :nodoc:
- end
+ PrimaryKeyDefinition = Struct.new(:name) # :nodoc:
- class ForeignKeyDefinition < Struct.new(:from_table, :to_table, :options) #:nodoc:
+ ForeignKeyDefinition = Struct.new(:from_table, :to_table, :options) do #:nodoc:
def name
options[:name]
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index 1bdc086380..d7e2818e35 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -1008,15 +1008,15 @@ module ActiveRecord
end
end
- # Should not be called normally, but this operation is non-destructive.
- # The migrations module handles this automatically.
- def initialize_schema_migrations_table
+ def initialize_schema_migrations_table # :nodoc:
ActiveRecord::SchemaMigration.create_table
end
+ deprecate :initialize_schema_migrations_table
- def initialize_internal_metadata_table
+ def initialize_internal_metadata_table # :nodoc:
ActiveRecord::InternalMetadata.create_table
end
+ deprecate :initialize_internal_metadata_table
def internal_string_options_for_primary_key # :nodoc:
{ primary_key: true }
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index 4046b3829d..348396de72 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -176,7 +176,7 @@ module ActiveRecord
if @owner == Thread.current
msg << "it is already leased by the current thread."
else
- msg << "it is already in use by a different thread: #{@owner}. " <<
+ msg << "it is already in use by a different thread: #{@owner}. " \
"Current thread: #{Thread.current}."
end
raise ActiveRecordError, msg
@@ -194,8 +194,8 @@ module ActiveRecord
def expire
if in_use?
if @owner != Thread.current
- raise ActiveRecordError, "Cannot expire connection, " <<
- "it is owned by a different thread: #{@owner}. " <<
+ raise ActiveRecordError, "Cannot expire connection, " \
+ "it is owned by a different thread: #{@owner}. " \
"Current thread: #{Thread.current}."
end
@@ -310,6 +310,12 @@ module ActiveRecord
false
end
+ # Does this adapter support creating foreign key constraints
+ # in the same statement as creating the table?
+ def supports_foreign_keys_in_create?
+ supports_foreign_keys?
+ end
+
# Does this adapter support views?
def supports_views?
false
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/mysql/schema_definitions.rb
index 0cf40de70f..f1ba0cb708 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/schema_definitions.rb
@@ -3,10 +3,8 @@ module ActiveRecord
module MySQL
module ColumnMethods
def primary_key(name, type = :primary_key, **options)
- if type == :primary_key && !options.key?(:default)
- options[:auto_increment] = true
- options[:limit] = 8
- end
+ options[:auto_increment] = true if [:primary_key, :integer, :bigint].include?(type) && !options.key?(:default)
+ options[:limit] = 8 if [:primary_key].include?(type)
super
end
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb
index 2065816501..d44c35714f 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb
@@ -4,8 +4,8 @@ module ActiveRecord
module ColumnDumper
def column_spec_for_primary_key(column)
spec = super
- if column.type == :integer && !column.auto_increment?
- spec[:default] = schema_default(column) || "nil"
+ if [:integer, :bigint].include?(schema_type(column)) && !column.auto_increment?
+ spec[:default] ||= schema_default(column) || "nil"
end
spec[:unsigned] = "true" if column.unsigned?
spec
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_definitions.rb
index 4afb4733eb..c3e182b43d 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_definitions.rb
@@ -42,6 +42,7 @@ module ActiveRecord
# a record (as primary keys cannot be +nil+). This might be done via the
# +SecureRandom.uuid+ method and a +before_save+ callback, for instance.
def primary_key(name, type = :primary_key, **options)
+ options[:auto_increment] = true if [:primary_key, :integer, :bigint].include?(type) && !options.key?(:default)
if type == :uuid
options[:default] = options.fetch(:default, "gen_random_uuid()")
elsif options.delete(:auto_increment) == true && %i(integer bigint).include?(type)
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 0ebd907cc0..315d70c33f 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -759,11 +759,11 @@ module ActiveRecord
query(<<-end_sql, "SCHEMA")
SELECT a.attname, format_type(a.atttypid, a.atttypmod),
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
- (SELECT c.collname FROM pg_collation c, pg_type t
- WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation),
- col_description(a.attrelid, a.attnum) AS comment
- FROM pg_attribute a LEFT JOIN pg_attrdef d
- ON a.attrelid = d.adrelid AND a.attnum = d.adnum
+ c.collname, col_description(a.attrelid, a.attnum) AS comment
+ FROM pg_attribute a
+ LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
+ LEFT JOIN pg_type t ON a.atttypid = t.oid
+ LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
WHERE a.attrelid = #{quote(quote_table_name(table_name))}::regclass
AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY a.attnum
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb
index d0b38dff4c..f9bb7e6d82 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb
@@ -3,7 +3,7 @@ module ActiveRecord
module SQLite3
module ColumnMethods
def primary_key(name, type = :primary_key, **options)
- if options.delete(:auto_increment) == true && %i(integer bigint).include?(type)
+ if %i(integer bigint).include?(type) && (options.delete(:auto_increment) == true || !options.key?(:default))
type = :primary_key
end
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index ec44d020c2..ca6de37a6b 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -95,6 +95,8 @@ module ActiveRecord
@active = nil
@statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
+
+ configure_connection
end
def supports_ddl_transactions?
@@ -128,6 +130,10 @@ module ActiveRecord
true
end
+ def supports_foreign_keys_in_create?
+ sqlite_version >= "3.6.19"
+ end
+
def supports_views?
true
end
@@ -185,6 +191,19 @@ module ActiveRecord
true
end
+ # REFERENTIAL INTEGRITY ====================================
+
+ def disable_referential_integrity # :nodoc:
+ old = select_value("PRAGMA foreign_keys")
+
+ begin
+ execute("PRAGMA foreign_keys = OFF")
+ yield
+ ensure
+ execute("PRAGMA foreign_keys = #{old}")
+ end
+ end
+
#--
# DATABASE STATEMENTS ======================================
#++
@@ -424,6 +443,19 @@ module ActiveRecord
rename_column_indexes(table_name, column.name, new_column_name)
end
+ def foreign_keys(table_name)
+ fk_info = select_all("PRAGMA foreign_key_list(#{quote(table_name)})", "SCHEMA")
+ fk_info.map do |row|
+ options = {
+ column: row["from"],
+ primary_key: row["to"],
+ on_delete: extract_foreign_key_action(row["on_delete"]),
+ on_update: extract_foreign_key_action(row["on_update"])
+ }
+ ForeignKeyDefinition.new(table_name, row["table"], options)
+ end
+ end
+
private
def table_structure(table_name)
@@ -525,6 +557,8 @@ module ActiveRecord
RecordNotUnique.new(message)
when /.* may not be NULL/, /NOT NULL constraint failed: .*/
NotNullViolation.new(message)
+ when /FOREIGN KEY constraint failed/i
+ InvalidForeignKey.new(message)
else
super
end
@@ -574,6 +608,18 @@ module ActiveRecord
def create_table_definition(*args)
SQLite3::TableDefinition.new(*args)
end
+
+ def extract_foreign_key_action(specifier)
+ case specifier
+ when "CASCADE"; :cascade
+ when "SET NULL"; :nullify
+ when "RESTRICT"; :restrict
+ end
+ end
+
+ def configure_connection
+ execute("PRAGMA foreign_keys = ON", "SCHEMA")
+ end
end
end
end
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index 4d30bdf196..0028dc0edb 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -308,7 +308,7 @@ module ActiveRecord
relation = Relation.create(self, arel_table, predicate_builder)
if finder_needs_type_condition? && !ignore_default_scope?
- relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
+ relation.where(type_condition).create_with(inheritance_column.to_s => sti_name)
else
relation
end
diff --git a/activerecord/lib/active_record/counter_cache.rb b/activerecord/lib/active_record/counter_cache.rb
index 93b9371206..cbd71a3779 100644
--- a/activerecord/lib/active_record/counter_cache.rb
+++ b/activerecord/lib/active_record/counter_cache.rb
@@ -105,7 +105,8 @@ module ActiveRecord
end
if touch
- updates << sanitize_sql_for_assignment(touch_updates(touch))
+ touch_updates = touch_updates(touch)
+ updates << sanitize_sql_for_assignment(touch_updates) unless touch_updates.empty?
end
unscoped.where(primary_key => id).update_all updates.join(", ")
diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb
index 6e5f5fa2a7..40f6226315 100644
--- a/activerecord/lib/active_record/migration.rb
+++ b/activerecord/lib/active_record/migration.rb
@@ -525,7 +525,7 @@ module ActiveRecord
raise StandardError, "Directly inheriting from ActiveRecord::Migration is not supported. " \
"Please specify the Rails release the migration was written for:\n" \
"\n" \
- " class #{self.class.name} < ActiveRecord::Migration[4.2]"
+ " class #{subclass} < ActiveRecord::Migration[4.2]"
end
end
@@ -692,7 +692,7 @@ module ActiveRecord
connection.respond_to?(:reverting) && connection.reverting
end
- class ReversibleBlockHelper < Struct.new(:reverting) # :nodoc:
+ ReversibleBlockHelper = Struct.new(:reverting) do # :nodoc:
def up
yield unless reverting
end
@@ -938,7 +938,7 @@ module ActiveRecord
# MigrationProxy is used to defer loading of the actual migration classes
# until they are needed
- class MigrationProxy < Struct.new(:name, :version, :filename, :scope)
+ MigrationProxy = Struct.new(:name, :version, :filename, :scope) do
def initialize(name, version, filename, scope)
super
@migration = nil
@@ -1107,8 +1107,8 @@ module ActiveRecord
validate(@migrations)
- Base.connection.initialize_schema_migrations_table
- Base.connection.initialize_internal_metadata_table
+ ActiveRecord::SchemaMigration.create_table
+ ActiveRecord::InternalMetadata.create_table
end
def current_version
diff --git a/activerecord/lib/active_record/migration/compatibility.rb b/activerecord/lib/active_record/migration/compatibility.rb
index 2904634eb7..ffeca2c91e 100644
--- a/activerecord/lib/active_record/migration/compatibility.rb
+++ b/activerecord/lib/active_record/migration/compatibility.rb
@@ -16,7 +16,7 @@ module ActiveRecord
class V5_0 < V5_1
def create_table(table_name, options = {})
if adapter_name == "PostgreSQL"
- if options[:id] == :uuid && !options[:default]
+ if options[:id] == :uuid && !options.key?(:default)
options[:default] = "uuid_generate_v4()"
end
end
@@ -24,9 +24,8 @@ module ActiveRecord
# Since 5.1 Postgres adapter uses bigserial type for primary
# keys by default and MySQL uses bigint. This compat layer makes old migrations utilize
# serial/int type instead -- the way it used to work before 5.1.
- if options[:id].blank?
+ unless options.key?(:id)
options[:id] = :integer
- options[:auto_increment] = true
end
super
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index 19fe9632ca..7ceb7d1a55 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -148,6 +148,8 @@ module ActiveRecord
#
# Attributes marked as readonly are silently ignored if the record is
# being updated.
+ #
+ # Unless an error is raised, returns true.
def save!(*args)
create_or_update(*args) || raise(RecordNotSaved.new("Failed to save the record", self))
end
@@ -341,11 +343,13 @@ module ActiveRecord
# Wrapper around #increment that writes the update to the database.
# Only +attribute+ is updated; the record itself is not saved.
# This means that any other modified attributes will still be dirty.
- # Validations and callbacks are skipped. Returns +self+.
- def increment!(attribute, by = 1)
+ # Validations and callbacks are skipped. Supports the `touch` option from
+ # +update_counters+, see that for more.
+ # Returns +self+.
+ def increment!(attribute, by = 1, touch: nil)
increment(attribute, by)
change = public_send(attribute) - (attribute_in_database(attribute.to_s) || 0)
- self.class.update_counters(id, attribute => change)
+ self.class.update_counters(id, attribute => change, touch: touch)
clear_attribute_change(attribute) # eww
self
end
@@ -360,9 +364,11 @@ module ActiveRecord
# Wrapper around #decrement that writes the update to the database.
# Only +attribute+ is updated; the record itself is not saved.
# This means that any other modified attributes will still be dirty.
- # Validations and callbacks are skipped. Returns +self+.
- def decrement!(attribute, by = 1)
- increment!(attribute, -by)
+ # Validations and callbacks are skipped. Supports the `touch` option from
+ # +update_counters+, see that for more.
+ # Returns +self+.
+ def decrement!(attribute, by = 1, touch: nil)
+ increment!(attribute, -by, touch: touch)
end
# Assigns to +attribute+ the boolean opposite of <tt>attribute?</tt>. So
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 8af0d06ecb..81ec4924b0 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -1,5 +1,6 @@
require "thread"
require "active_support/core_ext/string/filters"
+require "active_support/deprecation"
module ActiveRecord
# = Active Record Reflection
@@ -175,8 +176,19 @@ module ActiveRecord
JoinKeys.new(foreign_key, active_record_primary_key)
end
+ # Returns a list of scopes that should be applied for this Reflection
+ # object when querying the database.
+ def scopes
+ scope ? [scope] : []
+ end
+
+ def scope_chain
+ chain.map(&:scopes)
+ end
+ deprecate :scope_chain
+
def constraints
- scope_chain.flatten
+ chain.map(&:scopes).flatten
end
def counter_cache_column
@@ -321,7 +333,7 @@ module ActiveRecord
end
end
- # Holds all the meta-data about an aggregation as it was specified in the
+ # Holds all the metadata about an aggregation as it was specified in the
# Active Record class.
class AggregateReflection < MacroReflection #:nodoc:
def mapping
@@ -330,7 +342,7 @@ module ActiveRecord
end
end
- # Holds all the meta-data about an association as it was specified in the
+ # Holds all the metadata about an association as it was specified in the
# Active Record class.
class AssociationReflection < MacroReflection #:nodoc:
# Returns the target association's class.
@@ -461,12 +473,6 @@ module ActiveRecord
false
end
- # An array of arrays of scopes. Each item in the outside array corresponds to a reflection
- # in the #chain.
- def scope_chain
- scope ? [[scope]] : [[]]
- end
-
def has_scope?
scope
end
@@ -709,7 +715,7 @@ module ActiveRecord
end
end
- # Holds all the meta-data about a :through association as it was specified
+ # Holds all the metadata about a :through association as it was specified
# in the Active Record class.
class ThroughReflection < AbstractReflection #:nodoc:
attr_reader :delegate_reflection
@@ -796,45 +802,12 @@ module ActiveRecord
through_reflection.clear_association_scope_cache
end
- # Consider the following example:
- #
- # class Person
- # has_many :articles
- # has_many :comment_tags, through: :articles
- # end
- #
- # class Article
- # has_many :comments
- # has_many :comment_tags, through: :comments, source: :tags
- # end
- #
- # class Comment
- # has_many :tags
- # end
- #
- # There may be scopes on Person.comment_tags, Article.comment_tags and/or Comment.tags,
- # but only Comment.tags will be represented in the #chain. So this method creates an array
- # of scopes corresponding to the chain.
- def scope_chain
- @scope_chain ||= begin
- scope_chain = source_reflection.scope_chain.map(&:dup)
-
- # Add to it the scope from this reflection (if any)
- scope_chain.first << scope if scope
-
- through_scope_chain = through_reflection.scope_chain.map(&:dup)
-
- if options[:source_type]
- type = foreign_type
- source_type = options[:source_type]
- through_scope_chain.first << lambda { |object|
- where(type => source_type)
- }
- end
+ def scopes
+ source_reflection.scopes + super
+ end
- # Recursively fill out the rest of the array from the through reflection
- scope_chain + through_scope_chain
- end
+ def source_type_scope
+ through_reflection.klass.where(foreign_type => options[:source_type])
end
def has_scope?
@@ -1008,6 +981,15 @@ module ActiveRecord
@previous_reflection = previous_reflection
end
+ def scopes
+ scopes = @previous_reflection.scopes
+ if @previous_reflection.options[:source_type]
+ scopes + [@previous_reflection.source_type_scope]
+ else
+ scopes
+ end
+ end
+
def klass
@reflection.klass
end
diff --git a/activerecord/lib/active_record/schema.rb b/activerecord/lib/active_record/schema.rb
index 7a2bc9c8af..5104427339 100644
--- a/activerecord/lib/active_record/schema.rb
+++ b/activerecord/lib/active_record/schema.rb
@@ -48,7 +48,7 @@ module ActiveRecord
instance_eval(&block)
if info[:version].present?
- initialize_schema_migrations_table
+ ActiveRecord::SchemaMigration.create_table
connection.assume_migrated_upto_version(info[:version], migrations_paths)
end
diff --git a/activerecord/lib/active_record/store.rb b/activerecord/lib/active_record/store.rb
index d4be20d999..006afe7495 100644
--- a/activerecord/lib/active_record/store.rb
+++ b/activerecord/lib/active_record/store.rb
@@ -78,7 +78,7 @@ module ActiveRecord
module ClassMethods
def store(store_attribute, options = {})
- serialize store_attribute, IndifferentCoder.new(options[:coder])
+ serialize store_attribute, IndifferentCoder.new(store_attribute, options[:coder])
store_accessor(store_attribute, options[:accessors]) if options.has_key? :accessors
end
@@ -177,12 +177,12 @@ module ActiveRecord
end
class IndifferentCoder # :nodoc:
- def initialize(coder_or_class_name)
+ def initialize(attr_name, coder_or_class_name)
@coder =
if coder_or_class_name.respond_to?(:load) && coder_or_class_name.respond_to?(:dump)
coder_or_class_name
else
- ActiveRecord::Coders::YAMLColumn.new(coder_or_class_name || Object)
+ ActiveRecord::Coders::YAMLColumn.new(attr_name, coder_or_class_name || Object)
end
end
diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb
index bdb5184599..82604a915f 100644
--- a/activerecord/lib/active_record/tasks/database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/database_tasks.rb
@@ -267,8 +267,8 @@ module ActiveRecord
if seed_loader
seed_loader.load_seed
else
- raise "You tried to load seed data, but no seed loader is specified. Please specify seed " +
- "loader with ActiveRecord::Tasks::DatabaseTasks.seed_loader = your_seed_loader\n" +
+ raise "You tried to load seed data, but no seed loader is specified. Please specify seed " \
+ "loader with ActiveRecord::Tasks::DatabaseTasks.seed_loader = your_seed_loader\n" \
"Seed loader should respond to load_seed method"
end
end
diff --git a/activerecord/lib/rails/generators/active_record/migration.rb b/activerecord/lib/rails/generators/active_record/migration.rb
index 4263c11ffc..43075077b9 100644
--- a/activerecord/lib/rails/generators/active_record/migration.rb
+++ b/activerecord/lib/rails/generators/active_record/migration.rb
@@ -20,6 +20,14 @@ module ActiveRecord
key_type = options[:primary_key_type]
", id: :#{key_type}" if key_type
end
+
+ def db_migrate_path
+ if defined?(Rails) && Rails.application
+ Rails.application.config.paths["db/migrate"].to_ary.first
+ else
+ "db/migrate"
+ end
+ end
end
end
end
diff --git a/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
index 8511531af7..1f1c47499b 100644
--- a/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
+++ b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
@@ -10,7 +10,7 @@ module ActiveRecord
def create_migration_file
set_local_assigns!
validate_file_name!
- migration_template @migration_template, "db/migrate/#{file_name}.rb"
+ migration_template @migration_template, File.join(db_migrate_path, "#{file_name}.rb")
end
# TODO Change this to private once we've dropped Ruby 2.2 support.
diff --git a/activerecord/lib/rails/generators/active_record/model/model_generator.rb b/activerecord/lib/rails/generators/active_record/model/model_generator.rb
index a9df5212e3..5cec07d2e3 100644
--- a/activerecord/lib/rails/generators/active_record/model/model_generator.rb
+++ b/activerecord/lib/rails/generators/active_record/model/model_generator.rb
@@ -17,7 +17,7 @@ module ActiveRecord
def create_migration_file
return unless options[:migration] && options[:parent].nil?
attributes.each { |a| a.attr_options.delete(:index) if a.reference? && !a.has_index? } if options[:indexes] == false
- migration_template "../../migration/templates/create_table_migration.rb", "db/migrate/create_#{table_name}.rb"
+ migration_template "../../migration/templates/create_table_migration.rb", File.join(db_migrate_path, "create_#{table_name}.rb")
end
def create_model_file
diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb
index 9828e682ef..a2b7d53205 100644
--- a/activerecord/test/cases/adapter_test.rb
+++ b/activerecord/test/cases/adapter_test.rb
@@ -31,7 +31,6 @@ module ActiveRecord
end
def test_tables
- tables = nil
tables = @connection.tables
assert_includes tables, "accounts"
assert_includes tables, "authors"
@@ -185,34 +184,6 @@ module ActiveRecord
end
unless current_adapter?(:SQLite3Adapter)
- def test_foreign_key_violations_are_translated_to_specific_exception
- error = assert_raises(ActiveRecord::InvalidForeignKey) do
- # Oracle adapter uses prefetched primary key values from sequence and passes them to connection adapter insert method
- if @connection.prefetch_primary_key?
- id_value = @connection.next_sequence_value(@connection.default_sequence_name("fk_test_has_fk", "id"))
- @connection.execute "INSERT INTO fk_test_has_fk (id, fk_id) VALUES (#{id_value},0)"
- else
- @connection.execute "INSERT INTO fk_test_has_fk (fk_id) VALUES (0)"
- end
- end
-
- assert_not_nil error.cause
- end
-
- def test_foreign_key_violations_are_translated_to_specific_exception_with_validate_false
- klass_has_fk = Class.new(ActiveRecord::Base) do
- self.table_name = "fk_test_has_fk"
- end
-
- error = assert_raises(ActiveRecord::InvalidForeignKey) do
- has_fk = klass_has_fk.new
- has_fk.fk_id = 1231231231
- has_fk.save(validate: false)
- end
-
- assert_not_nil error.cause
- end
-
def test_value_limit_violations_are_translated_to_specific_exception
error = assert_raises(ActiveRecord::ValueTooLong) do
Event.create(title: "abcdefgh")
@@ -230,23 +201,6 @@ module ActiveRecord
end
end
- def test_disable_referential_integrity
- assert_nothing_raised do
- @connection.disable_referential_integrity do
- # Oracle adapter uses prefetched primary key values from sequence and passes them to connection adapter insert method
- if @connection.prefetch_primary_key?
- id_value = @connection.next_sequence_value(@connection.default_sequence_name("fk_test_has_fk", "id"))
- @connection.execute "INSERT INTO fk_test_has_fk (id, fk_id) VALUES (#{id_value},0)"
- else
- @connection.execute "INSERT INTO fk_test_has_fk (fk_id) VALUES (0)"
- end
- # should delete created record as otherwise disable_referential_integrity will try to enable constraints after executed block
- # and will fail (at least on Oracle)
- @connection.execute "DELETE FROM fk_test_has_fk"
- end
- end
- end
-
def test_select_all_always_return_activerecord_result
result = @connection.select_all "SELECT * FROM posts"
assert result.is_a?(ActiveRecord::Result)
@@ -290,6 +244,59 @@ module ActiveRecord
end
end
+ class AdapterForeignKeyTest < ActiveRecord::TestCase
+ self.use_transactional_tests = false
+
+ def setup
+ @connection = ActiveRecord::Base.connection
+ end
+
+ def test_foreign_key_violations_are_translated_to_specific_exception_with_validate_false
+ klass_has_fk = Class.new(ActiveRecord::Base) do
+ self.table_name = "fk_test_has_fk"
+ end
+
+ error = assert_raises(ActiveRecord::InvalidForeignKey) do
+ has_fk = klass_has_fk.new
+ has_fk.fk_id = 1231231231
+ has_fk.save(validate: false)
+ end
+
+ assert_not_nil error.cause
+ end
+
+ def test_foreign_key_violations_are_translated_to_specific_exception
+ error = assert_raises(ActiveRecord::InvalidForeignKey) do
+ insert_into_fk_test_has_fk
+ end
+
+ assert_not_nil error.cause
+ end
+
+ def test_disable_referential_integrity
+ assert_nothing_raised do
+ @connection.disable_referential_integrity do
+ insert_into_fk_test_has_fk
+ # should delete created record as otherwise disable_referential_integrity will try to enable constraints
+ # after executed block and will fail (at least on Oracle)
+ @connection.execute "DELETE FROM fk_test_has_fk"
+ end
+ end
+ end
+
+ private
+
+ def insert_into_fk_test_has_fk
+ # Oracle adapter uses prefetched primary key values from sequence and passes them to connection adapter insert method
+ if @connection.prefetch_primary_key?
+ id_value = @connection.next_sequence_value(@connection.default_sequence_name("fk_test_has_fk", "id"))
+ @connection.execute "INSERT INTO fk_test_has_fk (id,fk_id) VALUES (#{id_value},0)"
+ else
+ @connection.execute "INSERT INTO fk_test_has_fk (fk_id) VALUES (0)"
+ end
+ end
+ end
+
class AdapterTestWithoutTransaction < ActiveRecord::TestCase
self.use_transactional_tests = false
diff --git a/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb b/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb
index fa54aac6b3..605baa9905 100644
--- a/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb
@@ -16,7 +16,7 @@ class SchemaMigrationsTest < ActiveRecord::Mysql2TestCase
table_name = ActiveRecord::SchemaMigration.table_name
connection.drop_table table_name, if_exists: true
- connection.initialize_schema_migrations_table
+ ActiveRecord::SchemaMigration.create_table
assert connection.column_exists?(table_name, :version, :string, collation: "utf8_general_ci")
end
@@ -27,7 +27,7 @@ class SchemaMigrationsTest < ActiveRecord::Mysql2TestCase
table_name = ActiveRecord::InternalMetadata.table_name
connection.drop_table table_name, if_exists: true
- connection.initialize_internal_metadata_table
+ ActiveRecord::InternalMetadata.create_table
assert connection.column_exists?(table_name, :key, :string, collation: "utf8_general_ci")
end
diff --git a/activerecord/test/cases/adapters/postgresql/connection_test.rb b/activerecord/test/cases/adapters/postgresql/connection_test.rb
index 075301d6d5..3cbd4ca212 100644
--- a/activerecord/test/cases/adapters/postgresql/connection_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/connection_test.rb
@@ -156,7 +156,7 @@ module ActiveRecord
secondary_connection.query("select pg_terminate_backend(#{original_connection_pid.first.first})")
ActiveRecord::Base.connection_pool.checkin(secondary_connection)
elsif ARTest.config["with_manual_interventions"]
- puts "Kill the connection now (e.g. by restarting the PostgreSQL " +
+ puts "Kill the connection now (e.g. by restarting the PostgreSQL " \
'server with the "-m fast" option) and then press enter.'
$stdin.gets
else
@@ -175,7 +175,7 @@ module ActiveRecord
new_connection_pid = @connection.query("select pg_backend_pid()")
assert_not_equal original_connection_pid, new_connection_pid,
- "umm -- looks like you didn't break the connection, because we're still " +
+ "umm -- looks like you didn't break the connection, because we're still " \
"successfully querying with the same connection pid."
# Repair all fixture connections so other tests won't break.
diff --git a/activerecord/test/cases/adapters/postgresql/infinity_test.rb b/activerecord/test/cases/adapters/postgresql/infinity_test.rb
index 19b00258b6..b9e177e6ec 100644
--- a/activerecord/test/cases/adapters/postgresql/infinity_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/infinity_test.rb
@@ -30,7 +30,7 @@ class PostgresqlInfinityTest < ActiveRecord::PostgreSQLTestCase
record = PostgresqlInfinity.new(float: "-Infinity")
assert_equal(-Float::INFINITY, record.float)
record = PostgresqlInfinity.new(float: "NaN")
- assert_send [record.float, :nan?]
+ assert record.float.nan?, "Expected #{record.float} to be NaN"
end
test "update_all with infinity on a float column" do
diff --git a/activerecord/test/cases/adapters/postgresql/numbers_test.rb b/activerecord/test/cases/adapters/postgresql/numbers_test.rb
index 834354dcc9..bfb2b7c27a 100644
--- a/activerecord/test/cases/adapters/postgresql/numbers_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/numbers_test.rb
@@ -31,7 +31,7 @@ class PostgresqlNumberTest < ActiveRecord::PostgreSQLTestCase
assert_equal 123456.789, first.double
assert_equal(-::Float::INFINITY, second.single)
assert_equal ::Float::INFINITY, second.double
- assert_send [third.double, :nan?]
+ assert third.double.nan?, "Expected #{third.double} to be NaN"
end
def test_update
diff --git a/activerecord/test/cases/adapters/postgresql/uuid_test.rb b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
index f34d50e25c..4655cd1d20 100644
--- a/activerecord/test/cases/adapters/postgresql/uuid_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
@@ -234,25 +234,23 @@ class PostgresqlUUIDGenerationTest < ActiveRecord::PostgreSQLTestCase
end
end
- if ActiveRecord::Base.connection.supports_pgcrypto_uuid?
- def test_schema_dumper_for_uuid_primary_key_default_in_legacy_migration
- @verbose_was = ActiveRecord::Migration.verbose
- ActiveRecord::Migration.verbose = false
-
- migration = Class.new(ActiveRecord::Migration[4.2]) do
- def version; 101 end
- def migrate(x)
- create_table("pg_uuids_4", id: :uuid)
- end
- end.new
- ActiveRecord::Migrator.new(:up, [migration]).migrate
-
- schema = dump_table_schema "pg_uuids_4"
- assert_match(/\bcreate_table "pg_uuids_4", id: :uuid, default: -> { "uuid_generate_v4\(\)" }/, schema)
- ensure
- drop_table "pg_uuids_4"
- ActiveRecord::Migration.verbose = @verbose_was
- end
+ def test_schema_dumper_for_uuid_primary_key_default_in_legacy_migration
+ @verbose_was = ActiveRecord::Migration.verbose
+ ActiveRecord::Migration.verbose = false
+
+ migration = Class.new(ActiveRecord::Migration[5.0]) do
+ def version; 101 end
+ def migrate(x)
+ create_table("pg_uuids_4", id: :uuid)
+ end
+ end.new
+ ActiveRecord::Migrator.new(:up, [migration]).migrate
+
+ schema = dump_table_schema "pg_uuids_4"
+ assert_match(/\bcreate_table "pg_uuids_4", id: :uuid, default: -> { "uuid_generate_v4\(\)" }/, schema)
+ ensure
+ drop_table "pg_uuids_4"
+ ActiveRecord::Migration.verbose = @verbose_was
end
end
end
@@ -285,6 +283,25 @@ class PostgresqlUUIDTestNilDefault < ActiveRecord::PostgreSQLTestCase
schema = dump_table_schema "pg_uuids"
assert_match(/\bcreate_table "pg_uuids", id: :uuid, default: nil/, schema)
end
+
+ def test_schema_dumper_for_uuid_primary_key_with_default_nil_in_legacy_migration
+ @verbose_was = ActiveRecord::Migration.verbose
+ ActiveRecord::Migration.verbose = false
+
+ migration = Class.new(ActiveRecord::Migration[5.0]) do
+ def version; 101 end
+ def migrate(x)
+ create_table("pg_uuids_4", id: :uuid, default: nil)
+ end
+ end.new
+ ActiveRecord::Migrator.new(:up, [migration]).migrate
+
+ schema = dump_table_schema "pg_uuids_4"
+ assert_match(/\bcreate_table "pg_uuids_4", id: :uuid, default: nil/, schema)
+ ensure
+ drop_table "pg_uuids_4"
+ ActiveRecord::Migration.verbose = @verbose_was
+ end
end
end
diff --git a/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb b/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb
index 91967c1e33..e1cfd703e8 100644
--- a/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb
@@ -41,8 +41,8 @@ class CopyTableTest < ActiveRecord::SQLite3TestCase
test_copy_table("comments", "comments_with_index") do
@connection.add_index("comments_with_index", ["post_id", "type"])
test_copy_table("comments_with_index", "comments_with_index2") do
- assert_equal table_indexes_without_name("comments_with_index"),
- table_indexes_without_name("comments_with_index2")
+ assert_nil table_indexes_without_name("comments_with_index")
+ assert_nil table_indexes_without_name("comments_with_index2")
end
end
end
@@ -59,7 +59,8 @@ class CopyTableTest < ActiveRecord::SQLite3TestCase
copied_id = @connection.columns("goofy_string_id2").detect { |col| col.name == "id" }
assert_equal original_id.type, copied_id.type
assert_equal original_id.sql_type, copied_id.sql_type
- assert_equal original_id.limit, copied_id.limit
+ assert_nil original_id.limit
+ assert_nil copied_id.limit
end
end
diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb
index ff1bf8acd4..11f4aae5b3 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -739,18 +739,25 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
def test_eager_with_invalid_association_reference
- assert_raise(ActiveRecord::AssociationNotFoundError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
+ e = assert_raise(ActiveRecord::AssociationNotFoundError) {
Post.all.merge!(includes: :monkeys).find(6)
}
- assert_raise(ActiveRecord::AssociationNotFoundError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
+ assert_equal("Association named 'monkeys' was not found on Post; perhaps you misspelled it?", e.message)
+
+ e = assert_raise(ActiveRecord::AssociationNotFoundError) {
Post.all.merge!(includes: [ :monkeys ]).find(6)
}
- assert_raise(ActiveRecord::AssociationNotFoundError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
+ assert_equal("Association named 'monkeys' was not found on Post; perhaps you misspelled it?", e.message)
+
+ e = assert_raise(ActiveRecord::AssociationNotFoundError) {
Post.all.merge!(includes: [ "monkeys" ]).find(6)
}
- assert_raise(ActiveRecord::AssociationNotFoundError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys, :elephants") {
+ assert_equal("Association named 'monkeys' was not found on Post; perhaps you misspelled it?", e.message)
+
+ e = assert_raise(ActiveRecord::AssociationNotFoundError) {
Post.all.merge!(includes: [ :monkeys, :elephants ]).find(6)
}
+ assert_equal("Association named 'monkeys' was not found on Post; perhaps you misspelled it?", e.message)
end
def test_eager_has_many_through_with_order
@@ -933,7 +940,11 @@ class EagerAssociationTest < ActiveRecord::TestCase
d2 = find_all_ordered(Firm, :account)
d1.each_index do |i|
assert_equal(d1[i], d2[i])
- assert_equal(d1[i].account, d2[i].account)
+ if d1[i].account.nil?
+ assert_nil(d2[i].account)
+ else
+ assert_equal(d1[i].account, d2[i].account)
+ end
end
end
@@ -943,7 +954,13 @@ class EagerAssociationTest < ActiveRecord::TestCase
d2 = find_all_ordered(Client, firm_types)
d1.each_index do |i|
assert_equal(d1[i], d2[i])
- firm_types.each { |type| assert_equal(d1[i].send(type), d2[i].send(type)) }
+ firm_types.each do |type|
+ if (expected = d1[i].send(type)).nil?
+ assert_nil(d2[i].send(type))
+ else
+ assert_equal(expected, d2[i].send(type))
+ end
+ end
end
end
def test_eager_with_valid_association_as_string_not_symbol
diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb
index aa910ba409..fc1e61124c 100644
--- a/activerecord/test/cases/associations/has_one_associations_test.rb
+++ b/activerecord/test/cases/associations/has_one_associations_test.rb
@@ -476,7 +476,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
assert_equal ships(:black_pearl), pirate.ship
assert_equal pirate.id, pirate.ship.pirate_id
- assert_equal "Failed to remove the existing associated ship. " +
+ assert_equal "Failed to remove the existing associated ship. " \
"The record failed to save after its foreign key was set to nil.", error.message
end
diff --git a/activerecord/test/cases/associations/inverse_associations_test.rb b/activerecord/test/cases/associations/inverse_associations_test.rb
index 6fe6ee6783..287b3e9ebc 100644
--- a/activerecord/test/cases/associations/inverse_associations_test.rb
+++ b/activerecord/test/cases/associations/inverse_associations_test.rb
@@ -443,7 +443,7 @@ class InverseHasManyTests < ActiveRecord::TestCase
assert man.equal?(man.interests.first.man), "Two inverses should lead back to the same object that was originally held"
assert man.equal?(man.interests.find(interest.id).man), "Two inversions should lead back to the same object that was originally held"
- assert_equal man.name, man.interests.find(interest.id).man.name, "The name of the man should match before the name is changed"
+ assert_nil man.interests.find(interest.id).man.name, "The name of the man should match before the name is changed"
man.name = "Ben Bitdiddle"
assert_equal man.name, man.interests.find(interest.id).man.name, "The name of the man should match after the parent name is changed"
man.interests.find(interest.id).man.name = "Alyssa P. Hacker"
diff --git a/activerecord/test/cases/attribute_methods/read_test.rb b/activerecord/test/cases/attribute_methods/read_test.rb
index 978dd93fa4..1fc63a49d4 100644
--- a/activerecord/test/cases/attribute_methods/read_test.rb
+++ b/activerecord/test/cases/attribute_methods/read_test.rb
@@ -3,7 +3,7 @@ require "cases/helper"
module ActiveRecord
module AttributeMethods
class ReadTest < ActiveRecord::TestCase
- class FakeColumn < Struct.new(:name)
+ FakeColumn = Struct.new(:name) do
def type; :integer; end
end
diff --git a/activerecord/test/cases/coders/yaml_column_test.rb b/activerecord/test/cases/coders/yaml_column_test.rb
index b9c6224425..1e0b4580af 100644
--- a/activerecord/test/cases/coders/yaml_column_test.rb
+++ b/activerecord/test/cases/coders/yaml_column_test.rb
@@ -5,46 +5,48 @@ module ActiveRecord
module Coders
class YAMLColumnTest < ActiveRecord::TestCase
def test_initialize_takes_class
- coder = YAMLColumn.new(Object)
+ coder = YAMLColumn.new("attr_name", Object)
assert_equal Object, coder.object_class
end
def test_type_mismatch_on_different_classes_on_dump
- coder = YAMLColumn.new(Array)
- assert_raises(SerializationTypeMismatch) do
+ coder = YAMLColumn.new("attr_name", Array)
+ error = assert_raises(SerializationTypeMismatch) do
coder.dump("a")
end
+ assert_equal %{Attribute `attr_name` was supposed to be a Array, but was a String. -- "a"}, error.to_s
end
def test_type_mismatch_on_different_classes
- coder = YAMLColumn.new(Array)
- assert_raises(SerializationTypeMismatch) do
+ coder = YAMLColumn.new("attr_name", Array)
+ error = assert_raises(SerializationTypeMismatch) do
coder.load "--- foo"
end
+ assert_equal %{Attribute `attr_name` was supposed to be a Array, but was a String. -- "foo"}, error.to_s
end
def test_nil_is_ok
- coder = YAMLColumn.new
+ coder = YAMLColumn.new("attr_name")
assert_nil coder.load "--- "
end
def test_returns_new_with_different_class
- coder = YAMLColumn.new SerializationTypeMismatch
+ coder = YAMLColumn.new("attr_name", SerializationTypeMismatch)
assert_equal SerializationTypeMismatch, coder.load("--- ").class
end
def test_returns_string_unless_starts_with_dash
- coder = YAMLColumn.new
+ coder = YAMLColumn.new("attr_name")
assert_equal "foo", coder.load("foo")
end
def test_load_handles_other_classes
- coder = YAMLColumn.new
+ coder = YAMLColumn.new("attr_name")
assert_equal [], coder.load([])
end
def test_load_doesnt_swallow_yaml_exceptions
- coder = YAMLColumn.new
+ coder = YAMLColumn.new("attr_name")
bad_yaml = "--- {"
assert_raises(Psych::SyntaxError) do
coder.load(bad_yaml)
@@ -52,7 +54,7 @@ module ActiveRecord
end
def test_load_doesnt_handle_undefined_class_or_module
- coder = YAMLColumn.new
+ coder = YAMLColumn.new("attr_name")
missing_class_yaml = '--- !ruby/object:DoesNotExistAndShouldntEver {}\n'
assert_raises(ArgumentError) do
coder.load(missing_class_yaml)
diff --git a/activerecord/test/cases/connection_adapters/connection_handler_test.rb b/activerecord/test/cases/connection_adapters/connection_handler_test.rb
index 2c33bf22ab..4f2392042b 100644
--- a/activerecord/test/cases/connection_adapters/connection_handler_test.rb
+++ b/activerecord/test/cases/connection_adapters/connection_handler_test.rb
@@ -89,6 +89,41 @@ module ActiveRecord
rd.close
end
+ def test_pool_from_any_process_for_uses_most_recent_spec
+ skip unless current_adapter?(:SQLite3Adapter)
+
+ file = Tempfile.new "lol.sqlite3"
+
+ rd, wr = IO.pipe
+ rd.binmode
+ wr.binmode
+
+ pid = fork do
+ ActiveRecord::Base.configurations["arunit"]["database"] = file.path
+ ActiveRecord::Base.establish_connection(:arunit)
+
+ pid2 = fork do
+ wr.write ActiveRecord::Base.connection_config[:database]
+ wr.close
+ end
+
+ Process.waitpid pid2
+ end
+
+ Process.waitpid pid
+
+ wr.close
+
+ assert_equal file.path, rd.read
+
+ rd.close
+ ensure
+ if file
+ file.close
+ file.unlink
+ end
+ end
+
def test_a_class_using_custom_pool_and_switching_back_to_primary
klass2 = Class.new(Base) { def self.name; "klass2"; end }
diff --git a/activerecord/test/cases/connection_pool_test.rb b/activerecord/test/cases/connection_pool_test.rb
index 81d7113bc6..9f7280634e 100644
--- a/activerecord/test/cases/connection_pool_test.rb
+++ b/activerecord/test/cases/connection_pool_test.rb
@@ -399,7 +399,7 @@ module ActiveRecord
all_threads_in_new_connection.wait
end
rescue Timeout::Error
- flunk "pool unable to establish connections concurrently or implementation has " <<
+ flunk "pool unable to establish connections concurrently or implementation has " \
"changed, this test then needs to patch a different :new_connection method"
ensure
# clean up the threads
diff --git a/activerecord/test/cases/counter_cache_test.rb b/activerecord/test/cases/counter_cache_test.rb
index c7d0ba32b4..46d7526cc0 100644
--- a/activerecord/test/cases/counter_cache_test.rb
+++ b/activerecord/test/cases/counter_cache_test.rb
@@ -221,6 +221,15 @@ class CounterCacheTest < ActiveRecord::TestCase
assert_equal previously_updated_at, @topic.updated_at
end
+ test "update counters doesn't touch timestamps with touch: []" do
+ @topic.update_column :updated_at, 5.minutes.ago
+ previously_updated_at = @topic.updated_at
+
+ Topic.update_counters(@topic.id, replies_count: -1, touch: [])
+
+ assert_equal previously_updated_at, @topic.updated_at
+ end
+
test "update counters with touch: true" do
assert_touching @topic, :updated_at do
Topic.update_counters(@topic.id, replies_count: -1, touch: true)
diff --git a/activerecord/test/cases/date_time_precision_test.rb b/activerecord/test/cases/date_time_precision_test.rb
index a1c3c5af9c..e4a2f9ee17 100644
--- a/activerecord/test/cases/date_time_precision_test.rb
+++ b/activerecord/test/cases/date_time_precision_test.rb
@@ -73,7 +73,7 @@ if subsecond_precision_supported?
assert_match %r{t\.datetime\s+"updated_at",\s+precision: 6,\s+null: false$}, output
end
- if current_adapter?(:PostgreSQLAdapter)
+ if current_adapter?(:PostgreSQLAdapter, :SQLServerAdapter)
def test_datetime_precision_with_zero_should_be_dumped
@connection.create_table(:foos, force: true) do |t|
t.timestamps precision: 0
diff --git a/activerecord/test/cases/migration/compatibility_test.rb b/activerecord/test/cases/migration/compatibility_test.rb
index e5a7412bc3..9296f3da90 100644
--- a/activerecord/test/cases/migration/compatibility_test.rb
+++ b/activerecord/test/cases/migration/compatibility_test.rb
@@ -103,9 +103,10 @@ module ActiveRecord
end
def test_legacy_migrations_raises_exception_when_inherited
- assert_raises(StandardError) do
- Class.new(ActiveRecord::Migration)
+ e = assert_raises(StandardError) do
+ class_eval("class LegacyMigration < ActiveRecord::Migration; end")
end
+ assert_match(/LegacyMigration < ActiveRecord::Migration\[4\.2\]/, e.message)
end
end
end
diff --git a/activerecord/test/cases/migration/foreign_key_test.rb b/activerecord/test/cases/migration/foreign_key_test.rb
index 9be6667aa1..96e775a58b 100644
--- a/activerecord/test/cases/migration/foreign_key_test.rb
+++ b/activerecord/test/cases/migration/foreign_key_test.rb
@@ -2,6 +2,26 @@ require "cases/helper"
require "support/ddl_helper"
require "support/schema_dumping_helper"
+if ActiveRecord::Base.connection.supports_foreign_keys_in_create?
+ module ActiveRecord
+ class Migration
+ class ForeignKeyInCreateTest < ActiveRecord::TestCase
+ def test_foreign_keys
+ foreign_keys = ActiveRecord::Base.connection.foreign_keys("fk_test_has_fk")
+ assert_equal 1, foreign_keys.size
+
+ fk = foreign_keys.first
+ assert_equal "fk_test_has_fk", fk.from_table
+ assert_equal "fk_test_has_pk", fk.to_table
+ assert_equal "fk_id", fk.column
+ assert_equal "pk_id", fk.primary_key
+ assert_equal "fk_name", fk.name unless current_adapter?(:SQLite3Adapter)
+ end
+ end
+ end
+ end
+end
+
if ActiveRecord::Base.connection.supports_foreign_keys?
module ActiveRecord
class Migration
@@ -29,10 +49,8 @@ if ActiveRecord::Base.connection.supports_foreign_keys?
end
teardown do
- if defined?(@connection)
- @connection.drop_table "astronauts", if_exists: true
- @connection.drop_table "rockets", if_exists: true
- end
+ @connection.drop_table "astronauts", if_exists: true
+ @connection.drop_table "rockets", if_exists: true
end
def test_foreign_keys
@@ -305,9 +323,11 @@ else
@connection.remove_foreign_key :clubs, :categories
end
- def test_foreign_keys_should_raise_not_implemented
- assert_raises NotImplementedError do
- @connection.foreign_keys("clubs")
+ unless current_adapter?(:SQLite3Adapter)
+ def test_foreign_keys_should_raise_not_implemented
+ assert_raises NotImplementedError do
+ @connection.foreign_keys("clubs")
+ end
end
end
end
diff --git a/activerecord/test/cases/migration/references_foreign_key_test.rb b/activerecord/test/cases/migration/references_foreign_key_test.rb
index 4957ab8b3d..560adcbfed 100644
--- a/activerecord/test/cases/migration/references_foreign_key_test.rb
+++ b/activerecord/test/cases/migration/references_foreign_key_test.rb
@@ -1,9 +1,9 @@
require "cases/helper"
-if ActiveRecord::Base.connection.supports_foreign_keys?
+if ActiveRecord::Base.connection.supports_foreign_keys_in_create?
module ActiveRecord
class Migration
- class ReferencesForeignKeyTest < ActiveRecord::TestCase
+ class ReferencesForeignKeyInCreateTest < ActiveRecord::TestCase
setup do
@connection = ActiveRecord::Base.connection
@connection.create_table(:testing_parents, force: true)
@@ -61,6 +61,24 @@ if ActiveRecord::Base.connection.supports_foreign_keys?
assert_equal([["testings", "testing_parents", "parent_id"]],
fks.map { |fk| [fk.from_table, fk.to_table, fk.column] })
end
+ end
+ end
+ end
+end
+
+if ActiveRecord::Base.connection.supports_foreign_keys?
+ module ActiveRecord
+ class Migration
+ class ReferencesForeignKeyTest < ActiveRecord::TestCase
+ setup do
+ @connection = ActiveRecord::Base.connection
+ @connection.create_table(:testing_parents, force: true)
+ end
+
+ teardown do
+ @connection.drop_table "testings", if_exists: true
+ @connection.drop_table "testing_parents", if_exists: true
+ end
test "foreign keys cannot be added to polymorphic relations when creating the table" do
@connection.create_table :testings do |t|
diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
index 4edb807bbb..2fda4d60b8 100644
--- a/activerecord/test/cases/migration_test.rb
+++ b/activerecord/test/cases/migration_test.rb
@@ -43,10 +43,10 @@ class MigrationTest < ActiveRecord::TestCase
ActiveRecord::Base.table_name_prefix = ""
ActiveRecord::Base.table_name_suffix = ""
- ActiveRecord::Base.connection.initialize_schema_migrations_table
- ActiveRecord::Base.connection.execute "DELETE FROM #{ActiveRecord::Migrator.schema_migrations_table_name}"
+ ActiveRecord::SchemaMigration.create_table
+ ActiveRecord::SchemaMigration.delete_all
- %w(things awesome_things prefix_things_suffix p_awesome_things_s ).each do |table|
+ %w(things awesome_things prefix_things_suffix p_awesome_things_s).each do |table|
Thing.connection.drop_table(table) rescue nil
end
Thing.reset_column_information
@@ -916,7 +916,6 @@ if ActiveRecord::Base.connection.supports_bulk_alter?
@indexes ||= Person.connection.indexes("delete_me")
end
end # AlterTableMigrationsTest
-
end
class CopyMigrationsTest < ActiveRecord::TestCase
@@ -1134,4 +1133,9 @@ class CopyMigrationsTest < ActiveRecord::TestCase
def test_unknown_migration_version_should_raise_an_argument_error
assert_raise(ArgumentError) { ActiveRecord::Migration[1.0] }
end
+
+ def test_deprecate_initialize_internal_tables
+ assert_deprecated { ActiveRecord::Base.connection.initialize_schema_migrations_table }
+ assert_deprecated { ActiveRecord::Base.connection.initialize_internal_metadata_table }
+ end
end
diff --git a/activerecord/test/cases/migrator_test.rb b/activerecord/test/cases/migrator_test.rb
index 224e8d1854..20d70b75ac 100644
--- a/activerecord/test/cases/migrator_test.rb
+++ b/activerecord/test/cases/migrator_test.rb
@@ -45,10 +45,11 @@ class MigratorTest < ActiveRecord::TestCase
end
def test_migrator_with_duplicate_names
- assert_raises(ActiveRecord::DuplicateMigrationNameError, "Multiple migrations have the name Chunky") do
+ e = assert_raises(ActiveRecord::DuplicateMigrationNameError) do
list = [ActiveRecord::Migration.new("Chunky"), ActiveRecord::Migration.new("Chunky")]
ActiveRecord::Migrator.new(:up, list)
end
+ assert_match(/Multiple migrations have the name Chunky/, e.message)
end
def test_migrator_with_duplicate_versions
diff --git a/activerecord/test/cases/nested_attributes_with_callbacks_test.rb b/activerecord/test/cases/nested_attributes_with_callbacks_test.rb
index 350a966d40..b9d2acbed2 100644
--- a/activerecord/test/cases/nested_attributes_with_callbacks_test.rb
+++ b/activerecord/test/cases/nested_attributes_with_callbacks_test.rb
@@ -120,14 +120,14 @@ class NestedAttributesWithCallbacksTest < ActiveRecord::TestCase
assert_assignment_affects_records_in_target(:birds_with_add)
end
- test("Assignment updates records in target when not loaded" +
+ test("Assignment updates records in target when not loaded" \
" and callback loads target") do
assert_not @pirate.birds_with_add_load.loaded?
@pirate.birds_with_add_load_attributes = update_new_and_destroy_bird_attributes
assert_assignment_affects_records_in_target(:birds_with_add_load)
end
- test("Assignment updates records in target when loaded" +
+ test("Assignment updates records in target when loaded" \
" and callback loads target") do
@pirate.birds_with_add_load.load_target
@pirate.birds_with_add_load_attributes = update_new_and_destroy_bird_attributes
diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb
index 3f1da82cb4..5b7e2fd008 100644
--- a/activerecord/test/cases/persistence_test.rb
+++ b/activerecord/test/cases/persistence_test.rb
@@ -139,6 +139,14 @@ class PersistenceTest < ActiveRecord::TestCase
assert_equal initial_credit + 2, a1.reload.credit_limit
end
+ def test_increment_updates_timestamps
+ topic = topics(:first)
+ topic.update_columns(updated_at: 5.minutes.ago)
+ previous_updated_at = topic.updated_at
+ topic.increment!(:replies_count, touch: true)
+ assert_operator previous_updated_at, :<, topic.reload.updated_at
+ end
+
def test_destroy_all
conditions = "author_name = 'Mary'"
topics_by_mary = Topic.all.merge!(where: conditions, order: "id").to_a
@@ -230,6 +238,14 @@ class PersistenceTest < ActiveRecord::TestCase
assert_equal 41, accounts(:signals37, :reload).credit_limit
end
+ def test_decrement_updates_timestamps
+ topic = topics(:first)
+ topic.update_columns(updated_at: 5.minutes.ago)
+ previous_updated_at = topic.updated_at
+ topic.decrement!(:replies_count, touch: true)
+ assert_operator previous_updated_at, :<, topic.reload.updated_at
+ end
+
def test_create
topic = Topic.new
topic.title = "New Topic"
diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb
index 93a67d0738..04e48e201e 100644
--- a/activerecord/test/cases/query_cache_test.rb
+++ b/activerecord/test/cases/query_cache_test.rb
@@ -442,6 +442,10 @@ end
class QueryCacheExpiryTest < ActiveRecord::TestCase
fixtures :tasks, :posts, :categories, :categories_posts
+ def teardown
+ Task.connection.clear_query_cache
+ end
+
def test_cache_gets_cleared_after_migration
# warm the cache
Post.find(1)
diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb
index 2444eccab1..04ee67c177 100644
--- a/activerecord/test/cases/reflection_test.rb
+++ b/activerecord/test/cases/reflection_test.rb
@@ -258,7 +258,9 @@ class ReflectionTest < ActiveRecord::TestCase
[Post.reflect_on_association(:first_taggings).scope],
[Author.reflect_on_association(:misc_posts).scope]
]
- actual = Author.reflect_on_association(:misc_post_first_blue_tags).scope_chain
+ actual = assert_deprecated do
+ Author.reflect_on_association(:misc_post_first_blue_tags).scope_chain
+ end
assert_equal expected, actual
expected = [
@@ -270,7 +272,9 @@ class ReflectionTest < ActiveRecord::TestCase
[],
[]
]
- actual = Author.reflect_on_association(:misc_post_first_blue_tags_2).scope_chain
+ actual = assert_deprecated do
+ Author.reflect_on_association(:misc_post_first_blue_tags_2).scope_chain
+ end
assert_equal expected, actual
end
@@ -395,9 +399,15 @@ class ReflectionTest < ActiveRecord::TestCase
end
def test_through_reflection_scope_chain_does_not_modify_other_reflections
- orig_conds = Post.reflect_on_association(:first_blue_tags_2).scope_chain.inspect
- Author.reflect_on_association(:misc_post_first_blue_tags_2).scope_chain
- assert_equal orig_conds, Post.reflect_on_association(:first_blue_tags_2).scope_chain.inspect
+ orig_conds = assert_deprecated do
+ Post.reflect_on_association(:first_blue_tags_2).scope_chain
+ end.inspect
+ assert_deprecated do
+ Author.reflect_on_association(:misc_post_first_blue_tags_2).scope_chain
+ end
+ assert_equal orig_conds, assert_deprecated {
+ Post.reflect_on_association(:first_blue_tags_2).scope_chain
+ }.inspect
end
def test_symbol_for_class_name
diff --git a/activerecord/test/cases/relation/mutation_test.rb b/activerecord/test/cases/relation/mutation_test.rb
index de15eb9187..4f92f71a09 100644
--- a/activerecord/test/cases/relation/mutation_test.rb
+++ b/activerecord/test/cases/relation/mutation_test.rb
@@ -3,7 +3,7 @@ require "models/post"
module ActiveRecord
class RelationMutationTest < ActiveRecord::TestCase
- class FakeKlass < Struct.new(:table_name, :name)
+ FakeKlass = Struct.new(:table_name, :name) do
extend ActiveRecord::Delegation::DelegateCache
inherited self
diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb
index d5af0cc9a5..1241bb54a4 100644
--- a/activerecord/test/cases/relation_test.rb
+++ b/activerecord/test/cases/relation_test.rb
@@ -8,7 +8,7 @@ module ActiveRecord
class RelationTest < ActiveRecord::TestCase
fixtures :posts, :comments, :authors
- class FakeKlass < Struct.new(:table_name, :name)
+ FakeKlass = Struct.new(:table_name, :name) do
extend ActiveRecord::Delegation::DelegateCache
inherited self
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index bea78d2a95..34c5f356b8 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -343,7 +343,7 @@ class SchemaDumperTest < ActiveRecord::TestCase
t.column :name, :string
t.column :owner_id, :bigint
t.index [:name]
- t.foreign_key :dog_owners, column: "owner_id" if supports_foreign_keys?
+ t.foreign_key :dog_owners, column: "owner_id"
end
end
def down
diff --git a/activerecord/test/cases/serialized_attribute_test.rb b/activerecord/test/cases/serialized_attribute_test.rb
index a469da0a5b..24b83691f6 100644
--- a/activerecord/test/cases/serialized_attribute_test.rb
+++ b/activerecord/test/cases/serialized_attribute_test.rb
@@ -240,6 +240,20 @@ class SerializedAttributeTest < ActiveRecord::TestCase
assert_equal [], light.long_state
end
+ def test_unexpected_serialized_type
+ Topic.serialize :content, Hash
+ topic = Topic.create!(content: { zomg: true })
+
+ Topic.serialize :content, Array
+
+ topic.reload
+ error = assert_raise(ActiveRecord::SerializationTypeMismatch) do
+ topic.content
+ end
+ expected = "Attribute `content` was supposed to be a Array, but was a Hash. -- {:zomg=>true}"
+ assert_equal expected, error.to_s
+ end
+
def test_serialized_column_should_unserialize_after_update_column
t = Topic.create(content: "first")
assert_equal("first", t.content)
diff --git a/activerecord/test/cases/time_precision_test.rb b/activerecord/test/cases/time_precision_test.rb
index 03f6c234e8..09c585167e 100644
--- a/activerecord/test/cases/time_precision_test.rb
+++ b/activerecord/test/cases/time_precision_test.rb
@@ -68,7 +68,7 @@ if subsecond_precision_supported?
assert_match %r{t\.time\s+"finish",\s+precision: 6$}, output
end
- if current_adapter?(:PostgreSQLAdapter)
+ if current_adapter?(:PostgreSQLAdapter, :SQLServerAdapter)
def test_time_precision_with_zero_should_be_dumped
@connection.create_table(:foos, force: true) do |t|
t.time :start, precision: 0
diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb
index 9b1cca8583..8f9980f168 100644
--- a/activerecord/test/cases/transactions_test.rb
+++ b/activerecord/test/cases/transactions_test.rb
@@ -279,7 +279,11 @@ class TransactionTest < ActiveRecord::TestCase
e = assert_raises(RuntimeError) { new_topic.save }
assert_equal "Make the transaction rollback", e.message
assert_equal new_record_snapshot, !new_topic.persisted?, "The topic should have its old persisted value"
- assert_equal id_snapshot, new_topic.id, "The topic should have its old id"
+ if id_snapshot.nil?
+ assert_nil new_topic.id, "The topic should have its old id"
+ else
+ assert_equal id_snapshot, new_topic.id, "The topic should have its old id"
+ end
assert_equal id_present, new_topic.has_attribute?(Topic.primary_key)
end
end
diff --git a/activerecord/test/cases/view_test.rb b/activerecord/test/cases/view_test.rb
index d055968a56..07288568e8 100644
--- a/activerecord/test/cases/view_test.rb
+++ b/activerecord/test/cases/view_test.rb
@@ -154,7 +154,7 @@ if ActiveRecord::Base.connection.supports_views?
end
# sqlite dose not support CREATE, INSERT, and DELETE for VIEW
- if current_adapter?(:Mysql2Adapter, :PostgreSQLAdapter)
+ if current_adapter?(:Mysql2Adapter, :PostgreSQLAdapter, :SQLServerAdapter)
class UpdateableViewTest < ActiveRecord::TestCase
self.use_transactional_tests = false
fixtures :books
@@ -200,7 +200,7 @@ if ActiveRecord::Base.connection.supports_views?
end
end
end
- end # end of `if current_adapter?(:Mysql2Adapter, :PostgreSQLAdapter)`
+ end # end of `if current_adapter?(:Mysql2Adapter, :PostgreSQLAdapter, :SQLServerAdapter)`
end # end of `if ActiveRecord::Base.connection.supports_views?`
if ActiveRecord::Base.connection.respond_to?(:supports_materialized_views?) &&
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index ba6f5de894..b38b9661b3 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -1005,16 +1005,14 @@ ActiveRecord::Schema.define do
create_table :records, force: true do |t|
end
- if supports_foreign_keys?
- # fk_test_has_fk should be before fk_test_has_pk
- create_table :fk_test_has_fk, force: true do |t|
- t.bigint :fk_id, null: false
+ disable_referential_integrity do
+ create_table :fk_test_has_pk, primary_key: "pk_id", force: :cascade do |t|
end
- create_table :fk_test_has_pk, force: true, primary_key: "pk_id" do |t|
+ create_table :fk_test_has_fk, force: true do |t|
+ t.references :fk, null: false
+ t.foreign_key :fk_test_has_pk, column: "fk_id", name: "fk_name", primary_key: "pk_id"
end
-
- add_foreign_key :fk_test_has_fk, :fk_test_has_pk, column: "fk_id", name: "fk_name", primary_key: "pk_id"
end
create_table :overloaded_types, force: true do |t|
diff --git a/activerecord/test/schema/sqlite_specific_schema.rb b/activerecord/test/schema/sqlite_specific_schema.rb
deleted file mode 100644
index cc7c36fe2b..0000000000
--- a/activerecord/test/schema/sqlite_specific_schema.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-ActiveRecord::Schema.define do
- execute "DROP TABLE fk_test_has_fk" rescue nil
- execute "DROP TABLE fk_test_has_pk" rescue nil
- execute <<_SQL
- CREATE TABLE 'fk_test_has_pk' (
- 'pk_id' INTEGER NOT NULL PRIMARY KEY
- );
-_SQL
-
- execute <<_SQL
- CREATE TABLE 'fk_test_has_fk' (
- 'id' INTEGER NOT NULL PRIMARY KEY,
- 'fk_id' INTEGER NOT NULL,
-
- FOREIGN KEY ('fk_id') REFERENCES 'fk_test_has_pk'('pk_id')
- );
-_SQL
-end
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 873a39dbf6..5af97e3d37 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,3 +1,54 @@
+* Updated Unicode version to 9.0.0
+
+ Now we can handle new emojis such like "👩‍👩‍👧‍👦" ("\u{1F469}\u{200D}\u{1F469}\u{200D}\u{1F467}\u{200D}\u{1F466}").
+
+ version 8.0.0
+
+ "👩‍👩‍👧‍👦".mb_chars.grapheme_length # => 4
+ "👩‍👩‍👧‍👦".mb_chars.reverse # => "👦👧‍👩‍👩‍"
+
+ version 9.0.0
+
+ "👩‍👩‍👧‍👦".mb_chars.grapheme_length # => 1
+ "👩‍👩‍👧‍👦".mb_chars.reverse # => "👩‍👩‍👧‍👦"
+
+ *Fumiaki MATSUSHIMA*
+
+* Changed `ActiveSupport::Inflector#transliterate` to raise `ArgumentError` when it receives
+ anything except a string.
+
+ *Kevin McPhillips*
+
+* Fixed bugs that `StringInquirer#respond_to_missing?` and
+ `ArrayInquirer#respond_to_missing?` do not fallback to `super`.
+
+ *Akira Matsuda*
+
+* Fix inconsistent results when parsing large durations and constructing durations from code
+
+ ActiveSupport::Duration.parse('P3Y') == 3.years # It should be true
+
+ Duration parsing made independent from any moment of time:
+ Fixed length in seconds is assigned to each duration part during parsing.
+
+ Changed duration of months and years in seconds to more accurate and logical:
+
+ 1. The value of 365.2425 days in Gregorian year is more accurate
+ as it accounts for every 400th non-leap year.
+
+ 2. Month's length is bound to year's duration, which makes
+ sensible comparisons like `12.months == 1.year` to be `true`
+ and nonsensical ones like `30.days == 1.month` to be `false`.
+
+ Calculations on times and dates with durations shouldn't be affected as
+ duration's numeric value isn't used in calculations, only parts are used.
+
+ Methods on `Numeric` like `2.days` now use these predefined durations
+ to avoid duplicating of duration constants through the codebase and
+ eliminate creation of intermediate durations.
+
+ *Andrey Novikov, Andrew White*
+
* Change return value of `Rational#duplicable?`, `ComplexClass#duplicable?`
to false.
diff --git a/activesupport/bin/generate_tables b/activesupport/bin/generate_tables
index 5d912f375c..aa36a01b5b 100755
--- a/activesupport/bin/generate_tables
+++ b/activesupport/bin/generate_tables
@@ -8,6 +8,7 @@ end
require "open-uri"
require "tmpdir"
+require "fileutils"
module ActiveSupport
module Multibyte
@@ -101,9 +102,10 @@ module ActiveSupport
def parse
SOURCES.each do |type, url|
- filename = File.join(Dir.tmpdir, "#{url.split('/').last}")
+ filename = File.join(Dir.tmpdir, UNICODE_VERSION, "#{url.split('/').last}")
unless File.exist?(filename)
$stderr.puts "Downloading #{url.split('/').last}"
+ FileUtils.mkdir_p(File.dirname(filename))
File.open(filename, "wb") do |target|
open(url) do |source|
source.each_line { |line| target.write line }
diff --git a/activesupport/lib/active_support/array_inquirer.rb b/activesupport/lib/active_support/array_inquirer.rb
index 85122e39b2..befa1746c6 100644
--- a/activesupport/lib/active_support/array_inquirer.rb
+++ b/activesupport/lib/active_support/array_inquirer.rb
@@ -20,7 +20,7 @@ module ActiveSupport
# variants.any?(:phone, :tablet) # => true
# variants.any?('phone', 'desktop') # => true
# variants.any?(:desktop, :watch) # => false
- def any?(*candidates, &block)
+ def any?(*candidates)
if candidates.none?
super
else
@@ -32,7 +32,7 @@ module ActiveSupport
private
def respond_to_missing?(name, include_private = false)
- name[-1] == "?"
+ (name[-1] == "?") || super
end
def method_missing(name, *args)
diff --git a/activesupport/lib/active_support/backtrace_cleaner.rb b/activesupport/lib/active_support/backtrace_cleaner.rb
index 169a58ecd1..e47c90597f 100644
--- a/activesupport/lib/active_support/backtrace_cleaner.rb
+++ b/activesupport/lib/active_support/backtrace_cleaner.rb
@@ -12,7 +12,7 @@ module ActiveSupport
# is to exclude the output of a noisy library from the backtrace, so that you
# can focus on the rest.
#
- # bc = BacktraceCleaner.new
+ # bc = ActiveSupport::BacktraceCleaner.new
# bc.add_filter { |line| line.gsub(Rails.root.to_s, '') } # strip the Rails.root prefix
# bc.add_silencer { |line| line =~ /puma|rubygems/ } # skip any lines from puma or rubygems
# bc.clean(exception.backtrace) # perform the cleanup
diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb
index d1bbd2f405..4ff47c261d 100644
--- a/activesupport/lib/active_support/cache.rb
+++ b/activesupport/lib/active_support/cache.rb
@@ -71,8 +71,8 @@ module ActiveSupport
# each of elements in the array will be turned into parameters/keys and
# concatenated into a single key. For example:
#
- # expand_cache_key([:foo, :bar]) # => "foo/bar"
- # expand_cache_key([:foo, :bar], "namespace") # => "namespace/foo/bar"
+ # ActiveSupport::Cache.expand_cache_key([:foo, :bar]) # => "foo/bar"
+ # ActiveSupport::Cache.expand_cache_key([:foo, :bar], "namespace") # => "namespace/foo/bar"
#
# The +key+ argument can also respond to +cache_key+ or +to_param+.
def expand_cache_key(key, namespace = nil)
diff --git a/activesupport/lib/active_support/core_ext/array/access.rb b/activesupport/lib/active_support/core_ext/array/access.rb
index 37d833887a..fca33c9d69 100644
--- a/activesupport/lib/active_support/core_ext/array/access.rb
+++ b/activesupport/lib/active_support/core_ext/array/access.rb
@@ -31,7 +31,7 @@ class Array
#
# people = ["David", "Rafael", "Aaron", "Todd"]
# people.without "Aaron", "Todd"
- # => ["David", "Rafael"]
+ # # => ["David", "Rafael"]
#
# Note: This is an optimization of `Enumerable#without` that uses `Array#-`
# instead of `Array#reject` for performance reasons.
diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb
index ae08fd90c1..90d7d2947f 100644
--- a/activesupport/lib/active_support/core_ext/enumerable.rb
+++ b/activesupport/lib/active_support/core_ext/enumerable.rb
@@ -12,7 +12,7 @@ module Enumerable
#
# [5, 15, 10].sum # => 30
# ['foo', 'bar'].sum # => "foobar"
- # [[1, 2], [3, 1, 5]].sum => [1, 2, 3, 1, 5]
+ # [[1, 2], [3, 1, 5]].sum # => [1, 2, 3, 1, 5]
#
# The default sum of an empty list is zero. You can override this default:
#
@@ -29,9 +29,9 @@ module Enumerable
# Convert an enumerable to a hash.
#
# people.index_by(&:login)
- # => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
+ # # => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
# people.index_by { |person| "#{person.first_name} #{person.last_name}" }
- # => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}
+ # # => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}
def index_by
if block_given?
result = {}
@@ -67,10 +67,10 @@ module Enumerable
# Returns a copy of the enumerable without the specified elements.
#
# ["David", "Rafael", "Aaron", "Todd"].without "Aaron", "Todd"
- # => ["David", "Rafael"]
+ # # => ["David", "Rafael"]
#
# {foo: 1, bar: 2, baz: 3}.without :bar
- # => {foo: 1, baz: 3}
+ # # => {foo: 1, baz: 3}
def without(*elements)
reject { |element| elements.include?(element) }
end
@@ -78,10 +78,10 @@ module Enumerable
# Convert an enumerable to an array based on the given key.
#
# [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name)
- # => ["David", "Rafael", "Aaron"]
+ # # => ["David", "Rafael", "Aaron"]
#
# [{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pluck(:id, :name)
- # => [[1, "David"], [2, "Rafael"]]
+ # # => [[1, "David"], [2, "Rafael"]]
def pluck(*keys)
if keys.many?
map { |element| keys.map { |key| element[key] } }
diff --git a/activesupport/lib/active_support/core_ext/integer/time.rb b/activesupport/lib/active_support/core_ext/integer/time.rb
index 4a64872392..74baae3639 100644
--- a/activesupport/lib/active_support/core_ext/integer/time.rb
+++ b/activesupport/lib/active_support/core_ext/integer/time.rb
@@ -18,12 +18,12 @@ class Integer
# # equivalent to Time.now.advance(months: 4, years: 5)
# (4.months + 5.years).from_now
def months
- ActiveSupport::Duration.new(self * 30.days, [[:months, self]])
+ ActiveSupport::Duration.months(self)
end
alias :month :months
def years
- ActiveSupport::Duration.new(self * 365.25.days.to_i, [[:years, self]])
+ ActiveSupport::Duration.years(self)
end
alias :year :years
end
diff --git a/activesupport/lib/active_support/core_ext/load_error.rb b/activesupport/lib/active_support/core_ext/load_error.rb
index 029d6dd449..d273487010 100644
--- a/activesupport/lib/active_support/core_ext/load_error.rb
+++ b/activesupport/lib/active_support/core_ext/load_error.rb
@@ -6,18 +6,6 @@ class LoadError
/^cannot load such file -- (.+)$/i,
]
- unless method_defined?(:path)
- # Returns the path which was unable to be loaded.
- def path
- @path ||= begin
- REGEXPS.find do |regex|
- message =~ regex
- end
- $1
- end
- end
- end
-
# Returns true if the given path name (except perhaps for the ".rb"
# extension) is the missing file which caused the exception to be raised.
def is_missing?(location)
diff --git a/activesupport/lib/active_support/core_ext/module/introspection.rb b/activesupport/lib/active_support/core_ext/module/introspection.rb
index 0665aa88bc..ca20a6d4c5 100644
--- a/activesupport/lib/active_support/core_ext/module/introspection.rb
+++ b/activesupport/lib/active_support/core_ext/module/introspection.rb
@@ -5,10 +5,12 @@ class Module
#
# M::N.parent_name # => "M"
def parent_name
- if defined? @parent_name
+ if defined?(@parent_name)
@parent_name
else
- @parent_name = name =~ /::[^:]+\Z/ ? $`.freeze : nil
+ parent_name = name =~ /::[^:]+\Z/ ? $`.freeze : nil
+ @parent_name = parent_name unless frozen?
+ parent_name
end
end
diff --git a/activesupport/lib/active_support/core_ext/numeric/conversions.rb b/activesupport/lib/active_support/core_ext/numeric/conversions.rb
index 946f8ddeab..4f6621693e 100644
--- a/activesupport/lib/active_support/core_ext/numeric/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/numeric/conversions.rb
@@ -99,31 +99,30 @@ module ActiveSupport::NumericWithFormat
# 1234567.to_s(:human, precision: 1,
# separator: ',',
# significant: false) # => "1,2 Million"
- def to_s(*args)
- format, options = args
- options ||= {}
-
+ def to_s(format = nil, options = nil)
case format
+ when nil
+ super()
+ when Integer, String
+ super(format)
when :phone
- return ActiveSupport::NumberHelper.number_to_phone(self, options)
+ return ActiveSupport::NumberHelper.number_to_phone(self, options || {})
when :currency
- return ActiveSupport::NumberHelper.number_to_currency(self, options)
+ return ActiveSupport::NumberHelper.number_to_currency(self, options || {})
when :percentage
- return ActiveSupport::NumberHelper.number_to_percentage(self, options)
+ return ActiveSupport::NumberHelper.number_to_percentage(self, options || {})
when :delimited
- return ActiveSupport::NumberHelper.number_to_delimited(self, options)
+ return ActiveSupport::NumberHelper.number_to_delimited(self, options || {})
when :rounded
- return ActiveSupport::NumberHelper.number_to_rounded(self, options)
+ return ActiveSupport::NumberHelper.number_to_rounded(self, options || {})
when :human
- return ActiveSupport::NumberHelper.number_to_human(self, options)
+ return ActiveSupport::NumberHelper.number_to_human(self, options || {})
when :human_size
- return ActiveSupport::NumberHelper.number_to_human_size(self, options)
+ return ActiveSupport::NumberHelper.number_to_human_size(self, options || {})
+ when Symbol
+ super()
else
- if is_a?(Float) || format.is_a?(Symbol)
- super()
- else
- super
- end
+ super(format)
end
end
end
diff --git a/activesupport/lib/active_support/core_ext/numeric/time.rb b/activesupport/lib/active_support/core_ext/numeric/time.rb
index 809dfd4e07..2e6c70d418 100644
--- a/activesupport/lib/active_support/core_ext/numeric/time.rb
+++ b/activesupport/lib/active_support/core_ext/numeric/time.rb
@@ -19,7 +19,7 @@ class Numeric
# # equivalent to Time.current.advance(months: 4, years: 5)
# (4.months + 5.years).from_now
def seconds
- ActiveSupport::Duration.new(self, [[:seconds, self]])
+ ActiveSupport::Duration.seconds(self)
end
alias :second :seconds
@@ -27,7 +27,7 @@ class Numeric
#
# 2.minutes # => 2 minutes
def minutes
- ActiveSupport::Duration.new(self * 60, [[:minutes, self]])
+ ActiveSupport::Duration.minutes(self)
end
alias :minute :minutes
@@ -35,7 +35,7 @@ class Numeric
#
# 2.hours # => 2 hours
def hours
- ActiveSupport::Duration.new(self * 3600, [[:hours, self]])
+ ActiveSupport::Duration.hours(self)
end
alias :hour :hours
@@ -43,7 +43,7 @@ class Numeric
#
# 2.days # => 2 days
def days
- ActiveSupport::Duration.new(self * 24.hours, [[:days, self]])
+ ActiveSupport::Duration.days(self)
end
alias :day :days
@@ -51,7 +51,7 @@ class Numeric
#
# 2.weeks # => 2 weeks
def weeks
- ActiveSupport::Duration.new(self * 7.days, [[:weeks, self]])
+ ActiveSupport::Duration.weeks(self)
end
alias :week :weeks
@@ -59,7 +59,7 @@ class Numeric
#
# 2.fortnights # => 4 weeks
def fortnights
- ActiveSupport::Duration.new(self * 2.weeks, [[:weeks, self * 2]])
+ ActiveSupport::Duration.weeks(self * 2)
end
alias :fortnight :fortnights
diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb
index 227c34b032..94ce3f6a61 100644
--- a/activesupport/lib/active_support/core_ext/string/output_safety.rb
+++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb
@@ -152,18 +152,16 @@ module ActiveSupport #:nodoc:
def [](*args)
if args.size < 2
super
- else
- if html_safe?
- new_safe_buffer = super
-
- if new_safe_buffer
- new_safe_buffer.instance_variable_set :@html_safe, true
- end
+ elsif html_safe?
+ new_safe_buffer = super
- new_safe_buffer
- else
- to_str[*args]
+ if new_safe_buffer
+ new_safe_buffer.instance_variable_set :@html_safe, true
end
+
+ new_safe_buffer
+ else
+ to_str[*args]
end
end
diff --git a/activesupport/lib/active_support/deprecation/proxy_wrappers.rb b/activesupport/lib/active_support/deprecation/proxy_wrappers.rb
index 1c6618b19a..ce39e9a232 100644
--- a/activesupport/lib/active_support/deprecation/proxy_wrappers.rb
+++ b/activesupport/lib/active_support/deprecation/proxy_wrappers.rb
@@ -122,10 +122,11 @@ module ActiveSupport
# (Backtrace information…)
# ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
class DeprecatedConstantProxy < DeprecationProxy
- def initialize(old_const, new_const, deprecator = ActiveSupport::Deprecation.instance)
+ def initialize(old_const, new_const, deprecator = ActiveSupport::Deprecation.instance, message: "#{old_const} is deprecated! Use #{new_const} instead.")
@old_const = old_const
@new_const = new_const
@deprecator = deprecator
+ @message = message
end
# Returns the class of the new constant.
@@ -143,7 +144,7 @@ module ActiveSupport
end
def warn(callstack, called, args)
- @deprecator.warn("#{@old_const} is deprecated! Use #{@new_const} instead.", callstack)
+ @deprecator.warn(@message, callstack)
end
end
end
diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb
index c9e8c8fdc4..003f6203ef 100644
--- a/activesupport/lib/active_support/duration.rb
+++ b/activesupport/lib/active_support/duration.rb
@@ -7,13 +7,82 @@ module ActiveSupport
#
# 1.month.ago # equivalent to Time.now.advance(months: -1)
class Duration
- EPOCH = ::Time.utc(2000)
+ SECONDS_PER_MINUTE = 60
+ SECONDS_PER_HOUR = 3600
+ SECONDS_PER_DAY = 86400
+ SECONDS_PER_WEEK = 604800
+ SECONDS_PER_MONTH = 2629746 # 1/12 of a gregorian year
+ SECONDS_PER_YEAR = 31556952 # length of a gregorian year (365.2425 days)
+
+ PARTS_IN_SECONDS = {
+ seconds: 1,
+ minutes: SECONDS_PER_MINUTE,
+ hours: SECONDS_PER_HOUR,
+ days: SECONDS_PER_DAY,
+ weeks: SECONDS_PER_WEEK,
+ months: SECONDS_PER_MONTH,
+ years: SECONDS_PER_YEAR
+ }.freeze
attr_accessor :value, :parts
autoload :ISO8601Parser, "active_support/duration/iso8601_parser"
autoload :ISO8601Serializer, "active_support/duration/iso8601_serializer"
+ class << self
+ # Creates a new Duration from string formatted according to ISO 8601 Duration.
+ #
+ # See {ISO 8601}[http://en.wikipedia.org/wiki/ISO_8601#Durations] for more information.
+ # This method allows negative parts to be present in pattern.
+ # If invalid string is provided, it will raise +ActiveSupport::Duration::ISO8601Parser::ParsingError+.
+ def parse(iso8601duration)
+ parts = ISO8601Parser.new(iso8601duration).parse!
+ new(calculate_total_seconds(parts), parts)
+ end
+
+ def ===(other) #:nodoc:
+ other.is_a?(Duration)
+ rescue ::NoMethodError
+ false
+ end
+
+ def seconds(value) #:nodoc:
+ new(value, [[:seconds, value]])
+ end
+
+ def minutes(value) #:nodoc:
+ new(value * SECONDS_PER_MINUTE, [[:minutes, value]])
+ end
+
+ def hours(value) #:nodoc:
+ new(value * SECONDS_PER_HOUR, [[:hours, value]])
+ end
+
+ def days(value) #:nodoc:
+ new(value * SECONDS_PER_DAY, [[:days, value]])
+ end
+
+ def weeks(value) #:nodoc:
+ new(value * SECONDS_PER_WEEK, [[:weeks, value]])
+ end
+
+ def months(value) #:nodoc:
+ new(value * SECONDS_PER_MONTH, [[:months, value]])
+ end
+
+ def years(value) #:nodoc:
+ new(value * SECONDS_PER_YEAR, [[:years, value]])
+ end
+
+ private
+
+ def calculate_total_seconds(parts)
+ parts.inject(0) do |total, (part, value)|
+ total + value * PARTS_IN_SECONDS[part]
+ end
+ end
+ end
+
def initialize(value, parts) #:nodoc:
@value, @parts = value, parts.to_h
@parts.default = 0
@@ -78,14 +147,14 @@ module ActiveSupport
# 1.day.to_i # => 86400
#
# Note that this conversion makes some assumptions about the
- # duration of some periods, e.g. months are always 30 days
- # and years are 365.25 days:
+ # duration of some periods, e.g. months are always 1/12 of year
+ # and years are 365.2425 days:
#
- # # equivalent to 30.days.to_i
- # 1.month.to_i # => 2592000
+ # # equivalent to (1.year / 12).to_i
+ # 1.month.to_i # => 2629746
#
- # # equivalent to 365.25.days.to_i
- # 1.year.to_i # => 31557600
+ # # equivalent to 365.2425.days.to_i
+ # 1.year.to_i # => 31556952
#
# In such cases, Ruby's core
# Date[http://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and
@@ -105,12 +174,6 @@ module ActiveSupport
@value.hash
end
- def self.===(other) #:nodoc:
- other.is_a?(Duration)
- rescue ::NoMethodError
- false
- end
-
# Calculates a new Time or Date that is as far in the future
# as this Duration represents.
def since(time = ::Time.current)
@@ -141,16 +204,6 @@ module ActiveSupport
@value.respond_to?(method, include_private)
end
- # Creates a new Duration from string formatted according to ISO 8601 Duration.
- #
- # See {ISO 8601}[http://en.wikipedia.org/wiki/ISO_8601#Durations] for more information.
- # This method allows negative parts to be present in pattern.
- # If invalid string is provided, it will raise +ActiveSupport::Duration::ISO8601Parser::ParsingError+.
- def self.parse(iso8601duration)
- parts = ISO8601Parser.new(iso8601duration).parse!
- new(EPOCH.advance(parts) - EPOCH, parts)
- 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)
diff --git a/activesupport/lib/active_support/evented_file_update_checker.rb b/activesupport/lib/active_support/evented_file_update_checker.rb
index f54f88eb0a..ed4604c2df 100644
--- a/activesupport/lib/active_support/evented_file_update_checker.rb
+++ b/activesupport/lib/active_support/evented_file_update_checker.rb
@@ -17,7 +17,7 @@ module ActiveSupport
#
# Example:
#
- # checker = EventedFileUpdateChecker.new(["/tmp/foo"], -> { puts "changed" })
+ # checker = ActiveSupport::EventedFileUpdateChecker.new(["/tmp/foo"]) { puts "changed" }
# checker.updated?
# # => false
# checker.execute_if_updated
diff --git a/activesupport/lib/active_support/execution_wrapper.rb b/activesupport/lib/active_support/execution_wrapper.rb
index 3384d12d5b..ca88e7876b 100644
--- a/activesupport/lib/active_support/execution_wrapper.rb
+++ b/activesupport/lib/active_support/execution_wrapper.rb
@@ -19,14 +19,14 @@ module ActiveSupport
set_callback(:complete, *args, &block)
end
- class RunHook < Struct.new(:hook) # :nodoc:
+ RunHook = Struct.new(:hook) do # :nodoc:
def before(target)
hook_state = target.send(:hook_state)
hook_state[hook] = hook.run
end
end
- class CompleteHook < Struct.new(:hook) # :nodoc:
+ CompleteHook = Struct.new(:hook) do # :nodoc:
def before(target)
hook_state = target.send(:hook_state)
if hook_state.key?(hook)
diff --git a/activesupport/lib/active_support/inflector/transliterate.rb b/activesupport/lib/active_support/inflector/transliterate.rb
index 3e78986e8e..de6dd2720b 100644
--- a/activesupport/lib/active_support/inflector/transliterate.rb
+++ b/activesupport/lib/active_support/inflector/transliterate.rb
@@ -57,6 +57,8 @@ module ActiveSupport
# transliterate('Jürgen')
# # => "Juergen"
def transliterate(string, replacement = "?".freeze)
+ raise ArgumentError, "Can only transliterate strings. Received #{string.class.name}" unless string.is_a?(String)
+
I18n.transliterate(ActiveSupport::Multibyte::Unicode.normalize(
ActiveSupport::Multibyte::Unicode.tidy_bytes(string), :c),
replacement: replacement)
diff --git a/activesupport/lib/active_support/multibyte/unicode.rb b/activesupport/lib/active_support/multibyte/unicode.rb
index 05cfb249c3..0912912aba 100644
--- a/activesupport/lib/active_support/multibyte/unicode.rb
+++ b/activesupport/lib/active_support/multibyte/unicode.rb
@@ -9,7 +9,7 @@ module ActiveSupport
NORMALIZATION_FORMS = [:c, :kc, :d, :kd]
# The Unicode version that is supported by the implementation
- UNICODE_VERSION = "8.0.0"
+ UNICODE_VERSION = "9.0.0"
# The default normalization used for operations that require
# normalization. It can be set to any of the normalizations
@@ -57,9 +57,12 @@ module ActiveSupport
previous = codepoints[pos - 1]
current = codepoints[pos]
+ # See http://unicode.org/reports/tr29/#Grapheme_Cluster_Boundary_Rules
should_break =
+ if pos == eoc
+ true
# GB3. CR X LF
- if previous == database.boundary[:cr] && current == database.boundary[:lf]
+ elsif previous == database.boundary[:cr] && current == database.boundary[:lf]
false
# GB4. (Control|CR|LF) ÷
elsif previous && in_char_class?(previous, [:control, :cr, :lf])
@@ -76,11 +79,8 @@ module ActiveSupport
# GB8. (LVT|T) X (T)
elsif in_char_class?(previous, [:lvt, :t]) && database.boundary[:t] === current
false
- # GB8a. Regional_Indicator X Regional_Indicator
- elsif database.boundary[:regional_indicator] === previous && database.boundary[:regional_indicator] === current
- false
- # GB9. X Extend
- elsif database.boundary[:extend] === current
+ # GB9. X (Extend | ZWJ)
+ elsif in_char_class?(current, [:extend, :zwj])
false
# GB9a. X SpacingMark
elsif database.boundary[:spacingmark] === current
@@ -88,7 +88,17 @@ module ActiveSupport
# GB9b. Prepend X
elsif database.boundary[:prepend] === previous
false
- # GB10. Any ÷ Any
+ # GB10. (E_Base | EBG) Extend* X E_Modifier
+ elsif (marker...pos).any? { |i| in_char_class?(codepoints[i], [:e_base, :e_base_gaz]) && codepoints[i + 1...pos].all? { |c| database.boundary[:extend] === c } } && database.boundary[:e_modifier] === current
+ false
+ # GB11. ZWJ X (Glue_After_Zwj | EBG)
+ elsif database.boundary[:zwj] === previous && in_char_class?(current, [:glue_after_zwj, :e_base_gaz])
+ false
+ # GB12. ^ (RI RI)* RI X RI
+ # GB13. [^RI] (RI RI)* RI X RI
+ elsif codepoints[marker..pos].all? { |c| database.boundary[:regional_indicator] === c } && codepoints[marker..pos].count { |c| database.boundary[:regional_indicator] === c }.even?
+ false
+ # GB999. Any ÷ Any
else
true
end
diff --git a/activesupport/lib/active_support/number_helper.rb b/activesupport/lib/active_support/number_helper.rb
index 6000ea44be..da4e91e949 100644
--- a/activesupport/lib/active_support/number_helper.rb
+++ b/activesupport/lib/active_support/number_helper.rb
@@ -78,7 +78,7 @@ module ActiveSupport
# (defaults to "%u%n"). Fields are <tt>%u</tt> for the
# currency, and <tt>%n</tt> for the number.
# * <tt>:negative_format</tt> - Sets the format for negative
- # numbers (defaults to prepending an hyphen to the formatted
+ # numbers (defaults to prepending a hyphen to the formatted
# number given by <tt>:format</tt>). Accepts the same fields
# than <tt>:format</tt>, except <tt>%n</tt> is here the
# absolute value of the number.
diff --git a/activesupport/lib/active_support/string_inquirer.rb b/activesupport/lib/active_support/string_inquirer.rb
index 09e1cbb28d..90eac89c9e 100644
--- a/activesupport/lib/active_support/string_inquirer.rb
+++ b/activesupport/lib/active_support/string_inquirer.rb
@@ -18,7 +18,7 @@ module ActiveSupport
private
def respond_to_missing?(method_name, include_private = false)
- method_name[-1] == "?"
+ (method_name[-1] == "?") || super
end
def method_missing(method_name, *arguments)
diff --git a/activesupport/lib/active_support/values/unicode_tables.dat b/activesupport/lib/active_support/values/unicode_tables.dat
index dd2c178fb6..f7d9c48bbe 100644
--- a/activesupport/lib/active_support/values/unicode_tables.dat
+++ b/activesupport/lib/active_support/values/unicode_tables.dat
Binary files differ
diff --git a/activesupport/test/abstract_unit.rb b/activesupport/test/abstract_unit.rb
index 6b9daf0fe2..c4f34c0abf 100644
--- a/activesupport/test/abstract_unit.rb
+++ b/activesupport/test/abstract_unit.rb
@@ -24,16 +24,16 @@ ActiveSupport.to_time_preserves_timezone = ENV["PRESERVE_TIMEZONES"] == "1"
# Disable available locale checks to avoid warnings running the test suite.
I18n.enforce_available_locales = false
-# Skips the current run on Rubinius using Minitest::Assertions#skip
-def rubinius_skip(message = "")
- skip message if RUBY_ENGINE == "rbx"
-end
-
-# Skips the current run on JRuby using Minitest::Assertions#skip
-def jruby_skip(message = "")
- skip message if defined?(JRUBY_VERSION)
-end
-
class ActiveSupport::TestCase
include ActiveSupport::Testing::MethodCallAssertions
+
+ # Skips the current run on Rubinius using Minitest::Assertions#skip
+ private def rubinius_skip(message = "")
+ skip message if RUBY_ENGINE == "rbx"
+ end
+
+ # Skips the current run on JRuby using Minitest::Assertions#skip
+ private def jruby_skip(message = "")
+ skip message if defined?(JRUBY_VERSION)
+ end
end
diff --git a/activesupport/test/array_inquirer_test.rb b/activesupport/test/array_inquirer_test.rb
index 4d3f5b001c..5b2bc82905 100644
--- a/activesupport/test/array_inquirer_test.rb
+++ b/activesupport/test/array_inquirer_test.rb
@@ -38,4 +38,24 @@ class ArrayInquirerTest < ActiveSupport::TestCase
assert_instance_of ActiveSupport::ArrayInquirer, result
assert_equal @array_inquirer, result
end
+
+ def test_respond_to_fallback_to_array_respond_to
+ Array.class_eval do
+ def respond_to_missing?(name, include_private = false)
+ (name == :foo) || super
+ end
+ end
+ arr = ActiveSupport::ArrayInquirer.new([:x])
+
+ assert_respond_to arr, :can_you_hear_me?
+ assert_respond_to arr, :foo
+ assert_not_respond_to arr, :nope
+ ensure
+ Array.class_eval do
+ undef_method :respond_to_missing?
+ def respond_to_missing?(name, include_private = false)
+ super
+ end
+ end
+ end
end
diff --git a/activesupport/test/core_ext/duration_test.rb b/activesupport/test/core_ext/duration_test.rb
index fc0dd41d0e..6a275d1d5b 100644
--- a/activesupport/test/core_ext/duration_test.rb
+++ b/activesupport/test/core_ext/duration_test.rb
@@ -237,6 +237,29 @@ class DurationTest < ActiveSupport::TestCase
assert_equal(1, (61 <=> 1.minute))
end
+ def test_twelve_months_equals_one_year
+ assert_equal 12.months, 1.year
+ end
+
+ def test_thirty_days_does_not_equal_one_month
+ assert_not_equal 30.days, 1.month
+ end
+
+ def test_adding_one_month_maintains_day_of_month
+ (1..11).each do |month|
+ [1, 14, 28].each do |day|
+ assert_equal Date.civil(2016, month + 1, day), Date.civil(2016, month, day) + 1.month
+ end
+ end
+
+ assert_equal Date.civil(2017, 1, 1), Date.civil(2016, 12, 1) + 1.month
+ assert_equal Date.civil(2017, 1, 14), Date.civil(2016, 12, 14) + 1.month
+ assert_equal Date.civil(2017, 1, 28), Date.civil(2016, 12, 28) + 1.month
+
+ assert_equal Date.civil(2015, 2, 28), Date.civil(2015, 1, 31) + 1.month
+ assert_equal Date.civil(2016, 2, 29), Date.civil(2016, 1, 31) + 1.month
+ end
+
# ISO8601 string examples are taken from ISO8601 gem at https://github.com/arnau/ISO8601/blob/b93d466840/spec/iso8601/duration_spec.rb
# published under the conditions of MIT license at https://github.com/arnau/ISO8601/blob/b93d466840/LICENSE
#
@@ -345,6 +368,21 @@ class DurationTest < ActiveSupport::TestCase
end
end
+ def test_iso8601_parsing_equivalence_with_numeric_extensions_over_long_periods
+ with_env_tz eastern_time_zone do
+ with_tz_default "Eastern Time (US & Canada)" do
+ assert_equal 3.months, ActiveSupport::Duration.parse("P3M")
+ assert_equal 3.months.to_i, ActiveSupport::Duration.parse("P3M").to_i
+ assert_equal 10.months, ActiveSupport::Duration.parse("P10M")
+ assert_equal 10.months.to_i, ActiveSupport::Duration.parse("P10M").to_i
+ assert_equal 3.years, ActiveSupport::Duration.parse("P3Y")
+ assert_equal 3.years.to_i, ActiveSupport::Duration.parse("P3Y").to_i
+ assert_equal 10.years, ActiveSupport::Duration.parse("P10Y")
+ assert_equal 10.years.to_i, ActiveSupport::Duration.parse("P10Y").to_i
+ end
+ end
+ end
+
def test_adding_durations_do_not_hold_prior_states
time = Time.parse("Nov 29, 2016")
# If the implementation adds and subtracts 3 months, the
diff --git a/activesupport/test/core_ext/kernel_test.rb b/activesupport/test/core_ext/kernel_test.rb
index db0008b735..26f5088ede 100644
--- a/activesupport/test/core_ext/kernel_test.rb
+++ b/activesupport/test/core_ext/kernel_test.rb
@@ -49,19 +49,3 @@ class KernelSuppressTest < ActiveSupport::TestCase
suppress(LoadError, ArgumentError) { raise ArgumentError }
end
end
-
-class MockStdErr
- attr_reader :output
- def puts(message)
- @output ||= []
- @output << message
- end
-
- def info(message)
- puts(message)
- end
-
- def write(message)
- puts(message)
- end
-end
diff --git a/activesupport/test/core_ext/module/introspection_test.rb b/activesupport/test/core_ext/module/introspection_test.rb
new file mode 100644
index 0000000000..db383850cd
--- /dev/null
+++ b/activesupport/test/core_ext/module/introspection_test.rb
@@ -0,0 +1,37 @@
+require "abstract_unit"
+require "active_support/core_ext/module/introspection"
+
+module ParentA
+ module B
+ module C; end
+ module FrozenC; end
+ FrozenC.freeze
+ end
+
+ module FrozenB; end
+ FrozenB.freeze
+end
+
+class IntrospectionTest < ActiveSupport::TestCase
+ def test_parent_name
+ assert_equal "ParentA", ParentA::B.parent_name
+ assert_equal "ParentA::B", ParentA::B::C.parent_name
+ assert_nil ParentA.parent_name
+ end
+
+ def test_parent_name_when_frozen
+ assert_equal "ParentA", ParentA::FrozenB.parent_name
+ assert_equal "ParentA::B", ParentA::B::FrozenC.parent_name
+ end
+
+ def test_parent
+ assert_equal ParentA::B, ParentA::B::C.parent
+ assert_equal ParentA, ParentA::B.parent
+ assert_equal Object, ParentA.parent
+ end
+
+ def test_parents
+ assert_equal [ParentA::B, ParentA, Object], ParentA::B::C.parents
+ assert_equal [ParentA, Object], ParentA::B.parents
+ end
+end
diff --git a/activesupport/test/core_ext/module_test.rb b/activesupport/test/core_ext/module_test.rb
index a4515d1956..a17438bf4d 100644
--- a/activesupport/test/core_ext/module_test.rb
+++ b/activesupport/test/core_ext/module_test.rb
@@ -1,30 +1,11 @@
require "abstract_unit"
require "active_support/core_ext/module"
-module One
- Constant1 = "Hello World"
- Constant2 = "What's up?"
-end
-
-class Ab
- include One
- Constant1 = "Hello World" # Will have different object id than One::Constant1
- Constant3 = "Goodbye World"
-end
-
-module Yz
- module Zy
- class Cd
- include One
- end
- end
-end
-
Somewhere = Struct.new(:street, :city) do
attr_accessor :name
end
-class Someone < Struct.new(:name, :place)
+Someone = Struct.new(:name, :place) do
delegate :street, :city, :to_f, to: :place
delegate :name=, to: :place, prefix: true
delegate :upcase, to: "place.city"
@@ -35,10 +16,10 @@ class Someone < Struct.new(:name, :place)
"some_table"
end
- FAILED_DELEGATE_LINE = __LINE__ + 1
+ self::FAILED_DELEGATE_LINE = __LINE__ + 1
delegate :foo, to: :place
- FAILED_DELEGATE_LINE_2 = __LINE__ + 1
+ self::FAILED_DELEGATE_LINE_2 = __LINE__ + 1
delegate :bar, to: :place, allow_nil: true
private
@@ -375,17 +356,6 @@ class ModuleTest < ActiveSupport::TestCase
assert_match(/undefined method `my_fake_method' for/, e.message)
end
- def test_parent
- assert_equal Yz::Zy, Yz::Zy::Cd.parent
- assert_equal Yz, Yz::Zy.parent
- assert_equal Object, Yz.parent
- end
-
- def test_parents
- assert_equal [Yz::Zy, Yz, Object], Yz::Zy::Cd.parents
- assert_equal [Yz, Object], Yz::Zy.parents
- end
-
def test_delegate_with_case
event = Event.new(Tester.new)
assert_equal 1, event.foo
diff --git a/activesupport/test/core_ext/numeric_ext_test.rb b/activesupport/test/core_ext/numeric_ext_test.rb
index 5361b7b708..3cfbe6e7e6 100644
--- a/activesupport/test/core_ext/numeric_ext_test.rb
+++ b/activesupport/test/core_ext/numeric_ext_test.rb
@@ -12,7 +12,7 @@ class NumericExtTimeAndDateTimeTest < ActiveSupport::TestCase
10.minutes => 600,
1.hour + 15.minutes => 4500,
2.days + 4.hours + 30.minutes => 189000,
- 5.years + 1.month + 1.fortnight => 161589600
+ 5.years + 1.month + 1.fortnight => 161624106
}
end
@@ -61,10 +61,10 @@ class NumericExtTimeAndDateTimeTest < ActiveSupport::TestCase
end
def test_duration_after_conversion_is_no_longer_accurate
- assert_equal 30.days.to_i.seconds.since(@now), 1.month.to_i.seconds.since(@now)
- assert_equal 365.25.days.to_f.seconds.since(@now), 1.year.to_f.seconds.since(@now)
- assert_equal 30.days.to_i.seconds.since(@dtnow), 1.month.to_i.seconds.since(@dtnow)
- assert_equal 365.25.days.to_f.seconds.since(@dtnow), 1.year.to_f.seconds.since(@dtnow)
+ assert_equal (1.year / 12).to_i.seconds.since(@now), 1.month.to_i.seconds.since(@now)
+ assert_equal 365.2425.days.to_f.seconds.since(@now), 1.year.to_f.seconds.since(@now)
+ assert_equal (1.year / 12).to_i.seconds.since(@dtnow), 1.month.to_i.seconds.since(@dtnow)
+ assert_equal 365.2425.days.to_f.seconds.since(@dtnow), 1.year.to_f.seconds.since(@dtnow)
end
def test_add_one_year_to_leap_day
@@ -394,6 +394,10 @@ class NumericExtFormattingTest < ActiveSupport::TestCase
assert_equal "1000010.0", BigDecimal("1000010").to_s
assert_equal "10000 10.0", BigDecimal("1000010").to_s("5F")
+
+ assert_raises TypeError do
+ 1.to_s({})
+ end
end
def test_in_milliseconds
diff --git a/activesupport/test/core_ext/object/duplicable_test.rb b/activesupport/test/core_ext/object/duplicable_test.rb
index 466f62a4b4..e6f3c8aef2 100644
--- a/activesupport/test/core_ext/object/duplicable_test.rb
+++ b/activesupport/test/core_ext/object/duplicable_test.rb
@@ -4,7 +4,10 @@ require "active_support/core_ext/object/duplicable"
require "active_support/core_ext/numeric/time"
class DuplicableTest < ActiveSupport::TestCase
- if RUBY_VERSION >= "2.4.0"
+ if RUBY_VERSION >= "2.4.1"
+ RAISE_DUP = [method(:puts), Complex(1), Rational(1)]
+ ALLOW_DUP = ["1", "symbol_from_string".to_sym, Object.new, /foo/, [], {}, Time.now, Class.new, Module.new, BigDecimal.new("4.56"), nil, false, true, 1, 2.3]
+ elsif RUBY_VERSION >= "2.4.0" # Due to 2.4.0 bug. This elsif cannot be removed unless we drop 2.4.0 support...
RAISE_DUP = [method(:puts), Complex(1), Rational(1), "symbol_from_string".to_sym]
ALLOW_DUP = ["1", Object.new, /foo/, [], {}, Time.now, Class.new, Module.new, BigDecimal.new("4.56"), nil, false, true, 1, 2.3]
else
@@ -17,7 +20,7 @@ class DuplicableTest < ActiveSupport::TestCase
"* https://github.com/rubinius/rubinius/issues/3089"
RAISE_DUP.each do |v|
- assert !v.duplicable?
+ assert !v.duplicable?, "#{ v.inspect } should not be duplicable"
assert_raises(TypeError, v.class.name) { v.dup }
end
diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb
index 00685cd952..5d90fa2509 100644
--- a/activesupport/test/core_ext/string_ext_test.rb
+++ b/activesupport/test/core_ext/string_ext_test.rb
@@ -222,7 +222,7 @@ class StringInflectionsTest < ActiveSupport::TestCase
original = %{\u205f\u3000 A string surrounded by various unicode spaces,
with tabs(\t\t), newlines(\n\n), unicode nextlines(\u0085\u0085) and many spaces( ). \u00a0\u2007}
- expected = "A string surrounded by various unicode spaces, " +
+ expected = "A string surrounded by various unicode spaces, " \
"with tabs( ), newlines( ), unicode nextlines( ) and many spaces( )."
# Make sure squish returns what we expect:
diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb
index e772d15d53..577675ecdf 100644
--- a/activesupport/test/dependencies_test.rb
+++ b/activesupport/test/dependencies_test.rb
@@ -271,7 +271,8 @@ class DependenciesTest < ActiveSupport::TestCase
def test_raising_discards_autoloaded_constants
with_autoloading_fixtures do
- assert_raises(Exception, "arbitray exception message") { RaisesArbitraryException }
+ e = assert_raises(Exception) { RaisesArbitraryException }
+ assert_equal("arbitray exception message", e.message)
assert_not defined?(A)
assert_not defined?(RaisesArbitraryException)
end
@@ -397,14 +398,17 @@ class DependenciesTest < ActiveSupport::TestCase
end
end
- def failing_test_access_thru_and_upwards_fails
- with_autoloading_fixtures do
- assert_not defined?(ModuleFolder)
- assert_raise(NameError) { ModuleFolder::Object }
- assert_raise(NameError) { ModuleFolder::NestedClass::Object }
+ # This raises only on 2.5.. (warns on ..2.4)
+ if RUBY_VERSION > "2.5"
+ def test_access_thru_and_upwards_fails
+ with_autoloading_fixtures do
+ assert_not defined?(ModuleFolder)
+ assert_raise(NameError) { ModuleFolder::Object }
+ assert_raise(NameError) { ModuleFolder::NestedClass::Object }
+ end
+ ensure
+ remove_constants(:ModuleFolder)
end
- ensure
- remove_constants(:ModuleFolder)
end
def test_non_existing_const_raises_name_error_with_fully_qualified_name
diff --git a/activesupport/test/deprecation_test.rb b/activesupport/test/deprecation_test.rb
index 5be93f3a1a..5f72fbf662 100644
--- a/activesupport/test/deprecation_test.rb
+++ b/activesupport/test/deprecation_test.rb
@@ -285,6 +285,16 @@ class DeprecationTest < ActiveSupport::TestCase
end
end
+ def test_deprecated_constant_with_custom_message
+ deprecator = deprecator_with_messages
+
+ klass = Class.new
+ klass.const_set(:OLD, ActiveSupport::Deprecation::DeprecatedConstantProxy.new("klass::OLD", "Object", deprecator, message: "foo"))
+
+ klass::OLD.to_s
+ assert_match "foo", deprecator.messages.last
+ end
+
def test_deprecated_instance_variable_with_instance_deprecator
deprecator = deprecator_with_messages
diff --git a/activesupport/test/evented_file_update_checker_test.rb b/activesupport/test/evented_file_update_checker_test.rb
index 77d8dcb0f8..bb2ae4baa6 100644
--- a/activesupport/test/evented_file_update_checker_test.rb
+++ b/activesupport/test/evented_file_update_checker_test.rb
@@ -30,11 +30,6 @@ class EventedFileUpdateCheckerTest < ActiveSupport::TestCase
wait # wait for the events to fire
end
- def rm_f(files)
- super
- wait
- end
-
test "notifies forked processes" do
jruby_skip "Forking not available on JRuby"
diff --git a/activesupport/test/inflector_test.rb b/activesupport/test/inflector_test.rb
index 8d39303f9b..03d7b3fe94 100644
--- a/activesupport/test/inflector_test.rb
+++ b/activesupport/test/inflector_test.rb
@@ -271,35 +271,25 @@ class InflectorTest < ActiveSupport::TestCase
end
end
- # FIXME: get following tests to pass on jruby, currently skipped
- #
- # Currently this fails because ActiveSupport::Multibyte::Unicode#tidy_bytes
- # required a specific Encoding::Converter(UTF-8 to UTF8-MAC) which unavailable on JRuby
- # causing our tests to error out.
- # related bug http://jira.codehaus.org/browse/JRUBY-7194
def test_parameterize
- jruby_skip "UTF-8 to UTF8-MAC Converter is unavailable"
StringToParameterized.each do |some_string, parameterized_string|
assert_equal(parameterized_string, ActiveSupport::Inflector.parameterize(some_string))
end
end
def test_parameterize_and_normalize
- jruby_skip "UTF-8 to UTF8-MAC Converter is unavailable"
StringToParameterizedAndNormalized.each do |some_string, parameterized_string|
assert_equal(parameterized_string, ActiveSupport::Inflector.parameterize(some_string))
end
end
def test_parameterize_with_custom_separator
- jruby_skip "UTF-8 to UTF8-MAC Converter is unavailable"
StringToParameterizeWithUnderscore.each do |some_string, parameterized_string|
assert_equal(parameterized_string, ActiveSupport::Inflector.parameterize(some_string, separator: "_"))
end
end
def test_parameterize_with_multi_character_separator
- jruby_skip "UTF-8 to UTF8-MAC Converter is unavailable"
StringToParameterized.each do |some_string, parameterized_string|
assert_equal(parameterized_string.gsub("-", "__sep__"), ActiveSupport::Inflector.parameterize(some_string, separator: "__sep__"))
end
diff --git a/activesupport/test/json/decoding_test.rb b/activesupport/test/json/decoding_test.rb
index 6d1d8f1b95..6f5051c312 100644
--- a/activesupport/test/json/decoding_test.rb
+++ b/activesupport/test/json/decoding_test.rb
@@ -75,12 +75,17 @@ class TestJSONDecoding < ActiveSupport::TestCase
}
TESTS.each_with_index do |(json, expected), index|
+ fail_message = "JSON decoding failed for #{json}"
+
test "json decodes #{index}" do
with_tz_default "Eastern Time (US & Canada)" do
with_parse_json_times(true) do
silence_warnings do
- assert_equal expected, ActiveSupport::JSON.decode(json), "JSON decoding \
- failed for #{json}"
+ if expected.nil?
+ assert_nil ActiveSupport::JSON.decode(json), fail_message
+ else
+ assert_equal expected, ActiveSupport::JSON.decode(json), fail_message
+ end
end
end
end
diff --git a/activesupport/test/json/encoding_test_cases.rb b/activesupport/test/json/encoding_test_cases.rb
index 8eac246937..b2f0cf3048 100644
--- a/activesupport/test/json/encoding_test_cases.rb
+++ b/activesupport/test/json/encoding_test_cases.rb
@@ -23,7 +23,7 @@ module JSONTest
end
end
- class MyStruct < Struct.new(:name, :value)
+ MyStruct = Struct.new(:name, :value) do
def initialize(*)
@unused = "unused instance variable"
super
diff --git a/activesupport/test/multibyte_test_helpers.rb b/activesupport/test/multibyte_test_helpers.rb
index 2201860d8a..a70516bb08 100644
--- a/activesupport/test/multibyte_test_helpers.rb
+++ b/activesupport/test/multibyte_test_helpers.rb
@@ -18,7 +18,7 @@ module MultibyteTestHelpers
end
UNIDATA_URL = "http://www.unicode.org/Public/#{ActiveSupport::Multibyte::Unicode::UNICODE_VERSION}/ucd"
- CACHE_DIR = "#{Dir.tmpdir}/cache/unicode_conformance"
+ CACHE_DIR = "#{Dir.tmpdir}/cache/unicode_conformance/#{ActiveSupport::Multibyte::Unicode::UNICODE_VERSION}"
FileUtils.mkdir_p(CACHE_DIR)
UNICODE_STRING = "こにちわ".freeze
diff --git a/activesupport/test/number_helper_i18n_test.rb b/activesupport/test/number_helper_i18n_test.rb
index 4f58e6607a..a1d1c41dc2 100644
--- a/activesupport/test/number_helper_i18n_test.rb
+++ b/activesupport/test/number_helper_i18n_test.rb
@@ -1,5 +1,6 @@
require "abstract_unit"
require "active_support/number_helper"
+require "active_support/core_ext/hash/keys"
module ActiveSupport
class NumberHelperI18nTest < ActiveSupport::TestCase
diff --git a/activesupport/test/string_inquirer_test.rb b/activesupport/test/string_inquirer_test.rb
index d41e4d6800..79a715349c 100644
--- a/activesupport/test/string_inquirer_test.rb
+++ b/activesupport/test/string_inquirer_test.rb
@@ -20,4 +20,25 @@ class StringInquirerTest < ActiveSupport::TestCase
def test_respond_to
assert_respond_to @string_inquirer, :development?
end
+
+ def test_respond_to_fallback_to_string_respond_to
+ String.class_eval do
+ def respond_to_missing?(name, include_private = false)
+ (name == :bar) || super
+ end
+ end
+ str = ActiveSupport::StringInquirer.new("hello")
+
+ assert_respond_to str, :are_you_ready?
+ assert_respond_to str, :bar
+ assert_not_respond_to str, :nope
+
+ ensure
+ String.class_eval do
+ undef_method :respond_to_missing?
+ def respond_to_missing?(name, include_private = false)
+ super
+ end
+ end
+ end
end
diff --git a/activesupport/test/time_travel_test.rb b/activesupport/test/time_travel_test.rb
index cfc6447360..e0d3fb0cf5 100644
--- a/activesupport/test/time_travel_test.rb
+++ b/activesupport/test/time_travel_test.rb
@@ -94,11 +94,12 @@ class TimeTravelTest < ActiveSupport::TestCase
outer_expected_time = Time.new(2004, 11, 24, 01, 04, 44)
inner_expected_time = Time.new(2004, 10, 24, 01, 04, 44)
travel_to outer_expected_time do
- assert_raises(RuntimeError, /Calling `travel_to` with a block, when we have previously already made a call to `travel_to`, can lead to confusing time stubbing./) do
+ e = assert_raises(RuntimeError) do
travel_to(inner_expected_time) do
#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)
end
end
end
diff --git a/activesupport/test/transliterate_test.rb b/activesupport/test/transliterate_test.rb
index 040ddd25fc..466b69bcef 100644
--- a/activesupport/test/transliterate_test.rb
+++ b/activesupport/test/transliterate_test.rb
@@ -31,4 +31,22 @@ class TransliterateTest < ActiveSupport::TestCase
def test_transliterate_should_allow_a_custom_replacement_char
assert_equal "a*b", ActiveSupport::Inflector.transliterate("a索b", "*")
end
+
+ def test_transliterate_handles_empty_string
+ assert_equal "", ActiveSupport::Inflector.transliterate("")
+ end
+
+ def test_transliterate_handles_nil
+ exception = assert_raises ArgumentError do
+ ActiveSupport::Inflector.transliterate(nil)
+ end
+ assert_equal "Can only transliterate strings. Received NilClass", exception.message
+ end
+
+ def test_transliterate_handles_unknown_object
+ exception = assert_raises ArgumentError do
+ ActiveSupport::Inflector.transliterate(Object.new)
+ end
+ assert_equal "Can only transliterate strings. Received Object", exception.message
+ end
end
diff --git a/guides/bug_report_templates/action_controller_gem.rb b/guides/bug_report_templates/action_controller_gem.rb
index 960d269d90..85d698f81b 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.0.0"
+ gem "rails", "5.0.1"
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 debc46ad54..f715caec95 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.0.0"
+ gem "activejob", "5.0.1"
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 e18302fe65..98edcb76b1 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.0.0"
+ gem "activerecord", "5.0.1"
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 ba80e6b4ad..ece6ae4f12 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.0.0.1"
+ gem "activerecord", "5.0.1"
gem "sqlite3"
end
diff --git a/guides/bug_report_templates/generic_gem.rb b/guides/bug_report_templates/generic_gem.rb
index a94848e25b..fa9f94eea0 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.0.0"
+ gem "activesupport", "5.0.1"
end
require "active_support/core_ext/object/blank"
diff --git a/guides/source/action_cable_overview.md b/guides/source/action_cable_overview.md
index 319277ef68..e929945dd0 100644
--- a/guides/source/action_cable_overview.md
+++ b/guides/source/action_cable_overview.md
@@ -240,8 +240,8 @@ WebNotificationsChannel.broadcast_to(
```
The `WebNotificationsChannel.broadcast_to` call places a message in the current
-subscription adapter (by default `redis` for production and `async` for development and
-test environments)'s pubsub queue under a separate broadcasting name for each user.
+subscription adapter (by default `redis` for production and `async` for development and
+test environments)'s pubsub queue under a separate broadcasting name for each user.
For a user with an ID of 1, the broadcasting name would be `web_notifications:1`.
The channel has been instructed to stream everything that arrives at
@@ -530,7 +530,7 @@ Action Cable has two required configurations: a subscription adapter and allowed
### Subscription Adapter
By default, Action Cable looks for a configuration file in `config/cable.yml`.
-The file must specify an adapter and a URL for each Rails environment. See the
+The file must specify an adapter for each Rails environment. See the
[Dependencies](#dependencies) section for additional information on adapters.
```yaml
@@ -543,7 +543,28 @@ test:
production:
adapter: redis
url: redis://10.10.3.153:6381
+ channel_prefix: appname_production
```
+#### Adapter Configuration
+
+Below is a list of the subscription adapters available for end users.
+
+##### Async Adapter
+
+The async adapter is intended for development/testing and should not be used in production.
+
+##### Redis Adapter
+
+Action Cable contains two Redis adapters: "normal" Redis and Evented Redis. Both
+of the adapters require users to provide a URL pointing to the Redis server.
+Additionally, a channel_prefix may be provided to avoid channel name collisions
+when using the same Redis server for multiple applications. See the [Redis PubSub documentation](https://redis.io/topics/pubsub#database-amp-scoping) for more details.
+
+##### PostgreSQL Adapter
+
+The PostgreSQL adapter uses Active Record's connection pool, and thus the
+application's `config/database.yml` database configuration, for its connection.
+This may change in the future. [#27214](https://github.com/rails/rails/issues/27214)
### Allowed Request Origins
diff --git a/guides/source/action_mailer_basics.md b/guides/source/action_mailer_basics.md
index 0825d54cb7..380fdac658 100644
--- a/guides/source/action_mailer_basics.md
+++ b/guides/source/action_mailer_basics.md
@@ -160,8 +160,8 @@ When you call the `mail` method now, Action Mailer will detect the two templates
#### Calling the Mailer
Mailers are really just another way to render a view. Instead of rendering a
-view and sending out the HTTP protocol, they are just sending it out through the
-email protocols instead. Due to this, it makes sense to just have your
+view and sending it over the HTTP protocol, they are just sending it out through
+the email protocols instead. Due to this, it makes sense to just have your
controller tell the Mailer to send an email when a user is successfully created.
Setting this up is painfully simple.
@@ -525,7 +525,7 @@ By using the full URL, your links will now work in your emails.
#### Generating URLs with `url_for`
-`url_for` generate full URL by default in templates.
+`url_for` generates a full URL by default in templates.
If you did not configure the `:host` option globally make sure to pass it to
`url_for`.
@@ -574,7 +574,7 @@ Now you can display an image inside your email.
### Sending Multipart Emails
Action Mailer will automatically send multipart emails if you have different
-templates for the same action. So, for our UserMailer example, if you have
+templates for the same action. So, for our `UserMailer` example, if you have
`welcome_email.text.erb` and `welcome_email.html.erb` in
`app/views/user_mailer`, Action Mailer will automatically send a multipart email
with the HTML and text versions setup as different parts.
diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md
index 830a546570..fe5437ae5d 100644
--- a/guides/source/contributing_to_ruby_on_rails.md
+++ b/guides/source/contributing_to_ruby_on_rails.md
@@ -67,7 +67,7 @@ can expect it to be marked "invalid" as soon as it's reviewed.
Sometimes, the line between 'bug' and 'feature' is a hard one to draw.
Generally, a feature is anything that adds new behavior, while a bug is
anything that causes incorrect behavior. Sometimes,
-the core team will have to make a judgement call. That said, the distinction
+the core team will have to make a judgment call. That said, the distinction
generally just affects which release your patch will get in to; we love feature
submissions! They just won't get backported to maintenance branches.
@@ -335,10 +335,12 @@ file.
#### Testing Active Record
-First, create the databases you'll need. For MySQL and PostgreSQL,
-running the SQL statements `create database activerecord_unittest` and
-`create database activerecord_unittest2` is sufficient. This is not
-necessary for SQLite3.
+First, create the databases you'll need. You can find a list of the required
+table names, usernames, and passwords in `activerecord/test/config.example.yml`.
+
+For MySQL and PostgreSQL, running the SQL statements `create database
+activerecord_unittest` and `create database activerecord_unittest2` is
+sufficient. This is not necessary for SQLite3.
This is how you run the Active Record test suite only for SQLite3:
diff --git a/guides/source/debugging_rails_applications.md b/guides/source/debugging_rails_applications.md
index df3003a6a8..ba0cdbf3af 100644
--- a/guides/source/debugging_rails_applications.md
+++ b/guides/source/debugging_rails_applications.md
@@ -683,7 +683,7 @@ Ruby instruction to be executed -- in this case, Active Support's `week` method.
51: #
52: # 2.weeks # => 14 days
53: def weeks
-=> 54: ActiveSupport::Duration.new(self * 7.days, [[:days, self * 7]])
+=> 54: ActiveSupport::Duration.weeks(self)
55: end
56: alias :week :weeks
57:
diff --git a/guides/source/i18n.md b/guides/source/i18n.md
index df5869f9ca..4db6e3e195 100644
--- a/guides/source/i18n.md
+++ b/guides/source/i18n.md
@@ -672,7 +672,7 @@ end
### Pluralization
-In English there are only one singular and one plural form for a given string, e.g. "1 message" and "2 messages". Other languages ([Arabic](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html#ar), [Japanese](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html#ja), [Russian](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html#ru) and many more) have different grammars that have additional or fewer [plural forms](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html). Thus, the I18n API provides a flexible pluralization feature.
+In English there are only one singular and one plural form for a given string, e.g. "1 message" and "2 messages". Other languages ([Arabic](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#ar), [Japanese](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#ja), [Russian](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#ru) and many more) have different grammars that have additional or fewer [plural forms](http://cldr.unicode.org/index/cldr-spec/plural-rules). Thus, the I18n API provides a flexible pluralization feature.
The `:count` interpolation variable has a special role in that it both is interpolated to the translation and used to pick a pluralization from the translations according to the pluralization rules defined by CLDR:
diff --git a/guides/source/initialization.md b/guides/source/initialization.md
index aa7bbcc19b..3ea156c6fe 100644
--- a/guides/source/initialization.md
+++ b/guides/source/initialization.md
@@ -168,7 +168,7 @@ module Rails::Command
class << self
def invoke(namespace, args = [], **config)
namespace = namespace.to_s
- namespace = "help" if namespace.blank? || Thor::HELP_MAPPINGS.include?(namespace)
+ namespace = "help" if namespace.blank? || HELP_MAPPINGS.include?(namespace)
namespace = "version" if %w( -v --version ).include? namespace
if command = find_by_namespace(namespace)
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 6cb88ca01d..0b2fb3e9c8 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,3 +1,20 @@
+* Add option to configure Ruby's warning behaviour to test runner.
+
+ *Yuji Yaginuma*
+
+* Initialize git repo when generating new app, if option `--skip-git`
+ is not provided.
+
+ *Dino Maric*
+
+* Install Byebug gem as default in Windows (mingw and x64_mingw) platform.
+
+ *Junichi Ito*
+
+* Make every Rails command work within engines.
+
+ *Sean Collins*, *Yuji Yaginuma*
+
* Don't generate HTML/ERB templates for scaffold controller with `--api` flag.
Fixes #27591.
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index f96432c89f..1a6aed7ce4 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -72,7 +72,7 @@ module Rails
# on one of the applications to create a copy of the application which shares
# the configuration.
#
- # If you decide to define rake tasks, runners, or initializers in an
+ # If you decide to define Rake tasks, runners, or initializers in an
# application other than +Rails.application+, then you must run them manually.
class Application < Engine
autoload :Bootstrap, "rails/application/bootstrap"
@@ -265,8 +265,8 @@ module Rails
end
end
- # If you try to define a set of rake tasks on the instance, these will get
- # passed up to the rake tasks defined on the application's class.
+ # If you try to define a set of Rake tasks on the instance, these will get
+ # passed up to the Rake tasks defined on the application's class.
def rake_tasks(&block)
self.class.rake_tasks(&block)
end
@@ -511,7 +511,7 @@ module Rails
def validate_secret_key_config! #:nodoc:
if secrets.secret_key_base.blank?
- ActiveSupport::Deprecation.warn "You didn't set `secret_key_base`. " +
+ ActiveSupport::Deprecation.warn "You didn't set `secret_key_base`. " \
"Read the upgrade documentation to learn more about this new config option."
if secrets.secret_token.blank?
diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb
index 11da271501..6102af3fff 100644
--- a/railties/lib/rails/application/bootstrap.rb
+++ b/railties/lib/rails/application/bootstrap.rb
@@ -48,8 +48,8 @@ INFO
logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDERR))
logger.level = ActiveSupport::Logger::WARN
logger.warn(
- "Rails Error: Unable to access log file. Please ensure that #{path} exists and is writable " +
- "(ie, make it writable for user and group: chmod 0664 #{path}). " +
+ "Rails Error: Unable to access log file. Please ensure that #{path} exists and is writable " \
+ "(ie, make it writable for user and group: chmod 0664 #{path}). " \
"The log level has been raised to WARN and the output directed to STDERR until the problem is fixed."
)
logger
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index a9cc244869..b0d33f87a3 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -3,8 +3,6 @@ require "active_support/file_update_checker"
require "rails/engine/configuration"
require "rails/source_annotation_extractor"
-require "active_support/deprecation"
-
module Rails
class Application
class Configuration < ::Rails::Engine::Configuration
diff --git a/railties/lib/rails/command.rb b/railties/lib/rails/command.rb
index ddb953543f..13f3b90b6d 100644
--- a/railties/lib/rails/command.rb
+++ b/railties/lib/rails/command.rb
@@ -15,6 +15,8 @@ module Rails
include Behavior
+ HELP_MAPPINGS = %w(-h -? --help)
+
class << self
def hidden_commands # :nodoc:
@hidden_commands ||= []
@@ -27,7 +29,7 @@ module Rails
# Receives a namespace, arguments and the behavior to invoke the command.
def invoke(namespace, args = [], **config)
namespace = namespace.to_s
- namespace = "help" if namespace.blank? || Thor::HELP_MAPPINGS.include?(namespace)
+ namespace = "help" if namespace.blank? || HELP_MAPPINGS.include?(namespace)
namespace = "version" if %w( -v --version ).include? namespace
if command = find_by_namespace(namespace)
@@ -37,7 +39,7 @@ module Rails
end
end
- # Rails finds namespaces similar to thor, it only adds one rule:
+ # Rails finds namespaces similar to Thor, it only adds one rule:
#
# Command names must end with "_command.rb". This is required because Rails
# looks in load paths and loads the command just before it's going to be used.
diff --git a/railties/lib/rails/command/actions.rb b/railties/lib/rails/command/actions.rb
index 31b656ec31..fb80e9d997 100644
--- a/railties/lib/rails/command/actions.rb
+++ b/railties/lib/rails/command/actions.rb
@@ -11,6 +11,11 @@ module Rails
if defined?(ENGINE_PATH)
def require_application_and_environment!
require ENGINE_PATH
+
+ if defined?(APP_PATH)
+ require APP_PATH
+ Rails.application.require_environment!
+ end
end
def load_tasks
diff --git a/railties/lib/rails/command/base.rb b/railties/lib/rails/command/base.rb
index 7ae190433a..1435792536 100644
--- a/railties/lib/rails/command/base.rb
+++ b/railties/lib/rails/command/base.rb
@@ -56,7 +56,7 @@ module Rails
end
def perform(command, args, config) # :nodoc:
- command = nil if Thor::HELP_MAPPINGS.include?(args.first)
+ command = nil if Rails::Command::HELP_MAPPINGS.include?(args.first)
dispatch(command, args.dup, nil, config)
end
diff --git a/railties/lib/rails/commands/help/USAGE b/railties/lib/rails/commands/help/USAGE
index 348f41861f..c5f8ab72bb 100644
--- a/railties/lib/rails/commands/help/USAGE
+++ b/railties/lib/rails/commands/help/USAGE
@@ -1,16 +1,3 @@
-Usage: bin/rails COMMAND [args] [options]
-<% if engine? %>
-The common Rails commands available for engines are:
- generate Generate new code (short-cut alias: "g")
- destroy Undo code generated with "generate" (short-cut alias: "d")
- test Run tests (short-cut alias: "t")
-
-All commands can be run with -h for more information.
-
-If you want to run any commands that need to be run in context
-of the application, like `bin/rails server` or `bin/rails console`,
-you should do it from the application's directory (typically test/dummy).
-<% else %>
The most common rails commands are:
generate Generate new code (short-cut alias: "g")
console Start the Rails console (short-cut alias: "c")
@@ -18,10 +5,11 @@ The most common rails commands are:
test Run tests (short-cut alias: "t")
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"
+<% end %>
All commands can be run with -h (or --help) for more information.
-<% end %>
In addition to those commands, there are:
diff --git a/railties/lib/rails/commands/server/server_command.rb b/railties/lib/rails/commands/server/server_command.rb
index 15c636103b..d58721f648 100644
--- a/railties/lib/rails/commands/server/server_command.rb
+++ b/railties/lib/rails/commands/server/server_command.rb
@@ -95,7 +95,7 @@ module Rails
module Command
class ServerCommand < Base # :nodoc:
- DEFAULT_PID_PATH = File.expand_path("tmp/pids/server.pid").freeze
+ 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
@@ -141,7 +141,7 @@ module Rails
config: options[:config],
environment: environment,
daemonize: options[:daemon],
- pid: options[:pid],
+ pid: pid,
caching: options["dev-caching"],
restart_cmd: restart_command
}
@@ -165,6 +165,10 @@ module Rails
"bin/rails server #{@server} #{@original_options.join(" ")}"
end
+ def pid
+ File.expand_path(options[:pid])
+ end
+
def self.banner(*)
"rails server [puma, thin etc] [options]"
end
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 12b4f06c27..13af6051ce 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -109,7 +109,7 @@ module Rails
#
# == Endpoint
#
- # An engine can also be a rack application. It can be useful if you have a rack application that
+ # An engine can also be a Rack application. It can be useful if you have a Rack application that
# you would like to wrap with +Engine+ and provide with some of the +Engine+'s features.
#
# To do that, use the +endpoint+ method:
@@ -128,7 +128,7 @@ module Rails
#
# == Middleware stack
#
- # As an engine can now be a rack endpoint, it can also have a middleware
+ # As an engine can now be a Rack endpoint, it can also have a middleware
# stack. The usage is exactly the same as in <tt>Application</tt>:
#
# module MyEngine
@@ -499,7 +499,7 @@ module Rails
paths["app/helpers"].existent
end
- # Returns the underlying rack application for this engine.
+ # Returns the underlying Rack application for this engine.
def app
@app || @app_build_lock.synchronize {
@app ||= begin
@@ -549,7 +549,7 @@ module Rails
load(seed_file) if seed_file
end
- # Add configured load paths to ruby load paths and remove duplicates.
+ # Add configured load paths to Ruby's load path, and remove duplicate entries.
initializer :set_load_path, before: :bootstrap_hook do
_all_load_paths.reverse_each do |path|
$LOAD_PATH.unshift(path) if File.directory?(path)
diff --git a/railties/lib/rails/engine/commands.rb b/railties/lib/rails/engine/commands.rb
index a23ae44b0b..b9ef63243a 100644
--- a/railties/lib/rails/engine/commands.rb
+++ b/railties/lib/rails/engine/commands.rb
@@ -1,12 +1,7 @@
-require "rails/command"
+unless defined?(APP_PATH)
+ if File.exist?(File.expand_path("test/dummy/config/application.rb", ENGINE_ROOT))
+ APP_PATH = File.expand_path("test/dummy/config/application", ENGINE_ROOT)
+ end
+end
-aliases = {
- "g" => "generate",
- "d" => "destroy",
- "t" => "test"
-}
-
-command = ARGV.shift
-command = aliases[command] || command
-
-Rails::Command.invoke command, ARGV
+require "rails/commands"
diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb
index e1980a42ad..99bda728ee 100644
--- a/railties/lib/rails/generators.rb
+++ b/railties/lib/rails/generators.rb
@@ -218,7 +218,7 @@ module Rails
[[ "rails", rails ]] + groups.sort.to_a
end
- # Rails finds namespaces similar to thor, it only adds one rule:
+ # Rails finds namespaces similar to Thor, it only adds one rule:
#
# Generators names must end with "_generator.rb". This is required because Rails
# looks in load paths and loads the generator just before it's going to be used.
diff --git a/railties/lib/rails/generators/actions/create_migration.rb b/railties/lib/rails/generators/actions/create_migration.rb
index f677e545e5..d06609e91e 100644
--- a/railties/lib/rails/generators/actions/create_migration.rb
+++ b/railties/lib/rails/generators/actions/create_migration.rb
@@ -54,8 +54,8 @@ module Rails
say_status :skip, :yellow
else
say_status :conflict, :red
- raise Error, "Another migration is already named #{migration_file_name}: " +
- "#{existing_migration}. Use --force to replace this migration " +
+ raise Error, "Another migration is already named #{migration_file_name}: " \
+ "#{existing_migration}. Use --force to replace this migration " \
"or --skip to ignore conflicted file."
end
end
diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb
index ba031d7b5d..a650c52626 100644
--- a/railties/lib/rails/generators/base.rb
+++ b/railties/lib/rails/generators/base.rb
@@ -256,8 +256,8 @@ module Rails
last = extract_last_module(nesting)
if last && last.const_defined?(last_name.camelize, false)
- raise Error, "The name '#{class_name}' is either already used in your application " <<
- "or reserved by Ruby on Rails. Please choose an alternative and run " <<
+ raise Error, "The name '#{class_name}' is either already used in your application " \
+ "or reserved by Ruby on Rails. Please choose an alternative and run " \
"this generator again."
end
end
diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb
index 8efdfdcb44..3cf923faf0 100644
--- a/railties/lib/rails/generators/rails/app/app_generator.rb
+++ b/railties/lib/rails/generators/rails/app/app_generator.rb
@@ -53,6 +53,12 @@ module Rails
template "gitignore", ".gitignore"
end
+ def version_control
+ if !options[:skip_git] && !options[:pretend]
+ run "git init"
+ end
+ end
+
def app
directory "app"
@@ -181,10 +187,6 @@ module Rails
def initialize(*args)
super
- unless app_path
- raise Error, "Application name should be provided in arguments. For details run: rails --help"
- end
-
if !options[:skip_active_record] && !DATABASES.include?(options[:database])
raise Error, "Invalid value for --database option. Supported for preconfiguration are: #{DATABASES.join(", ")}."
end
@@ -205,6 +207,7 @@ module Rails
build(:configru)
build(:gitignore) unless options[:skip_git]
build(:gemfile) unless options[:skip_gemfile]
+ build(:version_control)
end
def create_app_files
diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile
index f1015b16d5..24d2fa1284 100644
--- a/railties/lib/rails/generators/rails/app/templates/Gemfile
+++ b/railties/lib/rails/generators/rails/app/templates/Gemfile
@@ -31,7 +31,7 @@ end
<% if RUBY_ENGINE == 'ruby' -%>
group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
- gem 'byebug', platform: :mri
+ gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
end
group :development do
diff --git a/railties/lib/rails/generators/rails/app/templates/config/cable.yml b/railties/lib/rails/generators/rails/app/templates/config/cable.yml
index 0bbde6f74f..1da4913082 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/cable.yml
+++ b/railties/lib/rails/generators/rails/app/templates/config/cable.yml
@@ -7,3 +7,4 @@ test:
production:
adapter: redis
url: redis://localhost:6379/1
+ channel_prefix: <%= app_name %>_production
diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml
index c223d6bc62..a21555e573 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml
+++ b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml
@@ -1,4 +1,4 @@
-# SQL Server (2005 or higher recommended)
+# SQL Server (2012 or higher recommended)
#
# Install the adapters and driver
# gem install tiny_tds
@@ -8,29 +8,12 @@
# gem 'tiny_tds'
# gem 'activerecord-sqlserver-adapter'
#
-# You should make sure freetds is configured correctly first.
-# freetds.conf contains host/port/protocol_versions settings.
-# http://freetds.schemamania.org/userguide/freetdsconf.htm
-#
-# A typical Microsoft server
-# [mssql]
-# host = mssqlserver.yourdomain.com
-# port = 1433
-# tds version = 7.1
-
-# If you can connect with "tsql -S servername", your basic FreeTDS installation is working.
-# 'man tsql' for more info
-# Set timeout to a larger number if valid queries against a live db fail
-#
default: &default
adapter: sqlserver
encoding: utf8
- pool: <%%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
- reconnect: false
- username: <%= app_name %>
- password:
- timeout: 25
- dataserver: from_freetds.conf
+ username: sa
+ password: <%= ENV['SA_PASSWORD'] %>
+ host: localhost
development:
<<: *default
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
index 7deab5dbb1..4a39e43e57 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
@@ -88,7 +88,7 @@ Rails.application.configure do
if ENV["RAILS_LOG_TO_STDOUT"].present?
logger = ActiveSupport::Logger.new(STDOUT)
logger.formatter = config.log_formatter
- config.logger = ActiveSupport::TaggedLogging.new(logger)
+ config.logger = ActiveSupport::TaggedLogging.new(logger)
end
<%- unless options.skip_active_record? -%>
diff --git a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb
index 4cf4f8cd9a..49259f32c8 100644
--- a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb
+++ b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb
@@ -186,7 +186,7 @@ task default: :test
desc: "Skip gemspec file"
class_option :skip_gemfile_entry, type: :boolean, default: false,
- desc: "If creating plugin in application's directory " +
+ desc: "If creating plugin in application's directory " \
"skip adding entry to Gemfile"
class_option :api, type: :boolean, default: false,
@@ -195,10 +195,6 @@ task default: :test
def initialize(*args)
@dummy_path = nil
super
-
- unless plugin_path
- raise Error, "Plugin name should be provided in arguments. For details run: rails plugin new --help"
- end
end
public_task :set_default_accessors!
@@ -415,7 +411,6 @@ task default: :test
require 'rake/testtask'
Rake::TestTask.new(:test) do |t|
- t.libs << 'lib'
t.libs << 'test'
t.pattern = 'test/**/*_test.rb'
t.verbose = false
diff --git a/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt b/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt
index 56e7925c6b..c03d9953d4 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt
+++ b/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt
@@ -3,6 +3,7 @@
ENGINE_ROOT = File.expand_path('../..', __FILE__)
ENGINE_PATH = File.expand_path('../../lib/<%= namespaced_name -%>/engine', __FILE__)
+APP_PATH = File.expand_path('../../<%= dummy_path -%>/config/application', __FILE__)
# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
diff --git a/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb b/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb
index 4cc1e2d0fd..cf97c22160 100644
--- a/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb
+++ b/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb
@@ -20,7 +20,6 @@ module Rails
template template_file, File.join("app/controllers", controller_class_path, "#{controller_file_name}_controller.rb")
end
-
hook_for :template_engine, as: :scaffold do |template_engine|
invoke template_engine unless options.api?
end
diff --git a/railties/lib/rails/generators/resource_helpers.rb b/railties/lib/rails/generators/resource_helpers.rb
index 978b053308..e7cb722473 100644
--- a/railties/lib/rails/generators/resource_helpers.rb
+++ b/railties/lib/rails/generators/resource_helpers.rb
@@ -59,7 +59,7 @@ module Rails
end
# Loads the ORM::Generators::ActiveModel class. This class is responsible
- # to tell scaffold entities how to generate an specific method for the
+ # to tell scaffold entities how to generate a specific method for the
# ORM. Check Rails::Generators::ActiveModel for more information.
def orm_class
@orm_class ||= begin
diff --git a/railties/lib/rails/info.rb b/railties/lib/rails/info.rb
index 5d4acd6f6b..fc064dac32 100644
--- a/railties/lib/rails/info.rb
+++ b/railties/lib/rails/info.rb
@@ -1,9 +1,9 @@
require "cgi"
module Rails
- # This module helps build the runtime properties used to display in the
- # Rails::InfoController responses. Including the active Rails version, Ruby
- # version, Rack version, and so on.
+ # This module helps build the runtime properties that are displayed in
+ # Rails::InfoController responses. These include the active Rails version,
+ # Ruby version, Rack version, and so on.
module Info
mattr_accessor :properties
class << (@@properties = [])
diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb
index 10925de8b2..af3be10a31 100644
--- a/railties/lib/rails/paths.rb
+++ b/railties/lib/rails/paths.rb
@@ -2,12 +2,12 @@ module Rails
module Paths
# This object is an extended hash that behaves as root of the <tt>Rails::Paths</tt> system.
# It allows you to collect information about how you want to structure your application
- # paths by a Hash like API. It requires you to give a physical path on initialization.
+ # paths through a Hash-like API. It requires you to give a physical path on initialization.
#
# root = Root.new "/rails"
# root.add "app/controllers", eager_load: true
#
- # The command above creates a new root object and adds "app/controllers" as a path.
+ # The above command creates a new root object and adds "app/controllers" as a path.
# This means we can get a <tt>Rails::Paths::Path</tt> object back like below:
#
# path = root["app/controllers"]
diff --git a/railties/lib/rails/source_annotation_extractor.rb b/railties/lib/rails/source_annotation_extractor.rb
index 3a48c4c496..e9088c44ce 100644
--- a/railties/lib/rails/source_annotation_extractor.rb
+++ b/railties/lib/rails/source_annotation_extractor.rb
@@ -13,7 +13,7 @@
# start with the tag optionally followed by a colon. Everything up to the end
# of the line (or closing ERB comment tag) is considered to be their text.
class SourceAnnotationExtractor
- class Annotation < Struct.new(:line, :tag, :text)
+ Annotation = Struct.new(:line, :tag, :text) do
def self.directories
@@directories ||= %w(app config db lib test) + (ENV["SOURCE_ANNOTATION_DIRECTORIES"] || "").split(",")
end
diff --git a/railties/lib/rails/tasks.rb b/railties/lib/rails/tasks.rb
index 48675b3845..c0a50e5bda 100644
--- a/railties/lib/rails/tasks.rb
+++ b/railties/lib/rails/tasks.rb
@@ -12,6 +12,7 @@ require "rake"
restart
routes
tmp
+ yarn
).tap { |arr|
arr << "statistics" if Rake.application.current_scope.empty?
}.each do |task|
diff --git a/railties/lib/rails/tasks/framework.rake b/railties/lib/rails/tasks/framework.rake
index d42d001b1a..f5586b53f0 100644
--- a/railties/lib/rails/tasks/framework.rake
+++ b/railties/lib/rails/tasks/framework.rake
@@ -1,5 +1,3 @@
-require "active_support/deprecation"
-
namespace :app do
desc "Update configs and some other initially generated files (or use just update:configs or update:bin)"
task update: [ "update:configs", "update:bin", "update:upgrade_guide_info" ]
diff --git a/railties/lib/rails/tasks/routes.rake b/railties/lib/rails/tasks/routes.rake
index 04daaf4a83..215fb2ceb5 100644
--- a/railties/lib/rails/tasks/routes.rake
+++ b/railties/lib/rails/tasks/routes.rake
@@ -1,5 +1,3 @@
-require "active_support/deprecation"
-require "active_support/core_ext/string/strip" # for strip_heredoc
require "optparse"
desc "Print out all defined routes in match order, with names. Target specific controller with -c option, or grep routes using -g option"
diff --git a/railties/lib/rails/tasks/yarn.rake b/railties/lib/rails/tasks/yarn.rake
new file mode 100644
index 0000000000..2097b7ffef
--- /dev/null
+++ b/railties/lib/rails/tasks/yarn.rake
@@ -0,0 +1,11 @@
+namespace :yarn do
+ desc "Install all JavaScript dependencies as specified via Yarn"
+ task :install do
+ system('./bin/yarn install --no-progress')
+ end
+end
+
+# Run Yarn prior to Sprockets assets precompilation, so dependencies are available for use.
+if Rake::Task.task_defined?("assets:precompile")
+ Rake::Task["assets:precompile"].enhance [ "yarn:install" ]
+end
diff --git a/railties/lib/rails/test_unit/minitest_plugin.rb b/railties/lib/rails/test_unit/minitest_plugin.rb
index 6e196a32ab..e3c70b0b3d 100644
--- a/railties/lib/rails/test_unit/minitest_plugin.rb
+++ b/railties/lib/rails/test_unit/minitest_plugin.rb
@@ -52,6 +52,11 @@ module Minitest
options[:color] = value
end
+ opts.on("-w", "--warnings",
+ "Enable ruby warnings") do
+ $VERBOSE = true
+ end
+
options[:color] = true
options[:output_inline] = true
options[:patterns] = defined?(@rake_patterns) ? @rake_patterns : opts.order!
diff --git a/railties/test/abstract_unit.rb b/railties/test/abstract_unit.rb
index fd1e1b9662..e4b2d0457d 100644
--- a/railties/test/abstract_unit.rb
+++ b/railties/test/abstract_unit.rb
@@ -17,15 +17,15 @@ module TestApp
end
end
-# Skips the current run on Rubinius using Minitest::Assertions#skip
-def rubinius_skip(message = "")
- skip message if RUBY_ENGINE == "rbx"
-end
-# Skips the current run on JRuby using Minitest::Assertions#skip
-def jruby_skip(message = "")
- skip message if defined?(JRUBY_VERSION)
-end
-
class ActiveSupport::TestCase
include ActiveSupport::Testing::Stream
+
+ # Skips the current run on Rubinius using Minitest::Assertions#skip
+ private def rubinius_skip(message = "")
+ skip message if RUBY_ENGINE == "rbx"
+ end
+ # Skips the current run on JRuby using Minitest::Assertions#skip
+ private def jruby_skip(message = "")
+ skip message if defined?(JRUBY_VERSION)
+ end
end
diff --git a/railties/test/application/bin_setup_test.rb b/railties/test/application/bin_setup_test.rb
index f62313f3e1..0fb995900f 100644
--- a/railties/test/application/bin_setup_test.rb
+++ b/railties/test/application/bin_setup_test.rb
@@ -38,9 +38,12 @@ module ApplicationTests
app_file "db/schema.rb", ""
output = `bin/setup 2>&1`
+
+ # Ignore line that's only output by Bundler < 1.14
+ output.sub!(/^Resolving dependencies\.\.\.\n/, "")
+
assert_equal(<<-OUTPUT, output)
== Installing dependencies ==
-Resolving dependencies...
The Gemfile's dependencies are satisfied
== Preparing database ==
diff --git a/railties/test/application/configuration/custom_test.rb b/railties/test/application/configuration/custom_test.rb
index 3c675eec71..8360b7bf4b 100644
--- a/railties/test/application/configuration/custom_test.rb
+++ b/railties/test/application/configuration/custom_test.rb
@@ -10,7 +10,6 @@ module ApplicationTests
def teardown
teardown_app
- FileUtils.rm_rf(new_app) if File.directory?(new_app)
end
test "access custom configuration point" do
@@ -30,28 +29,14 @@ module ApplicationTests
assert_equal false, x.hyper_debugger
assert_nil x.nil_debugger
assert_nil x.i_do_not_exist.zomg
- end
- test "custom configuration responds to all messages" do
- x = Rails.configuration.x
+ # test that custom configuration responds to all messages
assert_equal true, x.respond_to?(:i_do_not_exist)
assert_kind_of Method, x.method(:i_do_not_exist)
assert_kind_of ActiveSupport::OrderedOptions, x.i_do_not_exist
end
private
- def new_app
- File.expand_path("#{app_path}/../new_app")
- end
-
- def copy_app
- FileUtils.cp_r(app_path, new_app)
- end
-
- def app
- @app ||= Rails.application
- end
-
def require_environment
require "#{app_path}/config/environment"
end
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index 01a9807b6b..824831155e 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -623,9 +623,10 @@ module ApplicationTests
assert_equal "", app.config.secret_token
assert_nil app.secrets.secret_key_base
- assert_raise ArgumentError, /\AA secret is required/ do
+ e = assert_raise ArgumentError do
app.key_generator
end
+ assert_match(/\AA secret is required/, e.message)
end
test "that nested keys are symbolized the same as parents for hashes more than one level deep" do
@@ -1184,11 +1185,12 @@ module ApplicationTests
end
test "config.session_store with :active_record_store without activerecord-session_store gem" do
- assert_raise RuntimeError, /activerecord-session_store/ do
+ e = assert_raise RuntimeError do
make_basic_app do |application|
application.config.session_store :active_record_store
end
end
+ assert_match(/activerecord-session_store/, e.message)
end
test "default session store initializer does not overwrite the user defined session store even if it is disabled" do
diff --git a/railties/test/application/rake/dbs_test.rb b/railties/test/application/rake/dbs_test.rb
index 51db634b75..8bbae64d5e 100644
--- a/railties/test/application/rake/dbs_test.rb
+++ b/railties/test/application/rake/dbs_test.rb
@@ -175,7 +175,7 @@ module ApplicationTests
`bin/rails generate model book title:string;
bin/rails db:migrate db:structure:dump`
structure_dump = File.read("db/structure.sql")
- assert_match(/CREATE TABLE \"books\"/, structure_dump)
+ assert_match(/CREATE TABLE (?:IF NOT EXISTS )?\"books\"/, structure_dump)
`bin/rails environment db:drop db:structure:load`
assert_match expected_database, ActiveRecord::Base.connection_config[:database]
require "#{app_path}/app/models/book"
@@ -203,7 +203,7 @@ module ApplicationTests
stderr_output = capture(:stderr) { `bin/rails db:structure:dump` }
assert_empty stderr_output
structure_dump = File.read("db/structure.sql")
- assert_match(/CREATE TABLE \"posts\"/, structure_dump)
+ assert_match(/CREATE TABLE (?:IF NOT EXISTS )?\"posts\"/, structure_dump)
end
end
diff --git a/railties/test/application/test_runner_test.rb b/railties/test/application/test_runner_test.rb
index 0939587960..4e36d126fc 100644
--- a/railties/test/application/test_runner_test.rb
+++ b/railties/test/application/test_runner_test.rb
@@ -536,6 +536,17 @@ module ApplicationTests
assert_match "seed=1234", output, "passing TEST= should run selected test"
end
+ def test_warnings_option
+ app_file "test/models/warnings_test.rb", <<-RUBY
+ require 'test_helper'
+ def test_warnings
+ a = 1
+ end
+ RUBY
+ assert_match(/warning: assigned but unused variable/,
+ capture(:stderr) { run_test_command("test/models/warnings_test.rb -w") })
+ end
+
private
def run_test_command(arguments = "test/unit/test_test.rb")
Dir.chdir(app_path) { `bin/rails t #{arguments}` }
diff --git a/railties/test/commands/server_test.rb b/railties/test/commands/server_test.rb
index 527529aa52..e3dfc3e82b 100644
--- a/railties/test/commands/server_test.rb
+++ b/railties/test/commands/server_test.rb
@@ -122,11 +122,11 @@ class Rails::ServerTest < ActiveSupport::TestCase
end
def test_default_options
- old_default_options = parse_arguments
+ server = Rails::Server.new
+ old_default_options = server.default_options
Dir.chdir("..") do
- default_options = parse_arguments
- assert_equal old_default_options, default_options
+ assert_equal old_default_options, server.default_options
end
end
diff --git a/railties/test/engine/commands_tasks_test.rb b/railties/test/engine/commands_tasks_test.rb
deleted file mode 100644
index 817175b9ef..0000000000
--- a/railties/test/engine/commands_tasks_test.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require "abstract_unit"
-
-class Rails::Engine::CommandsTasksTest < ActiveSupport::TestCase
- def setup
- @destination_root = Dir.mktmpdir("bukkits")
- Dir.chdir(@destination_root) { `bundle exec rails plugin new bukkits --mountable` }
- end
-
- def teardown
- FileUtils.rm_rf(@destination_root)
- end
-
- def test_help_command_work_inside_engine
- output = capture(:stderr) do
- Dir.chdir(plugin_path) { `bin/rails --help` }
- end
- assert_no_match "NameError", output
- end
-
- private
- def plugin_path
- "#{@destination_root}/bukkits"
- end
-end
diff --git a/railties/test/engine/commands_test.rb b/railties/test/engine/commands_test.rb
new file mode 100644
index 0000000000..b1c937143f
--- /dev/null
+++ b/railties/test/engine/commands_test.rb
@@ -0,0 +1,96 @@
+require "abstract_unit"
+begin
+ require "pty"
+rescue LoadError
+end
+
+class Rails::Engine::CommandsTest < ActiveSupport::TestCase
+ def setup
+ @destination_root = Dir.mktmpdir("bukkits")
+ Dir.chdir(@destination_root) { `bundle exec rails plugin new bukkits --mountable` }
+ end
+
+ def teardown
+ FileUtils.rm_rf(@destination_root)
+ end
+
+ def test_help_command_work_inside_engine
+ output = capture(:stderr) do
+ Dir.chdir(plugin_path) { `bin/rails --help` }
+ end
+ assert_no_match "NameError", output
+ end
+
+ def test_runner_command_work_inside_engine
+ output = capture(:stdout) do
+ Dir.chdir(plugin_path) { system("bin/rails runner 'puts Rails.env'") }
+ end
+
+ assert_equal "test", output.strip
+ end
+
+ def test_console_command_work_inside_engine
+ skip "PTY unavailable" unless available_pty?
+
+ master, slave = PTY.open
+ spawn_command("console", slave)
+ assert_output(">", master)
+ ensure
+ master.puts "quit"
+ end
+
+ def test_dbconsole_command_work_inside_engine
+ skip "PTY unavailable" unless available_pty?
+
+ master, slave = PTY.open
+ spawn_command("dbconsole", slave)
+ assert_output("sqlite>", master)
+ ensure
+ master.puts ".exit"
+ end
+
+ def test_server_command_work_inside_engine
+ skip "PTY unavailable" unless available_pty?
+
+ master, slave = PTY.open
+ pid = spawn_command("server", slave)
+ assert_output("Listening on", master)
+ ensure
+ kill(pid)
+ end
+
+ private
+ def plugin_path
+ "#{@destination_root}/bukkits"
+ end
+
+ def assert_output(expected, io, timeout = 10)
+ timeout = Time.now + timeout
+
+ output = ""
+ until output.include?(expected) || Time.now > timeout
+ if IO.select([io], [], [], 0.1)
+ output << io.read(1)
+ end
+ end
+
+ assert_includes output, expected, "#{expected.inspect} expected, but got:\n\n#{output}"
+ end
+
+ def spawn_command(command, fd)
+ Process.spawn(
+ "#{plugin_path}/bin/rails #{command}",
+ in: fd, out: fd, err: fd
+ )
+ end
+
+ def available_pty?
+ defined?(PTY) && PTY.respond_to?(:open)
+ end
+
+ def kill(pid)
+ Process.kill("TERM", pid)
+ Process.wait(pid)
+ rescue Errno::ESRCH
+ end
+end
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index 20de2258c5..ee996dc9d6 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -592,6 +592,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
def test_pretend_option
output = run_generator [File.join(destination_root, "myapp"), "--pretend"]
assert_no_match(/run bundle install/, output)
+ assert_no_match(/run git init/, output)
end
def test_application_name_with_spaces
@@ -731,6 +732,11 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
end
+ def test_version_control_initializes_git_repo
+ run_generator [destination_root]
+ assert_directory ".git"
+ end
+
def test_create_keeps
run_generator
folders_with_keep = %w(
@@ -777,7 +783,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
template
end
- sequence = ["install", "exec spring binstub --all", "echo ran after_bundle"]
+ sequence = ["git init", "install", "exec spring binstub --all", "echo ran after_bundle"]
@sequence_step ||= 0
ensure_bundler_first = -> command do
assert_equal sequence[@sequence_step], command, "commands should be called in sequence #{sequence}"
@@ -792,7 +798,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
end
- assert_equal 3, @sequence_step
+ assert_equal 4, @sequence_step
end
private
diff --git a/railties/test/generators/migration_generator_test.rb b/railties/test/generators/migration_generator_test.rb
index 6e1d1b70a9..f46278cefe 100644
--- a/railties/test/generators/migration_generator_test.rb
+++ b/railties/test/generators/migration_generator_test.rb
@@ -309,6 +309,17 @@ class MigrationGeneratorTest < Rails::Generators::TestCase
end
end
+ def test_add_migration_to_configured_path
+ old_paths = Rails.application.config.paths["db/migrate"]
+ Rails.application.config.paths.add "db/migrate", with: "db2/migrate"
+
+ migration = "migration_in_custom_path"
+ run_generator [migration]
+ assert_migration "db2/migrate/#{migration}.rb", /.*/
+ ensure
+ Rails.application.config.paths["db/migrate"] = old_paths
+ end
+
private
def with_singular_table_name
diff --git a/railties/test/generators/model_generator_test.rb b/railties/test/generators/model_generator_test.rb
index 2b9f3ed7f2..99490af3a9 100644
--- a/railties/test/generators/model_generator_test.rb
+++ b/railties/test/generators/model_generator_test.rb
@@ -220,6 +220,17 @@ class ModelGeneratorTest < Rails::Generators::TestCase
ActiveRecord::Base.timestamped_migrations = true
end
+ def test_migration_with_configured_path
+ old_paths = Rails.application.config.paths["db/migrate"]
+ Rails.application.config.paths.add "db/migrate", with: "db2/migrate"
+
+ run_generator
+
+ assert_migration "db2/migrate/create_accounts.rb", /class CreateAccounts < ActiveRecord::Migration\[[0-9.]+\]/
+ ensure
+ Rails.application.config.paths["db/migrate"] = old_paths
+ end
+
def test_model_with_references_attribute_generates_belongs_to_associations
run_generator ["product", "name:string", "supplier:references"]
assert_file "app/models/product.rb", /belongs_to :supplier/
diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb
index 9921a80342..ddfbc1a698 100644
--- a/railties/test/generators/plugin_generator_test.rb
+++ b/railties/test/generators/plugin_generator_test.rb
@@ -421,6 +421,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase
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", /require 'rails\/all'/
assert_file "bin/rails", /require 'rails\/engine\/commands'/
end
diff --git a/railties/test/generators/plugin_test_runner_test.rb b/railties/test/generators/plugin_test_runner_test.rb
index 0bdf3b2726..0bdd2a77d2 100644
--- a/railties/test/generators/plugin_test_runner_test.rb
+++ b/railties/test/generators/plugin_test_runner_test.rb
@@ -92,6 +92,17 @@ class PluginTestRunnerTest < ActiveSupport::TestCase
assert_equal 1, result.scan(/1 runs, 1 assertions, 0 failures/).length
end
+ def test_warnings_option
+ plugin_file "test/models/warnings_test.rb", <<-RUBY
+ require 'test_helper'
+ def test_warnings
+ a = 1
+ end
+ RUBY
+ assert_match(/warning: assigned but unused variable/,
+ capture(:stderr) { run_test_command("test/models/warnings_test.rb -w") })
+ end
+
private
def plugin_path
"#{@destination_root}/bukkits"
diff --git a/railties/test/generators/shared_generator_tests.rb b/railties/test/generators/shared_generator_tests.rb
index 08b0e34fe2..cc9d3629e9 100644
--- a/railties/test/generators/shared_generator_tests.rb
+++ b/railties/test/generators/shared_generator_tests.rb
@@ -109,6 +109,7 @@ module SharedGeneratorTests
def test_skip_git
run_generator [destination_root, "--skip-git", "--full"]
assert_no_file(".gitignore")
+ assert_no_directory(".git")
end
def test_skip_keeps
diff --git a/railties/test/rack_logger_test.rb b/railties/test/rack_logger_test.rb
index 7dd91a2465..33b4bc6a3a 100644
--- a/railties/test/rack_logger_test.rb
+++ b/railties/test/rack_logger_test.rb
@@ -20,7 +20,7 @@ module Rails
def development?; false; end
end
- class Subscriber < Struct.new(:starts, :finishes)
+ Subscriber = Struct.new(:starts, :finishes) do
def initialize(starts = [], finishes = [])
super
end