aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml7
-rw-r--r--Gemfile8
-rw-r--r--Gemfile.lock21
-rw-r--r--actionmailer/actionmailer.gemspec2
-rw-r--r--actionmailer/lib/action_mailer/base.rb2
-rw-r--r--actionmailer/test/abstract_unit.rb5
-rw-r--r--actionpack/CHANGELOG.md46
-rw-r--r--actionpack/Rakefile5
-rw-r--r--actionpack/actionpack.gemspec4
-rw-r--r--actionpack/lib/action_controller/metal/conditional_get.rb2
-rw-r--r--actionpack/lib/action_controller/metal/head.rb2
-rw-r--r--actionpack/lib/action_controller/metal/helpers.rb2
-rw-r--r--actionpack/lib/action_controller/metal/http_authentication.rb2
-rw-r--r--actionpack/lib/action_controller/metal/mime_responds.rb13
-rw-r--r--actionpack/lib/action_controller/metal/params_wrapper.rb2
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb2
-rw-r--r--actionpack/lib/action_controller/metal/url_for.rb5
-rw-r--r--actionpack/lib/action_controller/test_case.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/filter_redirect.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/mime_negotiation.rb16
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb4
-rw-r--r--actionpack/lib/action_dispatch/http/url.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/public_exceptions.rb4
-rw-r--r--actionpack/lib/action_dispatch/middleware/static.rb3
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb31
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions.rb2
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb39
-rw-r--r--actionpack/lib/action_dispatch/testing/test_response.rb2
-rw-r--r--actionpack/test/abstract_unit.rb5
-rw-r--r--actionpack/test/controller/integration_test.rb29
-rw-r--r--actionpack/test/controller/new_base/render_template_test.rb6
-rw-r--r--actionpack/test/controller/parameters/always_permitted_parameters_test.rb9
-rw-r--r--actionpack/test/controller/redirect_test.rb4
-rw-r--r--actionpack/test/controller/render_test.rb11
-rw-r--r--actionpack/test/controller/request/test_request_test.rb8
-rw-r--r--actionpack/test/controller/show_exceptions_test.rb4
-rw-r--r--actionpack/test/controller/url_for_test.rb18
-rw-r--r--actionpack/test/dispatch/request_test.rb53
-rw-r--r--actionpack/test/dispatch/response_test.rb4
-rw-r--r--actionpack/test/dispatch/routing_test.rb6
-rw-r--r--actionpack/test/dispatch/session/cache_store_test.rb2
-rw-r--r--actionpack/test/dispatch/session/cookie_store_test.rb4
-rw-r--r--actionpack/test/dispatch/session/mem_cache_store_test.rb2
-rw-r--r--actionpack/test/dispatch/static_test.rb10
-rw-r--r--actionview/CHANGELOG.md15
-rw-r--r--actionview/Rakefile2
-rw-r--r--actionview/actionview.gemspec4
-rw-r--r--actionview/lib/action_view/helpers/capture_helper.rb4
-rw-r--r--actionview/lib/action_view/helpers/debug_helper.rb2
-rw-r--r--actionview/lib/action_view/helpers/form_helper.rb6
-rw-r--r--actionview/lib/action_view/helpers/form_options_helper.rb40
-rw-r--r--actionview/lib/action_view/helpers/javascript_helper.rb2
-rw-r--r--actionview/lib/action_view/helpers/number_helper.rb16
-rw-r--r--actionview/lib/action_view/helpers/sanitize_helper.rb2
-rw-r--r--actionview/lib/action_view/helpers/text_helper.rb7
-rw-r--r--actionview/lib/action_view/helpers/translation_helper.rb2
-rw-r--r--actionview/lib/action_view/helpers/url_helper.rb35
-rw-r--r--actionview/lib/action_view/layouts.rb2
-rw-r--r--actionview/lib/action_view/renderer/partial_renderer.rb18
-rw-r--r--actionview/lib/action_view/renderer/renderer.rb2
-rw-r--r--actionview/lib/action_view/renderer/template_renderer.rb2
-rw-r--r--actionview/test/abstract_unit.rb62
-rw-r--r--actionview/test/actionpack/abstract/views/abstract_controller/testing/me5/index.erb1
-rw-r--r--actionview/test/active_record_unit.rb2
-rw-r--r--actionview/test/activerecord/debug_helper_test.rb6
-rw-r--r--actionview/test/fixtures/layouts/streaming_with_capture.erb6
-rw-r--r--actionview/test/fixtures/multipart/bracketed_utf8_param5
-rw-r--r--actionview/test/fixtures/multipart/single_utf8_param5
-rw-r--r--actionview/test/template/asset_tag_helper_test.rb1
-rw-r--r--actionview/test/template/form_tag_helper_test.rb8
-rw-r--r--actionview/test/template/javascript_helper_test.rb9
-rw-r--r--actionview/test/template/number_helper_test.rb4
-rw-r--r--actionview/test/template/sanitize_helper_test.rb4
-rw-r--r--actionview/test/template/streaming_render_test.rb4
-rw-r--r--actionview/test/template/translation_helper_test.rb5
-rw-r--r--activejob/CHANGELOG.md4
-rw-r--r--activejob/activejob.gemspec2
-rw-r--r--activejob/lib/active_job/logging.rb2
-rw-r--r--activejob/lib/active_job/queue_adapter.rb50
-rw-r--r--activejob/lib/active_job/queue_adapters.rb9
-rw-r--r--activejob/lib/active_job/queue_adapters/backburner_adapter.rb14
-rw-r--r--activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb12
-rw-r--r--activejob/lib/active_job/queue_adapters/inline_adapter.rb12
-rw-r--r--activejob/lib/active_job/queue_adapters/qu_adapter.rb16
-rw-r--r--activejob/lib/active_job/queue_adapters/que_adapter.rb12
-rw-r--r--activejob/lib/active_job/queue_adapters/queue_classic_adapter.rb38
-rw-r--r--activejob/lib/active_job/queue_adapters/resque_adapter.rb18
-rw-r--r--activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb30
-rw-r--r--activejob/lib/active_job/queue_adapters/sneakers_adapter.rb20
-rw-r--r--activejob/lib/active_job/queue_adapters/sucker_punch_adapter.rb12
-rw-r--r--activejob/lib/active_job/queue_adapters/test_adapter.rb68
-rw-r--r--activejob/lib/active_job/test_helper.rb43
-rw-r--r--activejob/lib/rails/generators/job/job_generator.rb1
-rw-r--r--activejob/lib/rails/generators/job/templates/job.rb2
-rw-r--r--activejob/test/cases/adapter_test.rb2
-rw-r--r--activejob/test/cases/logging_test.rb2
-rw-r--r--activejob/test/cases/queue_adapter_test.rb56
-rw-r--r--activejob/test/cases/test_case_test.rb11
-rw-r--r--activejob/test/cases/test_helper_test.rb8
-rw-r--r--activejob/test/integration/queuing_test.rb13
-rw-r--r--activejob/test/support/integration/adapters/qu.rb2
-rw-r--r--activejob/test/support/integration/adapters/queue_classic.rb4
-rw-r--r--activejob/test/support/integration/test_case_helpers.rb6
-rw-r--r--activemodel/CHANGELOG.md5
-rw-r--r--activemodel/Rakefile2
-rw-r--r--activemodel/activemodel.gemspec2
-rw-r--r--activemodel/lib/active_model/errors.rb43
-rw-r--r--activemodel/lib/active_model/secure_password.rb2
-rw-r--r--activemodel/lib/active_model/validations/length.rb38
-rw-r--r--activemodel/test/cases/errors_test.rb12
-rw-r--r--activemodel/test/cases/helper.rb5
-rw-r--r--activemodel/test/cases/validations/length_validation_test.rb20
-rw-r--r--activerecord/CHANGELOG.md150
-rw-r--r--activerecord/Rakefile2
-rw-r--r--activerecord/activerecord.gemspec2
-rw-r--r--activerecord/lib/active_record.rb1
-rw-r--r--activerecord/lib/active_record/associations.rb32
-rw-r--r--activerecord/lib/active_record/associations/association.rb4
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb7
-rw-r--r--activerecord/lib/active_record/associations/collection_proxy.rb3
-rw-r--r--activerecord/lib/active_record/associations/singular_association.rb3
-rw-r--r--activerecord/lib/active_record/associations/through_association.rb2
-rw-r--r--activerecord/lib/active_record/attributes.rb20
-rw-r--r--activerecord/lib/active_record/base.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb16
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/transaction.rb45
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb15
-rw-r--r--activerecord/lib/active_record/connection_adapters/column.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql_adapter.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/array_parser.rb93
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/column.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb58
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb22
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/referential_integrity.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb67
-rw-r--r--activerecord/lib/active_record/core.rb38
-rw-r--r--activerecord/lib/active_record/fixtures.rb28
-rw-r--r--activerecord/lib/active_record/legacy_yaml_adapter.rb46
-rw-r--r--activerecord/lib/active_record/locking/pessimistic.rb2
-rw-r--r--activerecord/lib/active_record/null_relation.rb4
-rw-r--r--activerecord/lib/active_record/railtie.rb11
-rw-r--r--activerecord/lib/active_record/reflection.rb19
-rw-r--r--activerecord/lib/active_record/relation.rb4
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb2
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb6
-rw-r--r--activerecord/lib/active_record/relation/record_fetch_warning.rb49
-rw-r--r--activerecord/lib/active_record/scoping.rb11
-rw-r--r--activerecord/lib/active_record/scoping/default.rb5
-rw-r--r--activerecord/lib/active_record/scoping/named.rb11
-rw-r--r--activerecord/lib/active_record/tasks/database_tasks.rb2
-rw-r--r--activerecord/lib/active_record/tasks/postgresql_database_tasks.rb12
-rw-r--r--activerecord/lib/active_record/transactions.rb12
-rw-r--r--activerecord/lib/active_record/type/hash_lookup_type_map.rb10
-rw-r--r--activerecord/lib/active_record/type/serialized.rb8
-rw-r--r--activerecord/lib/active_record/type/value.rb6
-rw-r--r--activerecord/test/cases/adapter_test.rb2
-rw-r--r--activerecord/test/cases/adapters/mysql/consistency_test.rb2
-rw-r--r--activerecord/test/cases/adapters/mysql/reserved_word_test.rb2
-rw-r--r--activerecord/test/cases/adapters/mysql/unsigned_type_test.rb2
-rw-r--r--activerecord/test/cases/adapters/mysql2/boolean_test.rb2
-rw-r--r--activerecord/test/cases/adapters/mysql2/reserved_word_test.rb2
-rw-r--r--activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/array_test.rb1
-rw-r--r--activerecord/test/cases/adapters/postgresql/datatype_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/enum_test.rb8
-rw-r--r--activerecord/test/cases/adapters/postgresql/extension_migration_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/hstore_test.rb1
-rw-r--r--activerecord/test/cases/adapters/postgresql/infinity_test.rb9
-rw-r--r--activerecord/test/cases/adapters/postgresql/json_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/numbers_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb16
-rw-r--r--activerecord/test/cases/adapters/postgresql/range_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb28
-rw-r--r--activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/schema_test.rb8
-rw-r--r--activerecord/test/cases/adapters/postgresql/serial_test.rb60
-rw-r--r--activerecord/test/cases/adapters/postgresql/timestamp_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/uuid_test.rb20
-rw-r--r--activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb2
-rw-r--r--activerecord/test/cases/ar_schema_test.rb2
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb12
-rw-r--r--activerecord/test/cases/associations/has_one_associations_test.rb2
-rw-r--r--activerecord/test/cases/associations/join_model_test.rb2
-rw-r--r--activerecord/test/cases/associations/required_test.rb2
-rw-r--r--activerecord/test/cases/autosave_association_test.rb26
-rw-r--r--activerecord/test/cases/base_test.rb50
-rw-r--r--activerecord/test/cases/batches_test.rb5
-rw-r--r--activerecord/test/cases/calculations_test.rb11
-rw-r--r--activerecord/test/cases/date_time_precision_test.rb2
-rw-r--r--activerecord/test/cases/defaults_test.rb6
-rw-r--r--activerecord/test/cases/disconnected_test.rb2
-rw-r--r--activerecord/test/cases/enum_test.rb14
-rw-r--r--activerecord/test/cases/finder_test.rb1
-rw-r--r--activerecord/test/cases/fixtures_test.rb20
-rw-r--r--activerecord/test/cases/helper.rb7
-rw-r--r--activerecord/test/cases/hot_compatibility_test.rb2
-rw-r--r--activerecord/test/cases/invalid_connection_test.rb2
-rw-r--r--activerecord/test/cases/locking_test.rb6
-rw-r--r--activerecord/test/cases/migration/change_schema_test.rb2
-rw-r--r--activerecord/test/cases/migration/column_attributes_test.rb2
-rw-r--r--activerecord/test/cases/migration/columns_test.rb2
-rw-r--r--activerecord/test/cases/migration/logger_test.rb2
-rw-r--r--activerecord/test/cases/migration/references_statements_test.rb2
-rw-r--r--activerecord/test/cases/migration/rename_table_test.rb2
-rw-r--r--activerecord/test/cases/migration_test.rb2
-rw-r--r--activerecord/test/cases/migrator_test.rb2
-rw-r--r--activerecord/test/cases/mixin_test.rb2
-rw-r--r--activerecord/test/cases/modules_test.rb3
-rw-r--r--activerecord/test/cases/multiple_db_test.rb2
-rw-r--r--activerecord/test/cases/nested_attributes_test.rb4
-rw-r--r--activerecord/test/cases/persistence_test.rb8
-rw-r--r--activerecord/test/cases/pooled_connections_test.rb2
-rw-r--r--activerecord/test/cases/primary_keys_test.rb8
-rw-r--r--activerecord/test/cases/query_cache_test.rb2
-rw-r--r--activerecord/test/cases/reflection_test.rb17
-rw-r--r--activerecord/test/cases/relation/record_fetch_warning_test.rb28
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb7
-rw-r--r--activerecord/test/cases/serialized_attribute_test.rb10
-rw-r--r--activerecord/test/cases/tasks/database_tasks_test.rb16
-rw-r--r--activerecord/test/cases/tasks/postgresql_rake_test.rb49
-rw-r--r--activerecord/test/cases/test_fixtures_test.rb36
-rw-r--r--activerecord/test/cases/time_precision_test.rb2
-rw-r--r--activerecord/test/cases/timestamp_test.rb2
-rw-r--r--activerecord/test/cases/transaction_callbacks_test.rb24
-rw-r--r--activerecord/test/cases/transaction_isolation_test.rb4
-rw-r--r--activerecord/test/cases/transactions_test.rb22
-rw-r--r--activerecord/test/cases/unconnected_test.rb2
-rw-r--r--activerecord/test/cases/validations/length_validation_test.rb65
-rw-r--r--activerecord/test/cases/yaml_serialization_test.rb35
-rw-r--r--activerecord/test/models/chef.rb1
-rw-r--r--activerecord/test/models/hotel.rb1
-rw-r--r--activerecord/test/models/recipe.rb3
-rw-r--r--activerecord/test/schema/postgresql_specific_schema.rb4
-rw-r--r--activerecord/test/schema/schema.rb4
-rw-r--r--activerecord/test/support/yaml_compatibility_fixtures/rails_4_1.yml22
-rw-r--r--activerecord/test/support/yaml_compatibility_fixtures/rails_4_2_0.yml182
-rw-r--r--activesupport/CHANGELOG.md24
-rw-r--r--activesupport/activesupport.gemspec2
-rw-r--r--activesupport/lib/active_support.rb1
-rw-r--r--activesupport/lib/active_support/array_inquirer.rb38
-rw-r--r--activesupport/lib/active_support/cache.rb13
-rw-r--r--activesupport/lib/active_support/cache/strategy/local_cache.rb2
-rw-r--r--activesupport/lib/active_support/callbacks.rb15
-rw-r--r--activesupport/lib/active_support/core_ext/array.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/array/conversions.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/array/inquiry.rb15
-rw-r--r--activesupport/lib/active_support/core_ext/hash/keys.rb14
-rw-r--r--activesupport/lib/active_support/core_ext/hash/slice.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/integer/time.rb15
-rw-r--r--activesupport/lib/active_support/core_ext/marshal.rb14
-rw-r--r--activesupport/lib/active_support/core_ext/module/aliasing.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/module/remove_method.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/numeric/time.rb15
-rw-r--r--activesupport/lib/active_support/core_ext/object/json.rb16
-rw-r--r--activesupport/lib/active_support/core_ext/range/each.rb12
-rw-r--r--activesupport/lib/active_support/core_ext/range/include_range.rb8
-rw-r--r--activesupport/lib/active_support/core_ext/string/behavior.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/string/inflections.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/string/multibyte.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/string/output_safety.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/time/calculations.rb6
-rw-r--r--activesupport/lib/active_support/deprecation/method_wrappers.rb8
-rw-r--r--activesupport/lib/active_support/duration.rb24
-rw-r--r--activesupport/lib/active_support/number_helper.rb16
-rw-r--r--activesupport/lib/active_support/number_helper/number_to_currency_converter.rb4
-rw-r--r--activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb2
-rw-r--r--activesupport/lib/active_support/railtie.rb5
-rw-r--r--activesupport/lib/active_support/string_inquirer.rb2
-rw-r--r--activesupport/lib/active_support/subscriber.rb9
-rw-r--r--activesupport/lib/active_support/tagged_logging.rb2
-rw-r--r--activesupport/lib/active_support/test_case.rb4
-rw-r--r--activesupport/lib/active_support/testing/time_helpers.rb22
-rw-r--r--activesupport/lib/active_support/time_with_zone.rb2
-rw-r--r--activesupport/test/abstract_unit.rb5
-rw-r--r--activesupport/test/array_inquirer_test.rb36
-rw-r--r--activesupport/test/caching_test.rb28
-rw-r--r--activesupport/test/core_ext/array/conversions_test.rb6
-rw-r--r--activesupport/test/core_ext/marshal_test.rb4
-rw-r--r--activesupport/test/core_ext/module_test.rb220
-rw-r--r--activesupport/test/core_ext/secure_random_test.rb (renamed from activesupport/test/core_ext/securerandom.rb)0
-rw-r--r--activesupport/test/number_helper_test.rb4
-rw-r--r--activesupport/test/test_case_test.rb11
-rw-r--r--guides/rails_guides.rb46
-rw-r--r--guides/rails_guides/generator.rb1
-rw-r--r--guides/source/2_3_release_notes.md2
-rw-r--r--guides/source/3_1_release_notes.md2
-rw-r--r--guides/source/4_0_release_notes.md43
-rw-r--r--guides/source/4_2_release_notes.md30
-rw-r--r--guides/source/action_controller_overview.md89
-rw-r--r--guides/source/action_view_overview.md28
-rw-r--r--guides/source/active_record_basics.md14
-rw-r--r--guides/source/active_record_callbacks.md2
-rw-r--r--guides/source/active_record_migrations.md14
-rw-r--r--guides/source/active_record_querying.md4
-rw-r--r--guides/source/active_record_validations.md8
-rw-r--r--guides/source/active_support_core_extensions.md4
-rw-r--r--guides/source/asset_pipeline.md13
-rw-r--r--guides/source/association_basics.md4
-rw-r--r--guides/source/autoloading_and_reloading_constants.md5
-rw-r--r--guides/source/command_line.md6
-rw-r--r--guides/source/configuring.md18
-rw-r--r--guides/source/contributing_to_ruby_on_rails.md10
-rw-r--r--guides/source/debugging_rails_applications.md2
-rw-r--r--guides/source/form_helpers.md4
-rw-r--r--guides/source/getting_started.md28
-rw-r--r--guides/source/i18n.md2
-rw-r--r--guides/source/layouts_and_rendering.md7
-rw-r--r--guides/source/plugins.md6
-rw-r--r--guides/source/routing.md4
-rw-r--r--guides/source/security.md2
-rw-r--r--guides/source/testing.md16
-rw-r--r--guides/source/upgrading_ruby_on_rails.md17
-rw-r--r--rails.gemspec2
-rw-r--r--railties/CHANGELOG.md32
-rw-r--r--railties/lib/rails/app_rails_loader.rb3
-rw-r--r--railties/lib/rails/application.rb23
-rw-r--r--railties/lib/rails/commands.rb3
-rw-r--r--railties/lib/rails/commands/commands_tasks.rb7
-rw-r--r--railties/lib/rails/commands/test.rb5
-rw-r--r--railties/lib/rails/engine.rb2
-rw-r--r--railties/lib/rails/generators/actions.rb2
-rw-r--r--railties/lib/rails/generators/app_base.rb2
-rw-r--r--railties/lib/rails/generators/named_base.rb4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/Gemfile4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/app/jobs/application_job.rb3
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml2
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js2
-rw-r--r--railties/lib/rails/generators/rails/resource_route/resource_route_generator.rb6
-rw-r--r--railties/lib/rails/generators/test_unit/mailer/templates/preview.rb4
-rw-r--r--railties/lib/rails/generators/test_unit/model/model_generator.rb2
-rw-r--r--railties/lib/rails/ruby_version_check.rb6
-rw-r--r--railties/lib/rails/tasks.rb1
-rw-r--r--railties/lib/rails/tasks/initializers.rake6
-rw-r--r--railties/lib/rails/test_help.rb7
-rw-r--r--railties/lib/rails/test_unit/minitest_plugin.rb14
-rw-r--r--railties/lib/rails/test_unit/reporter.rb22
-rw-r--r--railties/lib/rails/test_unit/runner.rb137
-rw-r--r--railties/lib/rails/test_unit/testing.rake33
-rw-r--r--railties/railties.gemspec3
-rw-r--r--railties/test/abstract_unit.rb5
-rw-r--r--railties/test/application/asset_debugging_test.rb4
-rw-r--r--railties/test/application/assets_test.rb14
-rw-r--r--railties/test/application/build_original_fullpath_test.rb27
-rw-r--r--railties/test/application/rake_test.rb2
-rw-r--r--railties/test/application/test_runner_test.rb41
-rw-r--r--railties/test/application/test_test.rb19
-rw-r--r--railties/test/application/url_generation_test.rb13
-rw-r--r--railties/test/generators/actions_test.rb24
-rw-r--r--railties/test/generators/app_generator_test.rb13
-rw-r--r--railties/test/generators/job_generator_test.rb6
-rw-r--r--railties/test/generators/mailer_generator_test.rb10
-rw-r--r--railties/test/generators/model_generator_test.rb10
-rw-r--r--railties/test/rails_info_controller_test.rb16
-rw-r--r--railties/test/railties/engine_test.rb4
-rw-r--r--railties/test/test_unit/reporter_test.rb74
-rw-r--r--railties/test/test_unit/runner_test.rb111
-rw-r--r--tools/line_statistics2
364 files changed, 3232 insertions, 1685 deletions
diff --git a/.travis.yml b/.travis.yml
index 3130ee1b32..0038668ae7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,15 +13,14 @@ env:
matrix:
- "GEM=railties"
- "GEM=ap"
- - "GEM=aj"
- - "GEM=am,amo,as,av"
+ - "GEM=am,amo,as,av,aj"
- "GEM=ar:mysql"
- "GEM=ar:mysql2"
- "GEM=ar:sqlite3"
- "GEM=ar:postgresql"
- "GEM=aj:integration"
rvm:
- - 2.2
+ - 2.2.1
- ruby-head
- rbx-2
- jruby-head
@@ -31,8 +30,6 @@ matrix:
- rvm: ruby-head
- rvm: rbx-2
- rvm: jruby-head
- - env: "GEM=aj"
- - env: "GEM=aj:integration"
fast_finish: true
notifications:
email: false
diff --git a/Gemfile b/Gemfile
index 25850ff34e..70b8a74ddf 100644
--- a/Gemfile
+++ b/Gemfile
@@ -17,6 +17,8 @@ gem 'turbolinks'
gem 'arel', github: 'rails/arel', branch: 'master'
gem 'mail', github: 'mikel/mail'
+gem 'sprockets', '~> 3.0.0.rc.1'
+
# require: false so bcrypt is loaded only when has_secure_password is used.
# This is to avoid ActiveModel (and by extension the entire framework)
# being dependent on a binary library.
@@ -33,7 +35,7 @@ group :doc do
gem 'kindlerb', '0.1.1'
end
-# AS
+# ActiveSupport
gem 'dalli', '>= 2.2.1'
# ActiveJob
@@ -49,7 +51,7 @@ group :job do
gem 'backburner', require: false
gem 'qu-rails', github: "bkeepers/qu", branch: "master", require: false
gem 'qu-redis', require: false
- # gem 'delayed_job_active_record', require: false
+ gem 'delayed_job_active_record', require: false
gem 'sequel', require: false
end
@@ -82,7 +84,7 @@ platforms :ruby do
# Needed for compiling the ActionDispatch::Journey parser
gem 'racc', '>=1.4.6', require: false
- # AR
+ # ActiveRecord
gem 'sqlite3', '~> 1.3.6'
group :db do
diff --git a/Gemfile.lock b/Gemfile.lock
index e34449a7b0..90ade529bc 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -50,13 +50,13 @@ PATH
rack (~> 1.6)
rack-test (~> 0.6.3)
rails-dom-testing (~> 1.0, >= 1.0.5)
- rails-html-sanitizer (~> 1.0, >= 1.0.1)
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (5.0.0.alpha)
activesupport (= 5.0.0.alpha)
builder (~> 3.1)
erubis (~> 2.7.0)
rails-dom-testing (~> 1.0, >= 1.0.5)
- rails-html-sanitizer (~> 1.0, >= 1.0.1)
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
activejob (5.0.0.alpha)
activesupport (= 5.0.0.alpha)
globalid (>= 0.3.0)
@@ -87,6 +87,7 @@ PATH
railties (5.0.0.alpha)
actionpack (= 5.0.0.alpha)
activesupport (= 5.0.0.alpha)
+ method_source
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
@@ -117,11 +118,13 @@ GEM
dante (0.1.5)
delayed_job (4.0.6)
activesupport (>= 3.0, < 5.0)
+ delayed_job_active_record (4.0.3)
+ activerecord (>= 3.0, < 5.0)
+ delayed_job (>= 3.0, < 4.1)
erubis (2.7.0)
execjs (2.3.0)
globalid (0.3.3)
activesupport (>= 4.1.0)
- hike (1.2.3)
hitimes (1.2.2)
i18n (0.7.0)
json (1.8.2)
@@ -131,13 +134,14 @@ GEM
loofah (2.0.1)
nokogiri (>= 1.5.9)
metaclass (0.0.4)
+ method_source (0.8.2)
mime-types (2.4.3)
mini_portile (0.6.2)
minitest (5.3.3)
mocha (0.14.0)
metaclass (~> 0.0.1)
mono_logger (1.1.0)
- multi_json (1.10.1)
+ multi_json (1.11.0)
mustache (1.0.0)
mysql (2.9.1)
mysql2 (0.3.18)
@@ -162,7 +166,7 @@ GEM
activesupport (>= 4.2.0.beta, < 5.0)
nokogiri (~> 1.6.0)
rails-deprecated_sanitizer (>= 1.0.1)
- rails-html-sanitizer (1.0.1)
+ rails-html-sanitizer (1.0.2)
loofah (~> 2.0)
rake (10.4.2)
rdoc (4.2.0)
@@ -206,11 +210,8 @@ GEM
serverengine
thor
thread
- sprockets (2.12.3)
- hike (~> 1.2)
- multi_json (~> 1.0)
+ sprockets (3.0.0.rc.1)
rack (~> 1.0)
- tilt (~> 1.1, != 1.3.0)
sprockets-rails (2.2.4)
actionpack (>= 3.0)
activesupport (>= 3.0)
@@ -252,6 +253,7 @@ DEPENDENCIES
coffee-rails (~> 4.1.0)
dalli (>= 2.2.1)
delayed_job
+ delayed_job_active_record
jquery-rails!
json
kindlerb (= 0.1.1)
@@ -279,6 +281,7 @@ DEPENDENCIES
sequel
sidekiq
sneakers (= 0.1.1.pre)
+ sprockets (~> 3.0.0.rc.1)
sqlite3 (~> 1.3.6)
stackprof
sucker_punch
diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec
index 513c217733..41913899ff 100644
--- a/actionmailer/actionmailer.gemspec
+++ b/actionmailer/actionmailer.gemspec
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
s.summary = 'Email composition, delivery, and receiving framework (part of Rails).'
s.description = 'Email on Rails. Compose, deliver, receive, and test emails using the familiar controller/view pattern. First-class support for multipart email and attachments.'
- s.required_ruby_version = '>= 2.2.0'
+ s.required_ruby_version = '>= 2.2.1'
s.license = 'MIT'
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index 3e5125f72e..c7f09ed192 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -21,7 +21,7 @@ module ActionMailer
# the mailer views, options on the mail itself such as the <tt>:from</tt> address, and attachments.
#
# class ApplicationMailer < ActionMailer::Base
- # default from: 'from@exmaple.com'
+ # default from: 'from@example.com'
# layout 'mailer'
# end
#
diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb
index c4d5cb8c33..ae91903c95 100644
--- a/actionmailer/test/abstract_unit.rb
+++ b/actionmailer/test/abstract_unit.rb
@@ -42,8 +42,3 @@ def jruby_skip(message = '')
end
require 'mocha/setup' # FIXME: stop using mocha
-
-# FIXME: we have tests that depend on run order, we should fix that and
-# remove this method call.
-require 'active_support/test_case'
-ActiveSupport::TestCase.test_order = :sorted
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 8c4ba2a154..0ae96441ce 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,3 +1,49 @@
+* Provide friendlier access to request variants.
+
+ request.variant = :phone
+ request.variant.phone? # true
+ request.variant.tablet? # false
+
+ request.variant = [:phone, :tablet]
+ request.variant.phone? # true
+ request.variant.desktop? # false
+ request.variant.any?(:phone, :desktop) # true
+ request.variant.any?(:desktop, :watch) # false
+
+ *George Claghorn*
+
+* Fix regression where a gzip file response would have a Content-type,
+ even when it was a 304 status code.
+
+ See #19271.
+
+ *Kohei Suzuki*
+
+* Fix handling of empty X_FORWARDED_HOST header in raw_host_with_port
+
+ Previously, an empty X_FORWARDED_HOST header would cause
+ Actiondispatch::Http:URL.raw_host_with_port to return nil, causing
+ Actiondispatch::Http:URL.host to raise a NoMethodError.
+
+ *Adam Forsyth*
+
+* Drop request class from RouteSet constructor.
+
+ If you would like to use a custom request class, please subclass and implement
+ the `request_class` method.
+
+ *tenderlove@ruby-lang.org*
+
+* Fallback to `ENV['RAILS_RELATIVE_URL_ROOT']` in `url_for`.
+
+ Fixed an issue where the `RAILS_RELATIVE_URL_ROOT` environment variable is not
+ prepended to the path when `url_for` is called. If `SCRIPT_NAME` (used by Rack)
+ is set, it takes precedence.
+
+ Fixes #5122.
+
+ *Yasyf Mohamedali*
+
* Partitioning of routes is now done when the routes are being drawn. This
helps to decrease the time spent filtering the routes during the first request.
diff --git a/actionpack/Rakefile b/actionpack/Rakefile
index 4b60b77759..3bd27f8d64 100644
--- a/actionpack/Rakefile
+++ b/actionpack/Rakefile
@@ -9,10 +9,7 @@ task :default => :test
# Run the unit tests
Rake::TestTask.new do |t|
t.libs << 'test'
-
- # make sure we include the tests in alphabetical order as on some systems
- # this will not happen automatically and the tests (as a whole) will error
- t.test_files = test_files.sort
+ t.test_files = test_files
t.warning = true
t.verbose = true
diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec
index d907001bd6..b6b70a027c 100644
--- a/actionpack/actionpack.gemspec
+++ b/actionpack/actionpack.gemspec
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
s.summary = 'Web-flow and rendering framework putting the VC in MVC (part of Rails).'
s.description = 'Web apps on Rails. Simple, battle-tested conventions for building and testing MVC web applications. Works with any Rack-compatible server.'
- s.required_ruby_version = '>= 2.2.0'
+ s.required_ruby_version = '>= 2.2.1'
s.license = 'MIT'
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
s.add_dependency 'rack', '~> 1.6'
s.add_dependency 'rack-test', '~> 0.6.3'
- s.add_dependency 'rails-html-sanitizer', '~> 1.0', '>= 1.0.1'
+ s.add_dependency 'rails-html-sanitizer', '~> 1.0', '>= 1.0.2'
s.add_dependency 'rails-dom-testing', '~> 1.0', '>= 1.0.5'
s.add_dependency 'actionview', version
diff --git a/actionpack/lib/action_controller/metal/conditional_get.rb b/actionpack/lib/action_controller/metal/conditional_get.rb
index 858870d8b8..47bcfdb1e9 100644
--- a/actionpack/lib/action_controller/metal/conditional_get.rb
+++ b/actionpack/lib/action_controller/metal/conditional_get.rb
@@ -15,7 +15,7 @@ module ActionController
module ClassMethods
# Allows you to consider additional controller-wide information when generating an ETag.
# For example, if you serve pages tailored depending on who's logged in at the moment, you
- # may want to add the current user id to be part of the ETag to prevent authorized displaying
+ # may want to add the current user id to be part of the ETag to prevent unauthorized displaying
# of cached pages.
#
# class InvoicesController < ApplicationController
diff --git a/actionpack/lib/action_controller/metal/head.rb b/actionpack/lib/action_controller/metal/head.rb
index 0d93e2f7aa..70f42bf565 100644
--- a/actionpack/lib/action_controller/metal/head.rb
+++ b/actionpack/lib/action_controller/metal/head.rb
@@ -38,6 +38,8 @@ module ActionController
headers.delete('Content-Type')
headers.delete('Content-Length')
end
+
+ true
end
private
diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb
index 819837e767..4038101fe0 100644
--- a/actionpack/lib/action_controller/metal/helpers.rb
+++ b/actionpack/lib/action_controller/metal/helpers.rb
@@ -93,7 +93,7 @@ module ActionController
super(args)
end
- # Return a list of helper names in specific path.
+ # Returns a list of helper names in a given path.
#
# ActionController::Base.all_helpers_from_path 'app/helpers'
# # => ["application", "chart", "rubygems"]
diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb
index 20afcee537..2273406948 100644
--- a/actionpack/lib/action_controller/metal/http_authentication.rb
+++ b/actionpack/lib/action_controller/metal/http_authentication.rb
@@ -314,7 +314,7 @@ module ActionController
nonce(secret_key, t) == value && (t - Time.now.to_i).abs <= seconds_to_timeout
end
- # Opaque based on random generation - but changing each request?
+ # Opaque based on digest of secret key
def opaque(secret_key)
::Digest::MD5.hexdigest(secret_key)
end
diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb
index 7dae171215..fab1be3459 100644
--- a/actionpack/lib/action_controller/metal/mime_responds.rb
+++ b/actionpack/lib/action_controller/metal/mime_responds.rb
@@ -288,16 +288,17 @@ module ActionController #:nodoc:
end
def variant
- if @variant.nil?
+ if @variant.empty?
@variants[:none] || @variants[:any]
- elsif (@variants.keys & @variant).any?
- @variant.each do |v|
- return @variants[v] if @variants.key?(v)
- end
else
- @variants[:any]
+ @variants[variant_key]
end
end
+
+ private
+ def variant_key
+ @variant.find { |variant| @variants.key?(variant) } || :any
+ end
end
end
end
diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb
index a7e734db42..0a04848eba 100644
--- a/actionpack/lib/action_controller/metal/params_wrapper.rb
+++ b/actionpack/lib/action_controller/metal/params_wrapper.rb
@@ -131,7 +131,7 @@ module ActionController
private
# Determine the wrapper model from the controller's name. By convention,
# this could be done by trying to find the defined model that has the
- # same singularize name as the controller. For example, +UsersController+
+ # same singular name as the controller. For example, +UsersController+
# will try to find if the +User+ model exists.
#
# This method also does namespace lookup. Foo::Bar::UsersController will
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index f19c4201ba..e30c9c5ade 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -117,7 +117,7 @@ module ActionController
self.always_permitted_parameters = %w( controller action )
def self.const_missing(const_name)
- super unless const_name == :NEVER_UNPERMITTED_PARAMS
+ return super unless const_name == :NEVER_UNPERMITTED_PARAMS
ActiveSupport::Deprecation.warn(<<-MSG.squish)
`ActionController::Parameters::NEVER_UNPERMITTED_PARAMS` has been deprecated.
Use `ActionController::Parameters.always_permitted_parameters` instead.
diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb
index 572d1770f7..fbaa90d521 100644
--- a/actionpack/lib/action_controller/metal/url_for.rb
+++ b/actionpack/lib/action_controller/metal/url_for.rb
@@ -4,7 +4,10 @@ module ActionController
#
# In addition to <tt>AbstractController::UrlFor</tt>, this module accesses the HTTP layer to define
# url options like the +host+. In order to do so, this module requires the host class
- # to implement +env+ and +request+, which need to be a Rack-compatible.
+ # to implement +env+ which needs to be Rack-compatible and +request+
+ # which is either instance of +ActionDispatch::Request+ or an object
+ # that responds to <tt>host</tt>, <tt>optional_port</tt>, <tt>protocol</tt> and
+ # <tt>symbolized_path_parameter</tt> methods.
#
# class RootUrl
# include ActionController::UrlFor
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 4782991463..33c24999f9 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -201,7 +201,7 @@ module ActionController
super
self.session = TestSession.new
- self.session_options = TestSession::DEFAULT_OPTIONS.merge(:id => SecureRandom.hex(16))
+ self.session_options = TestSession::DEFAULT_OPTIONS
end
def assign_parameters(routes, controller_path, action, parameters = {})
diff --git a/actionpack/lib/action_dispatch/http/filter_redirect.rb b/actionpack/lib/action_dispatch/http/filter_redirect.rb
index cd603649c3..bf79963351 100644
--- a/actionpack/lib/action_dispatch/http/filter_redirect.rb
+++ b/actionpack/lib/action_dispatch/http/filter_redirect.rb
@@ -4,7 +4,7 @@ module ActionDispatch
FILTERED = '[FILTERED]'.freeze # :nodoc:
- def filtered_location
+ def filtered_location # :nodoc:
filters = location_filter
if !filters.empty? && location_filter_match?(filters)
FILTERED
diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
index 53a98c5d0a..ff336b7354 100644
--- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb
+++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
@@ -10,8 +10,6 @@ module ActionDispatch
self.ignore_accept_header = false
end
- attr_reader :variant
-
# The MIME type of the HTTP request, such as Mime::XML.
#
# For backward compatibility, the post \format is extracted from the
@@ -75,18 +73,22 @@ module ActionDispatch
# Sets the \variant for template.
def variant=(variant)
- if variant.is_a?(Symbol)
- @variant = [variant]
- elsif variant.nil? || variant.is_a?(Array) && variant.any? && variant.all?{ |v| v.is_a?(Symbol) }
- @variant = variant
+ variant = Array(variant)
+
+ if variant.all? { |v| v.is_a?(Symbol) }
+ @variant = ActiveSupport::ArrayInquirer.new(variant)
else
- raise ArgumentError, "request.variant must be set to a Symbol or an Array of Symbols, not a #{variant.class}. " \
+ raise ArgumentError, "request.variant must be set to a Symbol or an Array of Symbols. " \
"For security reasons, never directly set the variant to a user-provided value, " \
"like params[:variant].to_sym. Check user-provided value against a whitelist first, " \
"then set the variant: request.variant = :tablet if params[:variant] == 'tablet'"
end
end
+ def variant
+ @variant ||= ActiveSupport::ArrayInquirer.new
+ end
+
# Sets the \format by string extension, which can be used to force custom formats
# that are not controlled by the extension.
#
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index 5fe544c60c..a895d1ab18 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -113,9 +113,7 @@ module ActionDispatch # :nodoc:
# The underlying body, as a streamable object.
attr_reader :stream
- # Ruby 2.2 bug https://bugs.ruby-lang.org/issues/10685 prevents
- # default_headers from being a keyword argument.
- def initialize(status = 200, header = {}, body = [], default_headers = self.class.default_headers)
+ def initialize(status = 200, header = {}, body = [], default_headers: self.class.default_headers)
super()
header = merge_default_headers(header, default_headers)
diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb
index 7da6301ac4..f5b709ccd6 100644
--- a/actionpack/lib/action_dispatch/http/url.rb
+++ b/actionpack/lib/action_dispatch/http/url.rb
@@ -229,7 +229,7 @@ module ActionDispatch
# req = Request.new 'HTTP_HOST' => 'example.com:8080'
# req.raw_host_with_port # => "example.com:8080"
def raw_host_with_port
- if forwarded = env["HTTP_X_FORWARDED_HOST"]
+ if forwarded = env["HTTP_X_FORWARDED_HOST"].presence
forwarded.split(/,\s?/).last
else
env['HTTP_HOST'] || "#{env['SERVER_NAME'] || env['SERVER_ADDR']}:#{env['SERVER_PORT']}"
diff --git a/actionpack/lib/action_dispatch/middleware/public_exceptions.rb b/actionpack/lib/action_dispatch/middleware/public_exceptions.rb
index 040cb215b7..7cde76b30e 100644
--- a/actionpack/lib/action_dispatch/middleware/public_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/public_exceptions.rb
@@ -17,10 +17,10 @@ module ActionDispatch
end
def call(env)
- status = env["PATH_INFO"][1..-1]
+ status = env["PATH_INFO"][1..-1].to_i
request = ActionDispatch::Request.new(env)
content_type = request.formats.first
- body = { :status => status, :error => Rack::Utils::HTTP_STATUS_CODES.fetch(status.to_i, Rack::Utils::HTTP_STATUS_CODES[500]) }
+ body = { :status => status, :error => Rack::Utils::HTTP_STATUS_CODES.fetch(status, Rack::Utils::HTTP_STATUS_CODES[500]) }
render(status, content_type, body)
end
diff --git a/actionpack/lib/action_dispatch/middleware/static.rb b/actionpack/lib/action_dispatch/middleware/static.rb
index 2e1bd45c3d..fdd1bc4e69 100644
--- a/actionpack/lib/action_dispatch/middleware/static.rb
+++ b/actionpack/lib/action_dispatch/middleware/static.rb
@@ -47,6 +47,9 @@ module ActionDispatch
if gzip_path && gzip_encoding_accepted?(env)
env['PATH_INFO'] = gzip_path
status, headers, body = @file_server.call(env)
+ if status == 304
+ return [status, headers, body]
+ end
headers['Content-Encoding'] = 'gzip'
headers['Content-Type'] = content_type(path)
else
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 58b3fff9d7..0f3734dd74 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -309,7 +309,7 @@ module ActionDispatch
attr_accessor :formatter, :set, :named_routes, :default_scope, :router
attr_accessor :disable_clear_and_finalize, :resources_path_names
- attr_accessor :default_url_options, :request_class
+ attr_accessor :default_url_options
attr_reader :env_key
alias :routes :set
@@ -318,12 +318,25 @@ module ActionDispatch
{ :new => 'new', :edit => 'edit' }
end
- def initialize(request_class = ActionDispatch::Request)
+ def self.new_with_config(config)
+ if config.respond_to? :relative_url_root
+ new Config.new config.relative_url_root
+ else
+ # engines apparently don't have this set
+ new
+ end
+ end
+
+ Config = Struct.new :relative_url_root
+
+ DEFAULT_CONFIG = Config.new(nil)
+
+ def initialize(config = DEFAULT_CONFIG)
self.named_routes = NamedRouteCollection.new
self.resources_path_names = self.class.default_resources_path_names
self.default_url_options = {}
- self.request_class = request_class
+ @config = config
@append = []
@prepend = []
@disable_clear_and_finalize = false
@@ -335,6 +348,14 @@ module ActionDispatch
@formatter = Journey::Formatter.new @set
end
+ def relative_url_root
+ @config.relative_url_root
+ end
+
+ def request_class
+ ActionDispatch::Request
+ end
+
def draw(&block)
clear! unless @disable_clear_and_finalize
eval_block(block)
@@ -543,7 +564,7 @@ module ActionDispatch
conditions.keep_if do |k, _|
k == :action || k == :controller || k == :required_defaults ||
- @request_class.public_method_defined?(k) || path_values.include?(k)
+ request_class.public_method_defined?(k) || path_values.include?(k)
end
end
private :build_conditions
@@ -697,7 +718,7 @@ module ActionDispatch
end
def find_script_name(options)
- options.delete(:script_name) || ''
+ options.delete(:script_name) || relative_url_root || ''
end
def path_for(options, route_name = nil)
diff --git a/actionpack/lib/action_dispatch/testing/assertions.rb b/actionpack/lib/action_dispatch/testing/assertions.rb
index f325c35b57..21b3b89d22 100644
--- a/actionpack/lib/action_dispatch/testing/assertions.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions.rb
@@ -12,7 +12,7 @@ module ActionDispatch
include Rails::Dom::Testing::Assertions
def html_document
- @html_document ||= if @response.content_type =~ /xml$/
+ @html_document ||= if @response.content_type === Mime::XML
Nokogiri::XML::Document.parse(@response.body)
else
Nokogiri::HTML::Document.parse(@response.body)
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index f7f898288b..9390e2937a 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -388,8 +388,16 @@ module ActionDispatch
APP_SESSIONS = {}
- def app
- @app ||= nil
+ attr_reader :app
+
+ def before_setup
+ @app = nil
+ @integration_session = nil
+ super
+ end
+
+ def integration_session
+ @integration_session ||= create_session(app)
end
# Reset the current session. This is useful for testing multiple sessions
@@ -417,8 +425,6 @@ module ActionDispatch
%w(get post patch put head delete cookies assigns
xml_http_request xhr get_via_redirect post_via_redirect).each do |method|
define_method(method) do |*args|
- reset! unless integration_session
-
# reset the html_document variable, except for cookies/assigns calls
unless method == 'cookies' || method == 'assigns'
@html_document = nil
@@ -450,19 +456,16 @@ module ActionDispatch
# Copy the instance variables from the current session instance into the
# test instance.
def copy_session_variables! #:nodoc:
- return unless integration_session
@controller = @integration_session.controller
@response = @integration_session.response
@request = @integration_session.request
end
def default_url_options
- reset! unless integration_session
integration_session.default_url_options
end
def default_url_options=(options)
- reset! unless integration_session
integration_session.default_url_options = options
end
@@ -472,7 +475,6 @@ module ActionDispatch
# Delegate unhandled messages to the current session instance.
def method_missing(sym, *args, &block)
- reset! unless integration_session
if integration_session.respond_to?(sym)
integration_session.__send__(sym, *args, &block).tap do
copy_session_variables!
@@ -481,11 +483,6 @@ module ActionDispatch
super
end
end
-
- private
- def integration_session
- @integration_session ||= nil
- end
end
end
@@ -508,8 +505,8 @@ module ActionDispatch
# assert_equal 200, status
#
# # post the login and follow through to the home page
- # post "/login", username: people(:jamis).username,
- # password: people(:jamis).password
+ # post "/login", params: { username: people(:jamis).username,
+ # password: people(:jamis).password }
# follow_redirect!
# assert_equal 200, status
# assert_equal "/home", path
@@ -548,7 +545,7 @@ module ActionDispatch
# end
#
# def speak(room, message)
- # xml_http_request "/say/#{room.id}", message: message
+ # post "/say/#{room.id}", xhr: true, params: { message: message }
# assert(...)
# ...
# end
@@ -558,8 +555,8 @@ module ActionDispatch
# open_session do |sess|
# sess.extend(CustomAssertions)
# who = people(who)
- # sess.post "/login", username: who.username,
- # password: who.password
+ # sess.post "/login", params: { username: who.username,
+ # password: who.password }
# assert(...)
# end
# end
@@ -578,7 +575,8 @@ module ActionDispatch
# get "/login"
# assert_response :success
#
- # post_via_redirect "/login", username: users(:david).username, password: users(:david).password
+ # post "/login", params: { username: users(:david).username, password: users(:david).password }
+ # follow_redirect!
# assert_equal '/welcome', path
# assert_equal 'Welcome david!', flash[:notice]
#
@@ -633,7 +631,7 @@ module ActionDispatch
# sess.extend(CustomDsl)
# u = users(user)
# sess.https!
- # sess.post "/login", username: u.username, password: u.password
+ # sess.post "/login", params: { username: u.username, password: u.password }
# assert_equal '/welcome', sess.path
# sess.https!(false)
# end
@@ -662,7 +660,6 @@ module ActionDispatch
end
def url_options
- reset! unless integration_session
integration_session.url_options
end
diff --git a/actionpack/lib/action_dispatch/testing/test_response.rb b/actionpack/lib/action_dispatch/testing/test_response.rb
index 527784885c..a9b88ac5fd 100644
--- a/actionpack/lib/action_dispatch/testing/test_response.rb
+++ b/actionpack/lib/action_dispatch/testing/test_response.rb
@@ -7,7 +7,7 @@ module ActionDispatch
# See Response for more information on controller response objects.
class TestResponse < Response
def self.from_response(response)
- new response.status, response.headers, response.body, nil
+ new response.status, response.headers, response.body, default_headers: nil
end
# Was the response successful?
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index f5dd9d76af..62ff1be5c9 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -483,8 +483,3 @@ if RUBY_ENGINE == "ruby" && PROCESS_COUNT > 0
# Use N processes (N defaults to 4)
Minitest.parallel_executor = ForkingExecutor.new(PROCESS_COUNT)
end
-
-# FIXME: we have tests that depend on run order, we should fix that and
-# remove this method call.
-require 'active_support/test_case'
-ActiveSupport::TestCase.test_order = :sorted
diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb
index 438c044da2..a87059bee4 100644
--- a/actionpack/test/controller/integration_test.rb
+++ b/actionpack/test/controller/integration_test.rb
@@ -363,6 +363,7 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest
respond_to do |format|
format.html { render :text => "OK", :status => 200 }
format.js { render :text => "JS OK", :status => 200 }
+ format.xml { render :xml => "<root></root>", :status => 200 }
end
end
@@ -419,6 +420,22 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest
end
end
+ def test_get_xml
+ with_test_route_set do
+ get "/get", params: {}, headers: {"HTTP_ACCEPT" => "application/xml"}
+ assert_equal 200, status
+ assert_equal "OK", status_message
+ assert_response 200
+ assert_response :success
+ assert_response :ok
+ assert_equal({}, cookies.to_hash)
+ assert_equal "<root></root>", body
+ assert_equal "<root></root>", response.body
+ assert_instance_of Nokogiri::XML::Document, html_document
+ assert_equal 1, request_count
+ end
+ end
+
def test_post
with_test_route_set do
post '/post'
@@ -1036,3 +1053,15 @@ class IntegrationRequestsWithoutSetup < ActionDispatch::IntegrationTest
end
end
end
+
+# to ensure that session requirements in setup are persisted in the tests
+class IntegrationRequestsWithSessionSetup < ActionDispatch::IntegrationTest
+ setup do
+ cookies['user_name'] = 'david'
+ end
+
+ def test_cookies_set_in_setup_are_persisted_through_the_session
+ get "/foo"
+ assert_equal({"user_name"=>"david"}, cookies.to_hash)
+ end
+end
diff --git a/actionpack/test/controller/new_base/render_template_test.rb b/actionpack/test/controller/new_base/render_template_test.rb
index 19fef718e7..b06ce5db40 100644
--- a/actionpack/test/controller/new_base/render_template_test.rb
+++ b/actionpack/test/controller/new_base/render_template_test.rb
@@ -186,21 +186,21 @@ module RenderTemplate
end
end
- test "rendering with layout => :true" do
+ test "rendering with layout => true" do
get "/render_template/with_layout/with_layout"
assert_body "Hello from basic.html.erb, I'm here!"
assert_status 200
end
- test "rendering with layout => :false" do
+ test "rendering with layout => false" do
get "/render_template/with_layout/with_layout_false"
assert_body "Hello from basic.html.erb"
assert_status 200
end
- test "rendering with layout => :nil" do
+ test "rendering with layout => nil" do
get "/render_template/with_layout/with_layout_nil"
assert_body "Hello from basic.html.erb"
diff --git a/actionpack/test/controller/parameters/always_permitted_parameters_test.rb b/actionpack/test/controller/parameters/always_permitted_parameters_test.rb
index 059f310d49..59be08db54 100644
--- a/actionpack/test/controller/parameters/always_permitted_parameters_test.rb
+++ b/actionpack/test/controller/parameters/always_permitted_parameters_test.rb
@@ -1,5 +1,6 @@
require 'abstract_unit'
require 'action_controller/metal/strong_parameters'
+require 'minitest/mock'
class AlwaysPermittedParametersTest < ActiveSupport::TestCase
def setup
@@ -14,7 +15,13 @@ class AlwaysPermittedParametersTest < ActiveSupport::TestCase
test "shows deprecations warning on NEVER_UNPERMITTED_PARAMS" do
assert_deprecated do
- ActionController::Parameters::NEVER_UNPERMITTED_PARAMS
+ ActionController::Parameters::NEVER_UNPERMITTED_PARAMS
+ end
+ end
+
+ test "returns super on missing constant other than NEVER_UNPERMITTED_PARAMS" do
+ ActionController::Parameters.superclass.stub :const_missing, "super" do
+ assert_equal "super", ActionController::Parameters::NON_EXISTING_CONSTANT
end
end
diff --git a/actionpack/test/controller/redirect_test.rb b/actionpack/test/controller/redirect_test.rb
index 103ca9c776..efd790de63 100644
--- a/actionpack/test/controller/redirect_test.rb
+++ b/actionpack/test/controller/redirect_test.rb
@@ -63,7 +63,7 @@ class RedirectController < ActionController::Base
end
def redirect_to_url_with_unescaped_query_string
- redirect_to "http://dev.rubyonrails.org/query?status=new"
+ redirect_to "http://example.com/query?status=new"
end
def redirect_to_url_with_complex_scheme
@@ -233,7 +233,7 @@ class RedirectTest < ActionController::TestCase
def test_redirect_to_url_with_unescaped_query_string
get :redirect_to_url_with_unescaped_query_string
assert_response :redirect
- assert_redirected_to "http://dev.rubyonrails.org/query?status=new"
+ assert_redirected_to "http://example.com/query?status=new"
end
def test_redirect_to_url_with_complex_scheme
diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb
index 488585c7a4..79e2104789 100644
--- a/actionpack/test/controller/render_test.rb
+++ b/actionpack/test/controller/render_test.rb
@@ -173,6 +173,11 @@ class TestController < ActionController::Base
head :forbidden, :x_custom_header => "something"
end
+ def head_and_return
+ head :ok and return
+ raise 'should not reach this line'
+ end
+
def head_with_no_content
# Fill in the headers with dummy data to make
# sure they get removed during the testing
@@ -560,6 +565,12 @@ class HeadRenderTest < ActionController::TestCase
assert_equal "something", @response.headers["X-Custom-Header"]
assert_response :forbidden
end
+
+ def test_head_returns_truthy_value
+ assert_nothing_raised do
+ get :head_and_return
+ end
+ end
end
class HttpCacheForeverTest < ActionController::TestCase
diff --git a/actionpack/test/controller/request/test_request_test.rb b/actionpack/test/controller/request/test_request_test.rb
index e624f11773..77a2f68b1c 100644
--- a/actionpack/test/controller/request/test_request_test.rb
+++ b/actionpack/test/controller/request/test_request_test.rb
@@ -24,12 +24,4 @@ class ActionController::TestRequestTest < ActiveSupport::TestCase
end
end
- def test_session_id_exists_by_default
- assert_not_nil(@request.session_options[:id])
- end
-
- def test_session_id_different_on_each_call
- assert_not_equal(@request.session_options[:id], ActionController::TestRequest.new.session_options[:id])
- end
-
end
diff --git a/actionpack/test/controller/show_exceptions_test.rb b/actionpack/test/controller/show_exceptions_test.rb
index fba5ebba15..786dc15444 100644
--- a/actionpack/test/controller/show_exceptions_test.rb
+++ b/actionpack/test/controller/show_exceptions_test.rb
@@ -75,7 +75,7 @@ module ShowExceptions
get "/", headers: { 'HTTP_ACCEPT' => 'application/json' }
assert_response :internal_server_error
assert_equal 'application/json', response.content_type.to_s
- assert_equal({ :status => '500', :error => 'Internal Server Error' }.to_json, response.body)
+ assert_equal({ :status => 500, :error => 'Internal Server Error' }.to_json, response.body)
end
def test_render_xml_exception
@@ -83,7 +83,7 @@ module ShowExceptions
get "/", headers: { 'HTTP_ACCEPT' => 'application/xml' }
assert_response :internal_server_error
assert_equal 'application/xml', response.content_type.to_s
- assert_equal({ :status => '500', :error => 'Internal Server Error' }.to_xml, response.body)
+ assert_equal({ :status => 500, :error => 'Internal Server Error' }.to_xml, response.body)
end
def test_render_fallback_exception
diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb
index 0ffa2d2a03..31677f202d 100644
--- a/actionpack/test/controller/url_for_test.rb
+++ b/actionpack/test/controller/url_for_test.rb
@@ -30,8 +30,8 @@ module AbstractController
assert_equal '/foo/zot', path
end
- def add_host!
- W.default_url_options[:host] = 'www.basecamphq.com'
+ def add_host!(app = W)
+ app.default_url_options[:host] = 'www.basecamphq.com'
end
def add_port!
@@ -255,6 +255,20 @@ module AbstractController
)
end
+ def test_relative_url_root_is_respected_with_environment_variable
+ # `config.relative_url_root` is set by ENV['RAILS_RELATIVE_URL_ROOT']
+ w = Class.new {
+ config = ActionDispatch::Routing::RouteSet::Config.new '/subdir'
+ r = ActionDispatch::Routing::RouteSet.new(config)
+ r.draw { get ':controller(/:action(/:id(.:format)))' }
+ include r.url_helpers
+ }
+ add_host!(w)
+ assert_equal('https://www.basecamphq.com/subdir/c/a/i',
+ w.new.url_for(:controller => 'c', :action => 'a', :id => 'i', :protocol => 'https')
+ )
+ end
+
def test_named_routes
with_routing do |set|
set.draw do
diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb
index ee8e915610..f208cfda89 100644
--- a/actionpack/test/dispatch/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -435,6 +435,9 @@ class RequestHost < BaseRequestTest
request = stub_request 'HTTP_X_FORWARDED_HOST' => "www.firsthost.org, www.secondhost.org"
assert_equal "www.secondhost.org", request.host
+
+ request = stub_request 'HTTP_X_FORWARDED_HOST' => "", 'HTTP_HOST' => "rubyonrails.org"
+ assert_equal "rubyonrails.org", request.host
end
test "http host with default port overrides server port" do
@@ -1125,35 +1128,47 @@ class RequestEtag < BaseRequestTest
end
class RequestVariant < BaseRequestTest
- test "setting variant" do
- request = stub_request
+ def setup
+ super
+ @request = stub_request
+ end
- request.variant = :mobile
- assert_equal [:mobile], request.variant
+ test 'setting variant to a symbol' do
+ @request.variant = :phone
- request.variant = [:phone, :tablet]
- assert_equal [:phone, :tablet], request.variant
+ assert @request.variant.phone?
+ assert_not @request.variant.tablet?
+ assert @request.variant.any?(:phone, :tablet)
+ assert_not @request.variant.any?(:tablet, :desktop)
+ end
- assert_raise ArgumentError do
- request.variant = [:phone, "tablet"]
- end
+ test 'setting variant to an array of symbols' do
+ @request.variant = [:phone, :tablet]
- assert_raise ArgumentError do
- request.variant = "yolo"
- end
+ assert @request.variant.phone?
+ assert @request.variant.tablet?
+ assert_not @request.variant.desktop?
+ assert @request.variant.any?(:tablet, :desktop)
+ assert_not @request.variant.any?(:desktop, :watch)
end
- test "reset variant" do
- request = stub_request
+ test 'clearing variant' do
+ @request.variant = nil
- request.variant = nil
- assert_equal nil, request.variant
+ assert @request.variant.empty?
+ assert_not @request.variant.phone?
+ assert_not @request.variant.any?(:phone, :tablet)
end
- test "setting variant with non symbol value" do
- request = stub_request
+ test 'setting variant to a non-symbol value' do
+ assert_raise ArgumentError do
+ @request.variant = 'phone'
+ end
+ end
+
+ test 'setting variant to an array containing a non-symbol value' do
assert_raise ArgumentError do
- request.variant = "mobile"
+ @request.variant = [:phone, 'tablet']
end
end
end
diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb
index c61423dce4..5fbd19acdf 100644
--- a/actionpack/test/dispatch/response_test.rb
+++ b/actionpack/test/dispatch/response_test.rb
@@ -254,10 +254,6 @@ class ResponseTest < ActiveSupport::TestCase
end
class ResponseIntegrationTest < ActionDispatch::IntegrationTest
- def app
- @app
- end
-
test "response cache control from railsish app" do
@app = lambda { |env|
ActionDispatch::Response.new.tap { |resp|
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index b4502c19d6..55fc160ac8 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -3583,7 +3583,11 @@ class TestAltApp < ActionDispatch::IntegrationTest
end
end
- AltRoutes = ActionDispatch::Routing::RouteSet.new(AltRequest)
+ AltRoutes = Class.new(ActionDispatch::Routing::RouteSet) {
+ def request_class
+ AltRequest
+ end
+ }.new
AltRoutes.draw do
get "/" => TestAltApp::XHeader.new, :constraints => {:x_header => /HEADER/}
get "/" => TestAltApp::AltApp.new
diff --git a/actionpack/test/dispatch/session/cache_store_test.rb b/actionpack/test/dispatch/session/cache_store_test.rb
index 9f810cad01..22a46b0930 100644
--- a/actionpack/test/dispatch/session/cache_store_test.rb
+++ b/actionpack/test/dispatch/session/cache_store_test.rb
@@ -22,7 +22,7 @@ class CacheStoreTest < ActionDispatch::IntegrationTest
end
def get_session_id
- render :text => "#{request.session_options[:id]}"
+ render :text => "#{request.session.id}"
end
def call_reset_session
diff --git a/actionpack/test/dispatch/session/cookie_store_test.rb b/actionpack/test/dispatch/session/cookie_store_test.rb
index 2194efa503..e7f4235de8 100644
--- a/actionpack/test/dispatch/session/cookie_store_test.rb
+++ b/actionpack/test/dispatch/session/cookie_store_test.rb
@@ -29,7 +29,7 @@ class CookieStoreTest < ActionDispatch::IntegrationTest
end
def get_session_id
- render :text => "id: #{request.session_options[:id]}"
+ render :text => "id: #{request.session.id}"
end
def get_class_after_reset_session
@@ -53,7 +53,7 @@ class CookieStoreTest < ActionDispatch::IntegrationTest
end
def change_session_id
- request.session_options[:id] = nil
+ request.session.options[:id] = nil
get_session_id
end
diff --git a/actionpack/test/dispatch/session/mem_cache_store_test.rb b/actionpack/test/dispatch/session/mem_cache_store_test.rb
index fbd82945cc..9a5d5131c0 100644
--- a/actionpack/test/dispatch/session/mem_cache_store_test.rb
+++ b/actionpack/test/dispatch/session/mem_cache_store_test.rb
@@ -23,7 +23,7 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
end
def get_session_id
- render :text => "#{request.session_options[:id]}"
+ render :text => "#{request.session.id}"
end
def call_reset_session
diff --git a/actionpack/test/dispatch/static_test.rb b/actionpack/test/dispatch/static_test.rb
index ebc9d71403..288a2084f6 100644
--- a/actionpack/test/dispatch/static_test.rb
+++ b/actionpack/test/dispatch/static_test.rb
@@ -143,6 +143,16 @@ module StaticTests
assert_equal default_response.headers['Content-Type'], response.headers['Content-Type']
end
+ def test_serves_gzip_files_with_not_modified
+ file_name = "/gzip/application-a71b3024f80aea3181c09774ca17e712.js"
+ last_modified = File.mtime(File.join(@root, "#{file_name}.gz"))
+ response = get(file_name, 'HTTP_ACCEPT_ENCODING' => 'gzip', 'HTTP_IF_MODIFIED_SINCE' => last_modified.httpdate)
+ assert_equal 304, response.status
+ assert_equal nil, response.headers['Content-Type']
+ assert_equal nil, response.headers['Content-Encoding']
+ assert_equal nil, response.headers['Vary']
+ end
+
# Windows doesn't allow \ / : * ? " < > | in filenames
unless RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
def test_serves_static_file_with_colon
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index 101f1263d9..74a677968f 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -1,3 +1,18 @@
+* `translate` should accept nils as members of the `:default`
+ parameter without raising a translation missing error. Fixes a
+ regression introduced 362557e.
+
+ Fixes #19419
+
+ *Justin Coyne*
+
+* `number_to_percentage` does not crash with `Float::NAN` or `Float::INFINITY`
+ as input when `precision: 0` is used.
+
+ Fixes #19227.
+
+ *Yves Senn*
+
* Fixed the translation helper method to accept different default values types
besides String.
diff --git a/actionview/Rakefile b/actionview/Rakefile
index 1b71435948..2b752b83df 100644
--- a/actionview/Rakefile
+++ b/actionview/Rakefile
@@ -18,7 +18,7 @@ namespace :test do
Rake::TestTask.new(:template) do |t|
t.libs << 'test'
- t.test_files = Dir.glob('test/template/**/*_test.rb').sort
+ t.test_files = Dir.glob('test/template/**/*_test.rb')
t.warning = true
t.verbose = true
t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION)
diff --git a/actionview/actionview.gemspec b/actionview/actionview.gemspec
index 8f9194cda7..d8ea9d562c 100644
--- a/actionview/actionview.gemspec
+++ b/actionview/actionview.gemspec
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
s.summary = 'Rendering framework putting the V in MVC (part of Rails).'
s.description = 'Simple, battle-tested conventions and helpers for building web pages.'
- s.required_ruby_version = '>= 2.2.0'
+ s.required_ruby_version = '>= 2.2.1'
s.license = 'MIT'
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
s.add_dependency 'builder', '~> 3.1'
s.add_dependency 'erubis', '~> 2.7.0'
- s.add_dependency 'rails-html-sanitizer', '~> 1.0', '>= 1.0.1'
+ s.add_dependency 'rails-html-sanitizer', '~> 1.0', '>= 1.0.2'
s.add_dependency 'rails-dom-testing', '~> 1.0', '>= 1.0.5'
s.add_development_dependency 'actionpack', version
diff --git a/actionview/lib/action_view/helpers/capture_helper.rb b/actionview/lib/action_view/helpers/capture_helper.rb
index 5a3223968f..a67ba580f1 100644
--- a/actionview/lib/action_view/helpers/capture_helper.rb
+++ b/actionview/lib/action_view/helpers/capture_helper.rb
@@ -195,7 +195,9 @@ module ActionView
def with_output_buffer(buf = nil) #:nodoc:
unless buf
buf = ActionView::OutputBuffer.new
- buf.force_encoding(output_buffer.encoding) if output_buffer
+ if output_buffer && output_buffer.respond_to?(:encoding)
+ buf.force_encoding(output_buffer.encoding)
+ end
end
self.output_buffer, old_buffer = buf, output_buffer
yield
diff --git a/actionview/lib/action_view/helpers/debug_helper.rb b/actionview/lib/action_view/helpers/debug_helper.rb
index ba47eee9ba..e9dccbad1c 100644
--- a/actionview/lib/action_view/helpers/debug_helper.rb
+++ b/actionview/lib/action_view/helpers/debug_helper.rb
@@ -26,7 +26,7 @@ module ActionView
Marshal::dump(object)
object = ERB::Util.html_escape(object.to_yaml)
content_tag(:pre, object, :class => "debug_dump")
- rescue Exception # errors from Marshal or YAML
+ rescue # errors from Marshal or YAML
# Object couldn't be dumped, perhaps because of singleton methods -- this is the fallback
content_tag(:code, object.inspect, :class => "debug_dump")
end
diff --git a/actionview/lib/action_view/helpers/form_helper.rb b/actionview/lib/action_view/helpers/form_helper.rb
index b0793d0b91..891cc53765 100644
--- a/actionview/lib/action_view/helpers/form_helper.rb
+++ b/actionview/lib/action_view/helpers/form_helper.rb
@@ -67,9 +67,10 @@ module ActionView
#
# In particular, thanks to the conventions followed in the generated field names, the
# controller gets a nested hash <tt>params[:person]</tt> with the person attributes
- # set in the form. That hash is ready to be passed to <tt>Person.create</tt>:
+ # set in the form. That hash is ready to be passed to <tt>Person.new</tt>:
#
- # if @person = Person.create(params[:person])
+ # @person = Person.new(params[:person])
+ # if @person.save
# # success
# else
# # error handling
@@ -140,6 +141,7 @@ module ActionView
# will get expanded to
#
# <%= text_field :person, :first_name %>
+ #
# which results in an HTML <tt><input></tt> tag whose +name+ attribute is
# <tt>person[first_name]</tt>. This means that when the form is submitted,
# the value entered by the user will be available in the controller as
diff --git a/actionview/lib/action_view/helpers/form_options_helper.rb b/actionview/lib/action_view/helpers/form_options_helper.rb
index bbfbf482a4..8a5928477f 100644
--- a/actionview/lib/action_view/helpers/form_options_helper.rb
+++ b/actionview/lib/action_view/helpers/form_options_helper.rb
@@ -18,10 +18,10 @@ module ActionView
#
# could become:
#
- # <select name="post[category]">
- # <option></option>
- # <option>joke</option>
- # <option>poem</option>
+ # <select name="post[category]" id="post_category">
+ # <option value=""></option>
+ # <option value="joke">joke</option>
+ # <option value="poem">poem</option>
# </select>
#
# Another common case is a select tag for a <tt>belongs_to</tt>-associated object.
@@ -32,7 +32,7 @@ module ActionView
#
# could become:
#
- # <select name="post[person_id]">
+ # <select name="post[person_id]" id="post_person_id">
# <option value="">None</option>
# <option value="1">David</option>
# <option value="2" selected="selected">Sam</option>
@@ -45,7 +45,7 @@ module ActionView
#
# could become:
#
- # <select name="post[person_id]">
+ # <select name="post[person_id]" id="post_person_id">
# <option value="">Select Person</option>
# <option value="1">David</option>
# <option value="2">Sam</option>
@@ -71,11 +71,11 @@ module ActionView
#
# could become:
#
- # <select name="post[category]">
- # <option></option>
- # <option>joke</option>
- # <option>poem</option>
- # <option disabled="disabled">restricted</option>
+ # <select name="post[category]" id="post_category">
+ # <option value=""></option>
+ # <option value="joke">joke</option>
+ # <option value="poem">poem</option>
+ # <option disabled="disabled" value="restricted">restricted</option>
# </select>
#
# When used with the <tt>collection_select</tt> helper, <tt>:disabled</tt> can also be a Proc that identifies those options that should be disabled.
@@ -83,7 +83,7 @@ module ActionView
# collection_select(:post, :category_id, Category.all, :id, :name, {disabled: lambda{|category| category.archived? }})
#
# If the categories "2008 stuff" and "Christmas" return true when the method <tt>archived?</tt> is called, this would return:
- # <select name="post[category_id]">
+ # <select name="post[category_id]" id="post_category_id">
# <option value="1" disabled="disabled">2008 stuff</option>
# <option value="2" disabled="disabled">Christmas</option>
# <option value="3">Jokes</option>
@@ -109,7 +109,7 @@ module ActionView
#
# would become:
#
- # <select name="post[person_id]">
+ # <select name="post[person_id]" id="post_person_id">
# <option value=""></option>
# <option value="1" selected="selected">David</option>
# <option value="2">Sam</option>
@@ -192,7 +192,7 @@ module ActionView
# collection_select(:post, :author_id, Author.all, :id, :name_with_initial, prompt: true)
#
# If <tt>@post.author_id</tt> is already <tt>1</tt>, this would return:
- # <select name="post[author_id]">
+ # <select name="post[author_id]" id="post_author_id">
# <option value="">Please select</option>
# <option value="1" selected="selected">D. Heinemeier Hansson</option>
# <option value="2">D. Thomas</option>
@@ -243,7 +243,7 @@ module ActionView
#
# Possible output:
#
- # <select name="city[country_id]">
+ # <select name="city[country_id]" id="city_country_id">
# <optgroup label="Africa">
# <option value="1">South Africa</option>
# <option value="3">Somalia</option>
@@ -302,17 +302,17 @@ module ActionView
# # => <option value="DKK">Kroner</option>
#
# options_for_select([ "VISA", "MasterCard" ], "MasterCard")
- # # => <option>VISA</option>
- # # => <option selected="selected">MasterCard</option>
+ # # => <option value="VISA">VISA</option>
+ # # => <option selected="selected" value="MasterCard">MasterCard</option>
#
# options_for_select({ "Basic" => "$20", "Plus" => "$40" }, "$40")
# # => <option value="$20">Basic</option>
# # => <option value="$40" selected="selected">Plus</option>
#
# options_for_select([ "VISA", "MasterCard", "Discover" ], ["VISA", "Discover"])
- # # => <option selected="selected">VISA</option>
- # # => <option>MasterCard</option>
- # # => <option selected="selected">Discover</option>
+ # # => <option selected="selected" value="VISA">VISA</option>
+ # # => <option value="MasterCard">MasterCard</option>
+ # # => <option selected="selected" value="Discover">Discover</option>
#
# You can optionally provide HTML attributes as the last element of the array.
#
diff --git a/actionview/lib/action_view/helpers/javascript_helper.rb b/actionview/lib/action_view/helpers/javascript_helper.rb
index 629c447f3f..e237a32cb7 100644
--- a/actionview/lib/action_view/helpers/javascript_helper.rb
+++ b/actionview/lib/action_view/helpers/javascript_helper.rb
@@ -21,7 +21,7 @@ module ActionView
# Also available through the alias j(). This is particularly helpful in JavaScript
# responses, like:
#
- # $('some_element').replaceWith('<%=j render 'some/element_template' %>');
+ # $('some_element').replaceWith('<%= j render 'some/element_template' %>');
def escape_javascript(javascript)
if javascript
result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"'])/u) {|match| JS_ESCAPE_MAP[match] }
diff --git a/actionview/lib/action_view/helpers/number_helper.rb b/actionview/lib/action_view/helpers/number_helper.rb
index cfd617cedc..ca8d30e4ef 100644
--- a/actionview/lib/action_view/helpers/number_helper.rb
+++ b/actionview/lib/action_view/helpers/number_helper.rb
@@ -116,8 +116,8 @@ module ActionView
# (defaults to current locale).
# * <tt>:precision</tt> - Sets the precision of the number
# (defaults to 3).
- # * <tt>:significant</tt> - If +true+, precision will be the #
- # of significant_digits. If +false+, the # of fractional
+ # * <tt>:significant</tt> - If +true+, precision will be the number
+ # of significant_digits. If +false+, the number of fractional
# digits (defaults to +false+).
# * <tt>:separator</tt> - Sets the separator between the
# fractional and integer digits (defaults to ".").
@@ -191,8 +191,8 @@ module ActionView
# (defaults to current locale).
# * <tt>:precision</tt> - Sets the precision of the number
# (defaults to 3).
- # * <tt>:significant</tt> - If +true+, precision will be the #
- # of significant_digits. If +false+, the # of fractional
+ # * <tt>:significant</tt> - If +true+, precision will be the number
+ # of significant_digits. If +false+, the number of fractional
# digits (defaults to +false+).
# * <tt>:separator</tt> - Sets the separator between the
# fractional and integer digits (defaults to ".").
@@ -239,8 +239,8 @@ module ActionView
# (defaults to current locale).
# * <tt>:precision</tt> - Sets the precision of the number
# (defaults to 3).
- # * <tt>:significant</tt> - If +true+, precision will be the #
- # of significant_digits. If +false+, the # of fractional
+ # * <tt>:significant</tt> - If +true+, precision will be the number
+ # of significant_digits. If +false+, the number of fractional
# digits (defaults to +true+)
# * <tt>:separator</tt> - Sets the separator between the
# fractional and integer digits (defaults to ".").
@@ -291,8 +291,8 @@ module ActionView
# (defaults to current locale).
# * <tt>:precision</tt> - Sets the precision of the number
# (defaults to 3).
- # * <tt>:significant</tt> - If +true+, precision will be the #
- # of significant_digits. If +false+, the # of fractional
+ # * <tt>:significant</tt> - If +true+, precision will be the number
+ # of significant_digits. If +false+, the number of fractional
# digits (defaults to +true+)
# * <tt>:separator</tt> - Sets the separator between the
# fractional and integer digits (defaults to ".").
diff --git a/actionview/lib/action_view/helpers/sanitize_helper.rb b/actionview/lib/action_view/helpers/sanitize_helper.rb
index 463a4e9f60..a2e9f37453 100644
--- a/actionview/lib/action_view/helpers/sanitize_helper.rb
+++ b/actionview/lib/action_view/helpers/sanitize_helper.rb
@@ -99,7 +99,7 @@ module ActionView
# strip_tags("<div id='top-bar'>Welcome to my website!</div>")
# # => Welcome to my website!
def strip_tags(html)
- self.class.full_sanitizer.sanitize(html)
+ self.class.full_sanitizer.sanitize(html, encode_special_chars: false)
end
# Strips all link tags from +html+ leaving just the link text.
diff --git a/actionview/lib/action_view/helpers/text_helper.rb b/actionview/lib/action_view/helpers/text_helper.rb
index 2c40ed1832..c216d4401f 100644
--- a/actionview/lib/action_view/helpers/text_helper.rb
+++ b/actionview/lib/action_view/helpers/text_helper.rb
@@ -103,7 +103,9 @@ module ActionView
# Highlights one or more +phrases+ everywhere in +text+ by inserting it into
# a <tt>:highlighter</tt> string. The highlighter can be specialized by passing <tt>:highlighter</tt>
# as a single-quoted string with <tt>\1</tt> where the phrase is to be inserted (defaults to
- # '<mark>\1</mark>') or passing a block that receives each matched term.
+ # '<mark>\1</mark>') or passing a block that receives each matched term. By default +text+
+ # is sanitized to prevent possible XSS attacks. If the input is trustworthy, passing false
+ # for <tt>:sanitize</tt> will turn sanitizing off.
#
# highlight('You searched for: rails', 'rails')
# # => You searched for: <mark>rails</mark>
@@ -122,6 +124,9 @@ module ActionView
#
# highlight('You searched for: rails', 'rails') { |match| link_to(search_path(q: match, match)) }
# # => You searched for: <a href="search?q=rails">rails</a>
+ #
+ # highlight('<a href="javascript:alert(\'no!\')">ruby</a> on rails', 'rails', sanitize: false)
+ # # => "<a>ruby</a> on <mark>rails</mark>"
def highlight(text, phrases, options = {})
text = sanitize(text) if options.fetch(:sanitize, true)
diff --git a/actionview/lib/action_view/helpers/translation_helper.rb b/actionview/lib/action_view/helpers/translation_helper.rb
index 24b633c5bb..29a0860c00 100644
--- a/actionview/lib/action_view/helpers/translation_helper.rb
+++ b/actionview/lib/action_view/helpers/translation_helper.rb
@@ -38,7 +38,7 @@ module ActionView
def translate(key, options = {})
options = options.dup
has_default = options.has_key?(:default)
- remaining_defaults = Array(options.delete(:default))
+ remaining_defaults = Array(options.delete(:default)).compact
if has_default && !remaining_defaults.first.kind_of?(Symbol)
options[:default] = remaining_defaults.shift
diff --git a/actionview/lib/action_view/helpers/url_helper.rb b/actionview/lib/action_view/helpers/url_helper.rb
index 3dbce0738e..89b96ac42c 100644
--- a/actionview/lib/action_view/helpers/url_helper.rb
+++ b/actionview/lib/action_view/helpers/url_helper.rb
@@ -280,9 +280,7 @@ module ActionView
html_options, options = options, name if block_given?
options ||= {}
html_options ||= {}
-
html_options = html_options.stringify_keys
- convert_boolean_attributes!(html_options, %w(disabled))
url = options.is_a?(String) ? options : url_for(options)
remote = html_options.delete('remote')
@@ -294,8 +292,9 @@ module ActionView
form_method = method == 'get' ? 'get' : 'post'
form_options = html_options.delete('form') || {}
form_options[:class] ||= html_options.delete('form_class') || 'button_to'
- form_options.merge!(method: form_method, action: url)
- form_options.merge!("data-remote" => "true") if remote
+ form_options[:method] = form_method
+ form_options[:action] = url
+ form_options[:'data-remote'] = true if remote
request_token_tag = form_method == 'post' ? token_tag : ''
@@ -576,34 +575,6 @@ module ActionView
html_options["data-method"] = method
end
- # Processes the +html_options+ hash, converting the boolean
- # attributes from true/false form into the form required by
- # HTML/XHTML. (An attribute is considered to be boolean if
- # its name is listed in the given +bool_attrs+ array.)
- #
- # More specifically, for each boolean attribute in +html_options+
- # given as:
- #
- # "attr" => bool_value
- #
- # if the associated +bool_value+ evaluates to true, it is
- # replaced with the attribute's name; otherwise the attribute is
- # removed from the +html_options+ hash. (See the XHTML 1.0 spec,
- # section 4.5 "Attribute Minimization" for more:
- # http://www.w3.org/TR/xhtml1/#h-4.5)
- #
- # Returns the updated +html_options+ hash, which is also modified
- # in place.
- #
- # Example:
- #
- # convert_boolean_attributes!( html_options,
- # %w( checked disabled readonly ) )
- def convert_boolean_attributes!(html_options, bool_attrs)
- bool_attrs.each { |x| html_options[x] = x if html_options.delete(x) }
- html_options
- end
-
def token_tag(token=nil)
if token != false && protect_against_forgery?
token ||= form_authenticity_token
diff --git a/actionview/lib/action_view/layouts.rb b/actionview/lib/action_view/layouts.rb
index 0b5c0b9991..9d636c8c9e 100644
--- a/actionview/lib/action_view/layouts.rb
+++ b/actionview/lib/action_view/layouts.rb
@@ -228,7 +228,7 @@ module ActionView
# set by the <tt>layout</tt> method.
#
# ==== Returns
- # * <tt> Boolean</tt> - True if the action has a layout definition, false otherwise.
+ # * <tt>Boolean</tt> - True if the action has a layout definition, false otherwise.
def _conditional_layout?
return unless super
diff --git a/actionview/lib/action_view/renderer/partial_renderer.rb b/actionview/lib/action_view/renderer/partial_renderer.rb
index 56b8ab1e2d..cd151c0189 100644
--- a/actionview/lib/action_view/renderer/partial_renderer.rb
+++ b/actionview/lib/action_view/renderer/partial_renderer.rb
@@ -154,23 +154,23 @@ module ActionView
# specified globally for the entire action, but they work in a similar fashion. Imagine a list with two types
# of users:
#
- # <%# app/views/users/index.html.erb &>
+ # <%# app/views/users/index.html.erb %>
# Here's the administrator:
# <%= render partial: "user", layout: "administrator", locals: { user: administrator } %>
#
# Here's the editor:
# <%= render partial: "user", layout: "editor", locals: { user: editor } %>
#
- # <%# app/views/users/_user.html.erb &>
+ # <%# app/views/users/_user.html.erb %>
# Name: <%= user.name %>
#
- # <%# app/views/users/_administrator.html.erb &>
+ # <%# app/views/users/_administrator.html.erb %>
# <div id="administrator">
# Budget: $<%= user.budget %>
# <%= yield %>
# </div>
#
- # <%# app/views/users/_editor.html.erb &>
+ # <%# app/views/users/_editor.html.erb %>
# <div id="editor">
# Deadline: <%= user.deadline %>
# <%= yield %>
@@ -233,7 +233,7 @@ module ActionView
#
# You can also apply a layout to a block within any template:
#
- # <%# app/views/users/_chief.html.erb &>
+ # <%# app/views/users/_chief.html.erb %>
# <%= render(layout: "administrator", locals: { user: chief }) do %>
# Title: <%= chief.title %>
# <% end %>
@@ -250,13 +250,13 @@ module ActionView
# If you pass arguments to "yield" then this will be passed to the block. One way to use this is to pass
# an array to layout and treat it as an enumerable.
#
- # <%# app/views/users/_user.html.erb &>
+ # <%# app/views/users/_user.html.erb %>
# <div class="user">
# Budget: $<%= user.budget %>
# <%= yield user %>
# </div>
#
- # <%# app/views/users/index.html.erb &>
+ # <%# app/views/users/index.html.erb %>
# <%= render layout: @users do |user| %>
# Title: <%= user.title %>
# <% end %>
@@ -265,14 +265,14 @@ module ActionView
#
# You can also yield multiple times in one layout and use block arguments to differentiate the sections.
#
- # <%# app/views/users/_user.html.erb &>
+ # <%# app/views/users/_user.html.erb %>
# <div class="user">
# <%= yield user, :header %>
# Budget: $<%= user.budget %>
# <%= yield user, :footer %>
# </div>
#
- # <%# app/views/users/index.html.erb &>
+ # <%# app/views/users/index.html.erb %>
# <%= render layout: @users do |user, section| %>
# <%- case section when :header -%>
# Title: <%= user.title %>
diff --git a/actionview/lib/action_view/renderer/renderer.rb b/actionview/lib/action_view/renderer/renderer.rb
index 964b18337e..1bee35d80d 100644
--- a/actionview/lib/action_view/renderer/renderer.rb
+++ b/actionview/lib/action_view/renderer/renderer.rb
@@ -37,7 +37,7 @@ module ActionView
end
end
- # Direct accessor to template rendering.
+ # Direct access to template rendering.
def render_template(context, options) #:nodoc:
TemplateRenderer.new(@lookup_context).render(context, options)
end
diff --git a/actionview/lib/action_view/renderer/template_renderer.rb b/actionview/lib/action_view/renderer/template_renderer.rb
index cd21d7ab47..dbb4855e39 100644
--- a/actionview/lib/action_view/renderer/template_renderer.rb
+++ b/actionview/lib/action_view/renderer/template_renderer.rb
@@ -40,7 +40,7 @@ module ActionView
find_template(options[:template], options[:prefixes], false, keys, @details)
end
else
- raise ArgumentError, "You invoked render but did not give any of :partial, :template, :inline, :file, :plain, :text or :body option."
+ raise ArgumentError, "You invoked render but did not give any of :partial, :template, :inline, :file, :plain, :html, :text or :body option."
end
end
diff --git a/actionview/test/abstract_unit.rb b/actionview/test/abstract_unit.rb
index fc1ca9efdf..4635c645d0 100644
--- a/actionview/test/abstract_unit.rb
+++ b/actionview/test/abstract_unit.rb
@@ -49,20 +49,6 @@ I18n.backend.store_translations 'pt-BR', {}
ORIGINAL_LOCALES = I18n.available_locales.map(&:to_s).sort
FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
-FIXTURES = Pathname.new(FIXTURE_LOAD_PATH)
-
-module RackTestUtils
- def body_to_string(body)
- if body.respond_to?(:each)
- str = ""
- body.each {|s| str << s }
- str
- else
- body
- end
- end
- extend self
-end
module RenderERBUtils
def view
@@ -225,49 +211,6 @@ class ActionDispatch::IntegrationTest < ActiveSupport::TestCase
end
end
-# Temporary base class
-class Rack::TestCase < ActionDispatch::IntegrationTest
- def self.testing(klass = nil)
- if klass
- @testing = "/#{klass.name.underscore}".sub!(/_controller$/, '')
- else
- @testing
- end
- end
-
- def get(thing, *args)
- if thing.is_a?(Symbol)
- super("#{self.class.testing}/#{thing}", *args)
- else
- super
- end
- end
-
- def assert_body(body)
- assert_equal body, Array(response.body).join
- end
-
- def assert_status(code)
- assert_equal code, response.status
- end
-
- def assert_response(body, status = 200, headers = {})
- assert_body body
- assert_status status
- headers.each do |header, value|
- assert_header header, value
- end
- end
-
- def assert_content_type(type)
- assert_equal type, response.headers["Content-Type"]
- end
-
- def assert_header(name, value)
- assert_equal value, response.headers[name]
- end
-end
-
ActionView::RoutingUrlFor.include(ActionDispatch::Routing::UrlFor)
module ActionController
@@ -338,8 +281,3 @@ def jruby_skip(message = '')
end
require 'mocha/setup' # FIXME: stop using mocha
-
-# FIXME: we have tests that depend on run order, we should fix that and
-# remove this method call.
-require 'active_support/test_case'
-ActiveSupport::TestCase.test_order = :sorted
diff --git a/actionview/test/actionpack/abstract/views/abstract_controller/testing/me5/index.erb b/actionview/test/actionpack/abstract/views/abstract_controller/testing/me5/index.erb
deleted file mode 100644
index 84d0b7417e..0000000000
--- a/actionview/test/actionpack/abstract/views/abstract_controller/testing/me5/index.erb
+++ /dev/null
@@ -1 +0,0 @@
-Hello from me5/index.erb \ No newline at end of file
diff --git a/actionview/test/active_record_unit.rb b/actionview/test/active_record_unit.rb
index cca55c9af4..f9e94413b5 100644
--- a/actionview/test/active_record_unit.rb
+++ b/actionview/test/active_record_unit.rb
@@ -76,7 +76,7 @@ class ActiveRecordTestCase < ActionController::TestCase
# Set our fixture path
if ActiveRecordTestConnector.able_to_connect
self.fixture_path = [FIXTURE_LOAD_PATH]
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
end
def self.fixtures(*args)
diff --git a/actionview/test/activerecord/debug_helper_test.rb b/actionview/test/activerecord/debug_helper_test.rb
index 5609694cd5..03cb1d5a91 100644
--- a/actionview/test/activerecord/debug_helper_test.rb
+++ b/actionview/test/activerecord/debug_helper_test.rb
@@ -1,8 +1,14 @@
require 'active_record_unit'
+require 'nokogiri'
class DebugHelperTest < ActionView::TestCase
def test_debug
company = Company.new(name: "firebase")
assert_match "name: firebase", debug(company)
end
+
+ def test_debug_with_marshal_error
+ obj = -> { }
+ assert_match obj.inspect, Nokogiri.XML(debug(obj)).content
+ end
end
diff --git a/actionview/test/fixtures/layouts/streaming_with_capture.erb b/actionview/test/fixtures/layouts/streaming_with_capture.erb
new file mode 100644
index 0000000000..538c19ce3a
--- /dev/null
+++ b/actionview/test/fixtures/layouts/streaming_with_capture.erb
@@ -0,0 +1,6 @@
+<%= yield :header -%>
+<%= capture do %>
+ this works
+<% end %>
+<%= yield :footer -%>
+<%= yield(:unknown).presence || "." -%>
diff --git a/actionview/test/fixtures/multipart/bracketed_utf8_param b/actionview/test/fixtures/multipart/bracketed_utf8_param
deleted file mode 100644
index df9cecea08..0000000000
--- a/actionview/test/fixtures/multipart/bracketed_utf8_param
+++ /dev/null
@@ -1,5 +0,0 @@
---AaB03x
-Content-Disposition: form-data; name="Iñtërnâtiônàlizætiøn_name[Iñtërnâtiônàlizætiøn_nested_name]"
-
-Iñtërnâtiônàlizætiøn_value
---AaB03x--
diff --git a/actionview/test/fixtures/multipart/single_utf8_param b/actionview/test/fixtures/multipart/single_utf8_param
deleted file mode 100644
index 1d9fae7b17..0000000000
--- a/actionview/test/fixtures/multipart/single_utf8_param
+++ /dev/null
@@ -1,5 +0,0 @@
---AaB03x
-Content-Disposition: form-data; name="Iñtërnâtiônàlizætiøn_name"
-
-Iñtërnâtiônàlizætiøn_value
---AaB03x--
diff --git a/actionview/test/template/asset_tag_helper_test.rb b/actionview/test/template/asset_tag_helper_test.rb
index a15c6fac90..02dce71496 100644
--- a/actionview/test/template/asset_tag_helper_test.rb
+++ b/actionview/test/template/asset_tag_helper_test.rb
@@ -1,4 +1,3 @@
-require 'zlib'
require 'abstract_unit'
require 'active_support/ordered_options'
diff --git a/actionview/test/template/form_tag_helper_test.rb b/actionview/test/template/form_tag_helper_test.rb
index 84a581b107..cad1c82309 100644
--- a/actionview/test/template/form_tag_helper_test.rb
+++ b/actionview/test/template/form_tag_helper_test.rb
@@ -210,13 +210,13 @@ class FormTagHelperTest < ActionView::TestCase
end
def test_select_tag_with_multiple
- actual = select_tag "colors", "<option>Red</option><option>Blue</option><option>Green</option>".html_safe, :multiple => :true
- expected = %(<select id="colors" multiple="multiple" name="colors"><option>Red</option><option>Blue</option><option>Green</option></select>)
+ actual = select_tag "colors", "<option>Red</option><option>Blue</option><option>Green</option>".html_safe, multiple: true
+ expected = %(<select id="colors" multiple="multiple" name="colors[]"><option>Red</option><option>Blue</option><option>Green</option></select>)
assert_dom_equal expected, actual
end
def test_select_tag_disabled
- actual = select_tag "places", "<option>Home</option><option>Work</option><option>Pub</option>".html_safe, :disabled => :true
+ actual = select_tag "places", "<option>Home</option><option>Work</option><option>Pub</option>".html_safe, disabled: true
expected = %(<select id="places" disabled="disabled" name="places"><option>Home</option><option>Work</option><option>Pub</option></select>)
assert_dom_equal expected, actual
end
@@ -352,7 +352,7 @@ class FormTagHelperTest < ActionView::TestCase
end
def test_text_field_disabled
- actual = text_field_tag "title", "Hello!", :disabled => :true
+ actual = text_field_tag "title", "Hello!", disabled: true
expected = %(<input id="title" name="title" disabled="disabled" type="text" value="Hello!" />)
assert_dom_equal expected, actual
end
diff --git a/actionview/test/template/javascript_helper_test.rb b/actionview/test/template/javascript_helper_test.rb
index 9ba7f64ad1..9f1535ef53 100644
--- a/actionview/test/template/javascript_helper_test.rb
+++ b/actionview/test/template/javascript_helper_test.rb
@@ -3,14 +3,7 @@ require 'abstract_unit'
class JavaScriptHelperTest < ActionView::TestCase
tests ActionView::Helpers::JavaScriptHelper
- def _evaluate_assigns_and_ivars() end
-
- attr_accessor :formats, :output_buffer
-
- def update_details(details)
- @details = details
- yield if block_given?
- end
+ attr_accessor :output_buffer
setup do
@old_escape_html_entities_in_json = ActiveSupport.escape_html_entities_in_json
diff --git a/actionview/test/template/number_helper_test.rb b/actionview/test/template/number_helper_test.rb
index b59883b760..b70b750869 100644
--- a/actionview/test/template/number_helper_test.rb
+++ b/actionview/test/template/number_helper_test.rb
@@ -35,6 +35,10 @@ class NumberHelperTest < ActionView::TestCase
assert_equal "98a%", number_to_percentage("98a")
assert_equal "NaN%", number_to_percentage(Float::NAN)
assert_equal "Inf%", number_to_percentage(Float::INFINITY)
+ assert_equal "NaN%", number_to_percentage(Float::NAN, precision: 0)
+ assert_equal "Inf%", number_to_percentage(Float::INFINITY, precision: 0)
+ assert_equal "NaN%", number_to_percentage(Float::NAN, precision: 1)
+ assert_equal "Inf%", number_to_percentage(Float::INFINITY, precision: 1)
end
def test_number_with_delimiter
diff --git a/actionview/test/template/sanitize_helper_test.rb b/actionview/test/template/sanitize_helper_test.rb
index e4be21be2c..efe846a7eb 100644
--- a/actionview/test/template/sanitize_helper_test.rb
+++ b/actionview/test/template/sanitize_helper_test.rb
@@ -29,6 +29,10 @@ class SanitizeHelperTest < ActionView::TestCase
assert_equal "", strip_tags("<script>")
end
+ def test_strip_tags_will_not_encode_special_characters
+ assert_equal "test\r\n\r\ntest", strip_tags("test\r\n\r\ntest")
+ end
+
def test_sanitize_is_marked_safe
assert sanitize("<html><script></script></html>").html_safe?
end
diff --git a/actionview/test/template/streaming_render_test.rb b/actionview/test/template/streaming_render_test.rb
index ec537775be..d06ba4ceb0 100644
--- a/actionview/test/template/streaming_render_test.rb
+++ b/actionview/test/template/streaming_render_test.rb
@@ -104,4 +104,8 @@ class FiberedTest < ActiveSupport::TestCase
buffered_render(:template => "test/nested_streaming", :layout => "layouts/streaming")
end
+ def test_render_with_streaming_and_capture
+ assert_equal "Yes, \n this works\n like a charm.",
+ buffered_render(template: "test/streaming", layout: "layouts/streaming_with_capture")
+ end
end
diff --git a/actionview/test/template/translation_helper_test.rb b/actionview/test/template/translation_helper_test.rb
index ef4d13efa7..c4daaae221 100644
--- a/actionview/test/template/translation_helper_test.rb
+++ b/actionview/test/template/translation_helper_test.rb
@@ -190,6 +190,11 @@ class TranslationHelperTest < ActiveSupport::TestCase
assert_equal 'A Generic String', translation
end
+ def test_translate_with_array_of_defaults_with_nil
+ translation = translate(:'translations.missing', default: [:'also_missing', nil, 'A Generic String'])
+ assert_equal 'A Generic String', translation
+ end
+
def test_translate_does_not_change_options
options = {}
translate(:'translations.missing', options)
diff --git a/activejob/CHANGELOG.md b/activejob/CHANGELOG.md
index d4e19274fa..85a437a1dd 100644
--- a/activejob/CHANGELOG.md
+++ b/activejob/CHANGELOG.md
@@ -1,3 +1,7 @@
+* A generated job now inherents from `app/jobs/application_job.rb` by default.
+
+ *Jeroen van Baarsen*
+
* Add an `:only` option to `perform_enqueued_jobs` to filter jobs based on
type.
diff --git a/activejob/activejob.gemspec b/activejob/activejob.gemspec
index 5404ece804..ef8db3bcd3 100644
--- a/activejob/activejob.gemspec
+++ b/activejob/activejob.gemspec
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
s.summary = 'Job framework with pluggable queues.'
s.description = 'Declare job classes that can be run by a variety of queueing backends.'
- s.required_ruby_version = '>= 2.2.0'
+ s.required_ruby_version = '>= 2.2.1'
s.license = 'MIT'
diff --git a/activejob/lib/active_job/logging.rb b/activejob/lib/active_job/logging.rb
index cd29e6908e..54774db601 100644
--- a/activejob/lib/active_job/logging.rb
+++ b/activejob/lib/active_job/logging.rb
@@ -81,7 +81,7 @@ module ActiveJob
private
def queue_name(event)
- event.payload[:adapter].name.demodulize.remove('Adapter') + "(#{event.payload[:job].queue_name})"
+ event.payload[:adapter].class.name.demodulize.remove('Adapter') + "(#{event.payload[:job].queue_name})"
end
def args_info(job)
diff --git a/activejob/lib/active_job/queue_adapter.rb b/activejob/lib/active_job/queue_adapter.rb
index aa3ebdbc7b..9c4519432d 100644
--- a/activejob/lib/active_job/queue_adapter.rb
+++ b/activejob/lib/active_job/queue_adapter.rb
@@ -1,4 +1,5 @@
require 'active_job/queue_adapters/inline_adapter'
+require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/string/inflections'
module ActiveJob
@@ -7,27 +8,54 @@ module ActiveJob
module QueueAdapter #:nodoc:
extend ActiveSupport::Concern
+ included do
+ class_attribute :_queue_adapter, instance_accessor: false, instance_predicate: false
+ self.queue_adapter = :inline
+ end
+
# Includes the setter method for changing the active queue adapter.
module ClassMethods
- mattr_reader(:queue_adapter) { ActiveJob::QueueAdapters::InlineAdapter }
+ def queue_adapter
+ _queue_adapter
+ end
# Specify the backend queue provider. The default queue adapter
# is the :inline queue. See QueueAdapters for more
# information.
- def queue_adapter=(name_or_adapter)
- @@queue_adapter = \
- case name_or_adapter
- when Symbol, String
- load_adapter(name_or_adapter)
- else
- name_or_adapter if name_or_adapter.respond_to?(:enqueue)
- end
+ def queue_adapter=(name_or_adapter_or_class)
+ self._queue_adapter = interpret_adapter(name_or_adapter_or_class)
end
private
- def load_adapter(name)
- "ActiveJob::QueueAdapters::#{name.to_s.camelize}Adapter".constantize
+
+ def interpret_adapter(name_or_adapter_or_class)
+ case name_or_adapter_or_class
+ when Symbol, String
+ ActiveJob::QueueAdapters.lookup(name_or_adapter_or_class).new
+ else
+ if queue_adapter?(name_or_adapter_or_class)
+ name_or_adapter_or_class
+ elsif queue_adapter_class?(name_or_adapter_or_class)
+ ActiveSupport::Deprecation.warn "Passing an adapter class is deprecated " \
+ "and will be removed in Rails 5.1. Please pass an adapter name " \
+ "(.queue_adapter = :#{name_or_adapter_or_class.name.demodulize.remove('Adapter').underscore}) " \
+ "or an instance (.queue_adapter = #{name_or_adapter_or_class.name}.new) instead."
+ name_or_adapter_or_class.new
+ else
+ raise ArgumentError
+ end
end
+ end
+
+ QUEUE_ADAPTER_METHODS = [:enqueue, :enqueue_at].freeze
+
+ def queue_adapter?(object)
+ QUEUE_ADAPTER_METHODS.all? { |meth| object.respond_to?(meth) }
+ end
+
+ def queue_adapter_class?(object)
+ object.is_a?(Class) && QUEUE_ADAPTER_METHODS.all? { |meth| object.public_method_defined?(meth) }
+ end
end
end
end
diff --git a/activejob/lib/active_job/queue_adapters.rb b/activejob/lib/active_job/queue_adapters.rb
index 4b91c93dbe..b3d91dc562 100644
--- a/activejob/lib/active_job/queue_adapters.rb
+++ b/activejob/lib/active_job/queue_adapters.rb
@@ -48,5 +48,14 @@ module ActiveJob
autoload :SneakersAdapter
autoload :SuckerPunchAdapter
autoload :TestAdapter
+
+ ADAPTER = 'Adapter'.freeze
+ private_constant :ADAPTER
+
+ class << self
+ def lookup(name)
+ const_get(name.to_s.camelize << ADAPTER)
+ end
+ end
end
end
diff --git a/activejob/lib/active_job/queue_adapters/backburner_adapter.rb b/activejob/lib/active_job/queue_adapters/backburner_adapter.rb
index 2453d065de..17703e3e41 100644
--- a/activejob/lib/active_job/queue_adapters/backburner_adapter.rb
+++ b/activejob/lib/active_job/queue_adapters/backburner_adapter.rb
@@ -13,15 +13,13 @@ module ActiveJob
#
# Rails.application.config.active_job.queue_adapter = :backburner
class BackburnerAdapter
- class << self
- def enqueue(job) #:nodoc:
- Backburner::Worker.enqueue JobWrapper, [ job.serialize ], queue: job.queue_name
- end
+ def enqueue(job) #:nodoc:
+ Backburner::Worker.enqueue JobWrapper, [ job.serialize ], queue: job.queue_name
+ end
- def enqueue_at(job, timestamp) #:nodoc:
- delay = timestamp - Time.current.to_f
- Backburner::Worker.enqueue JobWrapper, [ job.serialize ], queue: job.queue_name, delay: delay
- end
+ def enqueue_at(job, timestamp) #:nodoc:
+ delay = timestamp - Time.current.to_f
+ Backburner::Worker.enqueue JobWrapper, [ job.serialize ], queue: job.queue_name, delay: delay
end
class JobWrapper #:nodoc:
diff --git a/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb b/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb
index 69d9e70de3..852a6ee326 100644
--- a/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb
+++ b/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb
@@ -13,14 +13,12 @@ module ActiveJob
#
# Rails.application.config.active_job.queue_adapter = :delayed_job
class DelayedJobAdapter
- class << self
- def enqueue(job) #:nodoc:
- Delayed::Job.enqueue(JobWrapper.new(job.serialize), queue: job.queue_name)
- end
+ def enqueue(job) #:nodoc:
+ Delayed::Job.enqueue(JobWrapper.new(job.serialize), queue: job.queue_name)
+ end
- def enqueue_at(job, timestamp) #:nodoc:
- Delayed::Job.enqueue(JobWrapper.new(job.serialize), queue: job.queue_name, run_at: Time.at(timestamp))
- end
+ def enqueue_at(job, timestamp) #:nodoc:
+ Delayed::Job.enqueue(JobWrapper.new(job.serialize), queue: job.queue_name, run_at: Time.at(timestamp))
end
class JobWrapper #:nodoc:
diff --git a/activejob/lib/active_job/queue_adapters/inline_adapter.rb b/activejob/lib/active_job/queue_adapters/inline_adapter.rb
index e25d88e723..1d06324c18 100644
--- a/activejob/lib/active_job/queue_adapters/inline_adapter.rb
+++ b/activejob/lib/active_job/queue_adapters/inline_adapter.rb
@@ -9,14 +9,12 @@ module ActiveJob
#
# Rails.application.config.active_job.queue_adapter = :inline
class InlineAdapter
- class << self
- def enqueue(job) #:nodoc:
- Base.execute(job.serialize)
- end
+ def enqueue(job) #:nodoc:
+ Base.execute(job.serialize)
+ end
- def enqueue_at(*) #:nodoc:
- raise NotImplementedError.new("Use a queueing backend to enqueue jobs in the future. Read more at http://guides.rubyonrails.org/active_job_basics.html")
- end
+ def enqueue_at(*) #:nodoc:
+ raise NotImplementedError.new("Use a queueing backend to enqueue jobs in the future. Read more at http://guides.rubyonrails.org/active_job_basics.html")
end
end
end
diff --git a/activejob/lib/active_job/queue_adapters/qu_adapter.rb b/activejob/lib/active_job/queue_adapters/qu_adapter.rb
index 30aa5a4670..94584ef9d8 100644
--- a/activejob/lib/active_job/queue_adapters/qu_adapter.rb
+++ b/activejob/lib/active_job/queue_adapters/qu_adapter.rb
@@ -16,16 +16,14 @@ module ActiveJob
#
# Rails.application.config.active_job.queue_adapter = :qu
class QuAdapter
- class << self
- def enqueue(job, *args) #:nodoc:
- Qu::Payload.new(klass: JobWrapper, args: [job.serialize]).tap do |payload|
- payload.instance_variable_set(:@queue, job.queue_name)
- end.push
- end
+ def enqueue(job, *args) #:nodoc:
+ Qu::Payload.new(klass: JobWrapper, args: [job.serialize]).tap do |payload|
+ payload.instance_variable_set(:@queue, job.queue_name)
+ end.push
+ end
- def enqueue_at(job, timestamp, *args) #:nodoc:
- raise NotImplementedError
- end
+ def enqueue_at(job, timestamp, *args) #:nodoc:
+ raise NotImplementedError
end
class JobWrapper < Qu::Job #:nodoc:
diff --git a/activejob/lib/active_job/queue_adapters/que_adapter.rb b/activejob/lib/active_job/queue_adapters/que_adapter.rb
index e501fe0368..84cc2845b0 100644
--- a/activejob/lib/active_job/queue_adapters/que_adapter.rb
+++ b/activejob/lib/active_job/queue_adapters/que_adapter.rb
@@ -15,14 +15,12 @@ module ActiveJob
#
# Rails.application.config.active_job.queue_adapter = :que
class QueAdapter
- class << self
- def enqueue(job) #:nodoc:
- JobWrapper.enqueue job.serialize, queue: job.queue_name
- end
+ def enqueue(job) #:nodoc:
+ JobWrapper.enqueue job.serialize, queue: job.queue_name
+ end
- def enqueue_at(job, timestamp) #:nodoc:
- JobWrapper.enqueue job.serialize, queue: job.queue_name, run_at: Time.at(timestamp)
- end
+ def enqueue_at(job, timestamp) #:nodoc:
+ JobWrapper.enqueue job.serialize, queue: job.queue_name, run_at: Time.at(timestamp)
end
class JobWrapper < Que::Job #:nodoc:
diff --git a/activejob/lib/active_job/queue_adapters/queue_classic_adapter.rb b/activejob/lib/active_job/queue_adapters/queue_classic_adapter.rb
index 34c11a68b2..059754a87f 100644
--- a/activejob/lib/active_job/queue_adapters/queue_classic_adapter.rb
+++ b/activejob/lib/active_job/queue_adapters/queue_classic_adapter.rb
@@ -17,29 +17,27 @@ module ActiveJob
#
# Rails.application.config.active_job.queue_adapter = :queue_classic
class QueueClassicAdapter
- class << self
- def enqueue(job) #:nodoc:
- build_queue(job.queue_name).enqueue("#{JobWrapper.name}.perform", job.serialize)
- end
+ def enqueue(job) #:nodoc:
+ build_queue(job.queue_name).enqueue("#{JobWrapper.name}.perform", job.serialize)
+ end
- def enqueue_at(job, timestamp) #:nodoc:
- queue = build_queue(job.queue_name)
- unless queue.respond_to?(:enqueue_at)
- raise NotImplementedError, 'To be able to schedule jobs with queue_classic ' \
- 'the QC::Queue needs to respond to `enqueue_at(timestamp, method, *args)`. ' \
- 'You can implement this yourself or you can use the queue_classic-later gem.'
- end
- queue.enqueue_at(timestamp, "#{JobWrapper.name}.perform", job.serialize)
+ def enqueue_at(job, timestamp) #:nodoc:
+ queue = build_queue(job.queue_name)
+ unless queue.respond_to?(:enqueue_at)
+ raise NotImplementedError, 'To be able to schedule jobs with queue_classic ' \
+ 'the QC::Queue needs to respond to `enqueue_at(timestamp, method, *args)`. ' \
+ 'You can implement this yourself or you can use the queue_classic-later gem.'
end
+ queue.enqueue_at(timestamp, "#{JobWrapper.name}.perform", job.serialize)
+ end
- # Builds a <tt>QC::Queue</tt> object to schedule jobs on.
- #
- # If you have a custom <tt>QC::Queue</tt> subclass you'll need to subclass
- # <tt>ActiveJob::QueueAdapters::QueueClassicAdapter</tt> and override the
- # <tt>build_queue</tt> method.
- def build_queue(queue_name)
- QC::Queue.new(queue_name)
- end
+ # Builds a <tt>QC::Queue</tt> object to schedule jobs on.
+ #
+ # If you have a custom <tt>QC::Queue</tt> subclass you'll need to subclass
+ # <tt>ActiveJob::QueueAdapters::QueueClassicAdapter</tt> and override the
+ # <tt>build_queue</tt> method.
+ def build_queue(queue_name)
+ QC::Queue.new(queue_name)
end
class JobWrapper #:nodoc:
diff --git a/activejob/lib/active_job/queue_adapters/resque_adapter.rb b/activejob/lib/active_job/queue_adapters/resque_adapter.rb
index 88c6b48fef..417854afd8 100644
--- a/activejob/lib/active_job/queue_adapters/resque_adapter.rb
+++ b/activejob/lib/active_job/queue_adapters/resque_adapter.rb
@@ -26,18 +26,16 @@ module ActiveJob
#
# Rails.application.config.active_job.queue_adapter = :resque
class ResqueAdapter
- class << self
- def enqueue(job) #:nodoc:
- Resque.enqueue_to job.queue_name, JobWrapper, job.serialize
- end
+ def enqueue(job) #:nodoc:
+ Resque.enqueue_to job.queue_name, JobWrapper, job.serialize
+ end
- def enqueue_at(job, timestamp) #:nodoc:
- unless Resque.respond_to?(:enqueue_at_with_queue)
- raise NotImplementedError, "To be able to schedule jobs with Resque you need the " \
- "resque-scheduler gem. Please add it to your Gemfile and run bundle install"
- end
- Resque.enqueue_at_with_queue job.queue_name, timestamp, JobWrapper, job.serialize
+ def enqueue_at(job, timestamp) #:nodoc:
+ unless Resque.respond_to?(:enqueue_at_with_queue)
+ raise NotImplementedError, "To be able to schedule jobs with Resque you need the " \
+ "resque-scheduler gem. Please add it to your Gemfile and run bundle install"
end
+ Resque.enqueue_at_with_queue job.queue_name, timestamp, JobWrapper, job.serialize
end
class JobWrapper #:nodoc:
diff --git a/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb b/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb
index 21005fc728..743d5ea333 100644
--- a/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb
+++ b/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb
@@ -15,22 +15,22 @@ module ActiveJob
#
# Rails.application.config.active_job.queue_adapter = :sidekiq
class SidekiqAdapter
- class << self
- def enqueue(job) #:nodoc:
- #Sidekiq::Client does not support symbols as keys
- Sidekiq::Client.push \
- 'class' => JobWrapper,
- 'queue' => job.queue_name,
- 'args' => [ job.serialize ]
- end
+ def enqueue(job) #:nodoc:
+ #Sidekiq::Client does not support symbols as keys
+ Sidekiq::Client.push \
+ 'class' => JobWrapper,
+ 'wrapped' => job.class.to_s,
+ 'queue' => job.queue_name,
+ 'args' => [ job.serialize ]
+ end
- def enqueue_at(job, timestamp) #:nodoc:
- Sidekiq::Client.push \
- 'class' => JobWrapper,
- 'queue' => job.queue_name,
- 'args' => [ job.serialize ],
- 'at' => timestamp
- end
+ def enqueue_at(job, timestamp) #:nodoc:
+ Sidekiq::Client.push \
+ 'class' => JobWrapper,
+ 'wrapped' => job.class.to_s,
+ 'queue' => job.queue_name,
+ 'args' => [ job.serialize ],
+ 'at' => timestamp
end
class JobWrapper #:nodoc:
diff --git a/activejob/lib/active_job/queue_adapters/sneakers_adapter.rb b/activejob/lib/active_job/queue_adapters/sneakers_adapter.rb
index 6d60a2f303..f5737487ca 100644
--- a/activejob/lib/active_job/queue_adapters/sneakers_adapter.rb
+++ b/activejob/lib/active_job/queue_adapters/sneakers_adapter.rb
@@ -16,19 +16,19 @@ module ActiveJob
#
# Rails.application.config.active_job.queue_adapter = :sneakers
class SneakersAdapter
- @monitor = Monitor.new
+ def initialize
+ @monitor = Monitor.new
+ end
- class << self
- def enqueue(job) #:nodoc:
- @monitor.synchronize do
- JobWrapper.from_queue job.queue_name
- JobWrapper.enqueue ActiveSupport::JSON.encode(job.serialize)
- end
+ def enqueue(job) #:nodoc:
+ @monitor.synchronize do
+ JobWrapper.from_queue job.queue_name
+ JobWrapper.enqueue ActiveSupport::JSON.encode(job.serialize)
end
+ end
- def enqueue_at(job, timestamp) #:nodoc:
- raise NotImplementedError
- end
+ def enqueue_at(job, timestamp) #:nodoc:
+ raise NotImplementedError
end
class JobWrapper #:nodoc:
diff --git a/activejob/lib/active_job/queue_adapters/sucker_punch_adapter.rb b/activejob/lib/active_job/queue_adapters/sucker_punch_adapter.rb
index be9e7fd03a..64c93e8198 100644
--- a/activejob/lib/active_job/queue_adapters/sucker_punch_adapter.rb
+++ b/activejob/lib/active_job/queue_adapters/sucker_punch_adapter.rb
@@ -18,14 +18,12 @@ module ActiveJob
#
# Rails.application.config.active_job.queue_adapter = :sucker_punch
class SuckerPunchAdapter
- class << self
- def enqueue(job) #:nodoc:
- JobWrapper.new.async.perform job.serialize
- end
+ def enqueue(job) #:nodoc:
+ JobWrapper.new.async.perform job.serialize
+ end
- def enqueue_at(job, timestamp) #:nodoc:
- raise NotImplementedError
- end
+ def enqueue_at(job, timestamp) #:nodoc:
+ raise NotImplementedError
end
class JobWrapper #:nodoc:
diff --git a/activejob/lib/active_job/queue_adapters/test_adapter.rb b/activejob/lib/active_job/queue_adapters/test_adapter.rb
index fd7c0b207a..9b7b7139f4 100644
--- a/activejob/lib/active_job/queue_adapters/test_adapter.rb
+++ b/activejob/lib/active_job/queue_adapters/test_adapter.rb
@@ -10,52 +10,50 @@ module ActiveJob
#
# Rails.application.config.active_job.queue_adapter = :test
class TestAdapter
- class << self
- attr_accessor(:perform_enqueued_jobs, :perform_enqueued_at_jobs, :filter)
- attr_writer(:enqueued_jobs, :performed_jobs)
+ attr_accessor(:perform_enqueued_jobs, :perform_enqueued_at_jobs, :filter)
+ attr_writer(:enqueued_jobs, :performed_jobs)
- # Provides a store of all the enqueued jobs with the TestAdapter so you can check them.
- def enqueued_jobs
- @enqueued_jobs ||= []
- end
+ # Provides a store of all the enqueued jobs with the TestAdapter so you can check them.
+ def enqueued_jobs
+ @enqueued_jobs ||= []
+ end
- # Provides a store of all the performed jobs with the TestAdapter so you can check them.
- def performed_jobs
- @performed_jobs ||= []
- end
+ # Provides a store of all the performed jobs with the TestAdapter so you can check them.
+ def performed_jobs
+ @performed_jobs ||= []
+ end
- def enqueue(job) #:nodoc:
- return if filtered?(job)
+ def enqueue(job) #:nodoc:
+ return if filtered?(job)
- job_data = job_to_hash(job)
- enqueue_or_perform(perform_enqueued_jobs, job, job_data)
- end
+ job_data = job_to_hash(job)
+ enqueue_or_perform(perform_enqueued_jobs, job, job_data)
+ end
- def enqueue_at(job, timestamp) #:nodoc:
- return if filtered?(job)
+ def enqueue_at(job, timestamp) #:nodoc:
+ return if filtered?(job)
- job_data = job_to_hash(job, at: timestamp)
- enqueue_or_perform(perform_enqueued_at_jobs, job, job_data)
- end
+ job_data = job_to_hash(job, at: timestamp)
+ enqueue_or_perform(perform_enqueued_at_jobs, job, job_data)
+ end
- private
+ private
- def job_to_hash(job, extras = {})
- { job: job.class, args: job.serialize.fetch('arguments'), queue: job.queue_name }.merge!(extras)
- end
+ def job_to_hash(job, extras = {})
+ { job: job.class, args: job.serialize.fetch('arguments'), queue: job.queue_name }.merge!(extras)
+ end
- def enqueue_or_perform(perform, job, job_data)
- if perform
- performed_jobs << job_data
- Base.execute job.serialize
- else
- enqueued_jobs << job_data
- end
+ def enqueue_or_perform(perform, job, job_data)
+ if perform
+ performed_jobs << job_data
+ Base.execute job.serialize
+ else
+ enqueued_jobs << job_data
end
+ end
- def filtered?(job)
- filter && !Array(filter).include?(job.class)
- end
+ def filtered?(job)
+ filter && !Array(filter).include?(job.class)
end
end
end
diff --git a/activejob/lib/active_job/test_helper.rb b/activejob/lib/active_job/test_helper.rb
index 66508114d1..4efb4b72d2 100644
--- a/activejob/lib/active_job/test_helper.rb
+++ b/activejob/lib/active_job/test_helper.rb
@@ -1,3 +1,4 @@
+require 'active_support/core_ext/class/subclasses'
require 'active_support/core_ext/hash/keys'
module ActiveJob
@@ -7,18 +8,27 @@ module ActiveJob
included do
def before_setup
- @old_queue_adapter = queue_adapter
- ActiveJob::Base.queue_adapter = :test
+ test_adapter = ActiveJob::QueueAdapters::TestAdapter.new
+
+ @old_queue_adapters = (ActiveJob::Base.subclasses << ActiveJob::Base).select do |klass|
+ # only override explicitly set adapters, a quirk of `class_attribute`
+ klass.singleton_class.public_instance_methods(false).include?(:_queue_adapter)
+ end.map do |klass|
+ [klass, klass.queue_adapter].tap do
+ klass.queue_adapter = test_adapter
+ end
+ end
+
clear_enqueued_jobs
clear_performed_jobs
- queue_adapter.perform_enqueued_jobs = false
- queue_adapter.perform_enqueued_at_jobs = false
super
end
def after_teardown
super
- ActiveJob::Base.queue_adapter = @old_queue_adapter
+ @old_queue_adapters.each do |(klass, adapter)|
+ klass.queue_adapter = adapter
+ end
end
# Asserts that the number of enqueued jobs matches the given number.
@@ -253,15 +263,20 @@ module ActiveJob
end
def perform_enqueued_jobs(only: nil)
- @old_perform_enqueued_jobs = queue_adapter.perform_enqueued_jobs
- @old_perform_enqueued_at_jobs = queue_adapter.perform_enqueued_at_jobs
- queue_adapter.perform_enqueued_jobs = true
- queue_adapter.perform_enqueued_at_jobs = true
- queue_adapter.filter = only
- yield
- ensure
- queue_adapter.perform_enqueued_jobs = @old_perform_enqueued_jobs
- queue_adapter.perform_enqueued_at_jobs = @old_perform_enqueued_at_jobs
+ old_perform_enqueued_jobs = queue_adapter.perform_enqueued_jobs
+ old_perform_enqueued_at_jobs = queue_adapter.perform_enqueued_at_jobs
+ old_filter = queue_adapter.filter
+
+ begin
+ queue_adapter.perform_enqueued_jobs = true
+ queue_adapter.perform_enqueued_at_jobs = true
+ queue_adapter.filter = only
+ yield
+ ensure
+ queue_adapter.perform_enqueued_jobs = old_perform_enqueued_jobs
+ queue_adapter.perform_enqueued_at_jobs = old_perform_enqueued_at_jobs
+ queue_adapter.filter = old_filter
+ end
end
def queue_adapter
diff --git a/activejob/lib/rails/generators/job/job_generator.rb b/activejob/lib/rails/generators/job/job_generator.rb
index 979ffcb748..86e4c5266c 100644
--- a/activejob/lib/rails/generators/job/job_generator.rb
+++ b/activejob/lib/rails/generators/job/job_generator.rb
@@ -18,7 +18,6 @@ module Rails
def create_job_file
template 'job.rb', File.join('app/jobs', class_path, "#{file_name}_job.rb")
end
-
end
end
end
diff --git a/activejob/lib/rails/generators/job/templates/job.rb b/activejob/lib/rails/generators/job/templates/job.rb
index 462c71d917..4ad2914a45 100644
--- a/activejob/lib/rails/generators/job/templates/job.rb
+++ b/activejob/lib/rails/generators/job/templates/job.rb
@@ -1,5 +1,5 @@
<% module_namespacing do -%>
-class <%= class_name %>Job < ActiveJob::Base
+class <%= class_name %>Job < ApplicationJob
queue_as :<%= options[:queue] %>
def perform(*args)
diff --git a/activejob/test/cases/adapter_test.rb b/activejob/test/cases/adapter_test.rb
index f0c710f9ed..6d75ae9a7c 100644
--- a/activejob/test/cases/adapter_test.rb
+++ b/activejob/test/cases/adapter_test.rb
@@ -2,6 +2,6 @@ require 'helper'
class AdapterTest < ActiveSupport::TestCase
test "should load #{ENV['AJ_ADAPTER']} adapter" do
- assert_equal "active_job/queue_adapters/#{ENV['AJ_ADAPTER']}_adapter".classify, ActiveJob::Base.queue_adapter.name
+ assert_equal "active_job/queue_adapters/#{ENV['AJ_ADAPTER']}_adapter".classify, ActiveJob::Base.queue_adapter.class.name
end
end
diff --git a/activejob/test/cases/logging_test.rb b/activejob/test/cases/logging_test.rb
index 64aae00441..b18be553ec 100644
--- a/activejob/test/cases/logging_test.rb
+++ b/activejob/test/cases/logging_test.rb
@@ -6,7 +6,7 @@ require 'jobs/logging_job'
require 'jobs/nested_job'
require 'models/person'
-class AdapterTest < ActiveSupport::TestCase
+class LoggingTest < ActiveSupport::TestCase
include ActiveSupport::LogSubscriber::TestHelper
include ActiveSupport::Logger::Severity
diff --git a/activejob/test/cases/queue_adapter_test.rb b/activejob/test/cases/queue_adapter_test.rb
new file mode 100644
index 0000000000..fb3fdc392f
--- /dev/null
+++ b/activejob/test/cases/queue_adapter_test.rb
@@ -0,0 +1,56 @@
+require 'helper'
+
+module ActiveJob
+ module QueueAdapters
+ class StubOneAdapter
+ def enqueue(*); end
+ def enqueue_at(*); end
+ end
+
+ class StubTwoAdapter
+ def enqueue(*); end
+ def enqueue_at(*); end
+ end
+ end
+end
+
+class QueueAdapterTest < ActiveJob::TestCase
+ test 'should forbid nonsense arguments' do
+ assert_raises(ArgumentError) { ActiveJob::Base.queue_adapter = Mutex }
+ assert_raises(ArgumentError) { ActiveJob::Base.queue_adapter = Mutex.new }
+ end
+
+ test 'should warn on passing an adapter class' do
+ klass = Class.new do
+ def self.name
+ 'fake'
+ end
+
+ def enqueue(*); end
+ def enqueue_at(*); end
+ end
+
+ assert_deprecated { ActiveJob::Base.queue_adapter = klass }
+ end
+
+ test 'should allow overriding the queue_adapter at the child class level without affecting the parent or its sibling' do
+ base_queue_adapter = ActiveJob::Base.queue_adapter
+
+ child_job_one = Class.new(ActiveJob::Base)
+ child_job_one.queue_adapter = :stub_one
+
+ assert_not_equal ActiveJob::Base.queue_adapter, child_job_one.queue_adapter
+ assert_kind_of ActiveJob::QueueAdapters::StubOneAdapter, child_job_one.queue_adapter
+
+ child_job_two = Class.new(ActiveJob::Base)
+ child_job_two.queue_adapter = :stub_two
+
+ assert_kind_of ActiveJob::QueueAdapters::StubTwoAdapter, child_job_two.queue_adapter
+ assert_kind_of ActiveJob::QueueAdapters::StubOneAdapter, child_job_one.queue_adapter, "child_job_one's queue adapter should remain unchanged"
+ assert_equal base_queue_adapter, ActiveJob::Base.queue_adapter, "ActiveJob::Base's queue adapter should remain unchanged"
+
+ child_job_three = Class.new(ActiveJob::Base)
+
+ assert_not_nil child_job_three.queue_adapter
+ end
+end
diff --git a/activejob/test/cases/test_case_test.rb b/activejob/test/cases/test_case_test.rb
index 7d1702990e..0a3a20d5a0 100644
--- a/activejob/test/cases/test_case_test.rb
+++ b/activejob/test/cases/test_case_test.rb
@@ -4,11 +4,20 @@ require 'jobs/logging_job'
require 'jobs/nested_job'
class ActiveJobTestCaseTest < ActiveJob::TestCase
+ # this tests that this job class doesn't get its adapter set.
+ # that's the correct behaviour since we don't want to break
+ # the `class_attribute` inheritence
+ class TestClassAttributeInheritenceJob < ActiveJob::Base
+ def self.queue_adapter=(*)
+ raise 'Attemping to break `class_attribute` inheritence, bad!'
+ end
+ end
+
def test_include_helper
assert_includes self.class.ancestors, ActiveJob::TestHelper
end
def test_set_test_adapter
- assert_equal ActiveJob::QueueAdapters::TestAdapter, self.queue_adapter
+ assert_kind_of ActiveJob::QueueAdapters::TestAdapter, self.queue_adapter
end
end
diff --git a/activejob/test/cases/test_helper_test.rb b/activejob/test/cases/test_helper_test.rb
index 58de2f2588..19a2820a6e 100644
--- a/activejob/test/cases/test_helper_test.rb
+++ b/activejob/test/cases/test_helper_test.rb
@@ -199,6 +199,14 @@ class EnqueuedJobsTest < ActiveJob::TestCase
end
class PerformedJobsTest < ActiveJob::TestCase
+ def test_performed_enqueue_jobs_with_only_option_doesnt_leak_outside_the_block
+ assert_equal nil, queue_adapter.filter
+ perform_enqueued_jobs only: HelloJob do
+ assert_equal HelloJob, queue_adapter.filter
+ end
+ assert_equal nil, queue_adapter.filter
+ end
+
def test_assert_performed_jobs
assert_nothing_raised do
assert_performed_jobs 1 do
diff --git a/activejob/test/integration/queuing_test.rb b/activejob/test/integration/queuing_test.rb
index 38874b51a8..af19a92118 100644
--- a/activejob/test/integration/queuing_test.rb
+++ b/activejob/test/integration/queuing_test.rb
@@ -1,5 +1,6 @@
require 'helper'
require 'jobs/logging_job'
+require 'jobs/hello_job'
require 'active_support/core_ext/numeric/time'
class QueuingTest < ActiveSupport::TestCase
@@ -23,6 +24,18 @@ class QueuingTest < ActiveSupport::TestCase
end
end
+ test 'should supply a wrapped class name to Sidekiq' do
+ skip unless adapter_is?(:sidekiq)
+ require 'sidekiq/testing'
+
+ Sidekiq::Testing.fake! do
+ ::HelloJob.perform_later
+ hash = ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper.jobs.first
+ assert_equal "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper", hash['class']
+ assert_equal "HelloJob", hash['wrapped']
+ end
+ end
+
test 'should not run job enqueued in the future' do
begin
TestJob.set(wait: 10.minutes).perform_later @id
diff --git a/activejob/test/support/integration/adapters/qu.rb b/activejob/test/support/integration/adapters/qu.rb
index 3a5b66a057..256ddb3cf3 100644
--- a/activejob/test/support/integration/adapters/qu.rb
+++ b/activejob/test/support/integration/adapters/qu.rb
@@ -3,7 +3,7 @@ module QuJobsManager
require 'qu-rails'
require 'qu-redis'
ActiveJob::Base.queue_adapter = :qu
- ENV['REDISTOGO_URL'] = "tcp://127.0.0.1:6379/12"
+ ENV['REDISTOGO_URL'] = "redis://127.0.0.1:6379/12"
backend = Qu::Backend::Redis.new
backend.namespace = "active_jobs_int_test"
Qu.backend = backend
diff --git a/activejob/test/support/integration/adapters/queue_classic.rb b/activejob/test/support/integration/adapters/queue_classic.rb
index 038473ccdc..f522b2711f 100644
--- a/activejob/test/support/integration/adapters/queue_classic.rb
+++ b/activejob/test/support/integration/adapters/queue_classic.rb
@@ -1,6 +1,7 @@
module QueueClassicJobsManager
def setup
ENV['QC_DATABASE_URL'] ||= 'postgres:///active_jobs_qc_int_test'
+ ENV['QC_RAILS_DATABASE'] = 'false'
ENV['QC_LISTEN_TIME'] = "0.5"
uri = URI.parse(ENV['QC_DATABASE_URL'])
user = uri.user||ENV['USER']
@@ -20,7 +21,8 @@ module QueueClassicJobsManager
end
def start_workers
- QC::Conn.disconnect
+ QC.default_conn_adapter.disconnect
+ QC.default_conn_adapter = nil
@pid = fork do
worker = QC::Worker.new(q_name: 'integration_tests')
worker.start
diff --git a/activejob/test/support/integration/test_case_helpers.rb b/activejob/test/support/integration/test_case_helpers.rb
index ee2f6aebea..bed28b2900 100644
--- a/activejob/test/support/integration/test_case_helpers.rb
+++ b/activejob/test/support/integration/test_case_helpers.rb
@@ -5,7 +5,7 @@ module TestCaseHelpers
extend ActiveSupport::Concern
included do
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
setup do
clear_jobs
@@ -27,8 +27,8 @@ module TestCaseHelpers
jobs_manager.clear_jobs
end
- def adapter_is?(adapter)
- ActiveJob::Base.queue_adapter.name.split("::").last.gsub(/Adapter$/, '').underscore==adapter.to_s
+ def adapter_is?(adapter_class_symbol)
+ ActiveJob::Base.queue_adapter.class.name.split("::").last.gsub(/Adapter$/, '').underscore == adapter_class_symbol.to_s
end
def wait_for_jobs_to_finish_for(seconds=60)
diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md
index 80b42859e2..ae0016d3d5 100644
--- a/activemodel/CHANGELOG.md
+++ b/activemodel/CHANGELOG.md
@@ -1,3 +1,8 @@
+* Deprecate the `:tokenizer` option for `validates_length_of`, in favor of
+ plain Ruby.
+
+ *Sean Griffin*
+
* Deprecate `ActiveModel::Errors#add_on_empty` and `ActiveModel::Errors#add_on_blank`
with no replacement.
diff --git a/activemodel/Rakefile b/activemodel/Rakefile
index c30a559ef5..7256285a41 100644
--- a/activemodel/Rakefile
+++ b/activemodel/Rakefile
@@ -6,7 +6,7 @@ task :default => :test
Rake::TestTask.new do |t|
t.libs << "test"
- t.test_files = Dir.glob("#{dir}/test/cases/**/*_test.rb").sort
+ t.test_files = Dir.glob("#{dir}/test/cases/**/*_test.rb")
t.warning = true
t.verbose = true
t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION)
diff --git a/activemodel/activemodel.gemspec b/activemodel/activemodel.gemspec
index 3c6eb56296..1a16f2a1ed 100644
--- a/activemodel/activemodel.gemspec
+++ b/activemodel/activemodel.gemspec
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
s.summary = 'A toolkit for building modeling frameworks (part of Rails).'
s.description = 'A toolkit for building modeling frameworks like Active Record. Rich support for attributes, callbacks, validations, serialization, internationalization, and testing.'
- s.required_ruby_version = '>= 2.2.0'
+ s.required_ruby_version = '>= 2.2.1'
s.license = 'MIT'
diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index f324788979..f843b279ce 100644
--- a/activemodel/lib/active_model/errors.rb
+++ b/activemodel/lib/active_model/errors.rb
@@ -3,6 +3,7 @@
require 'active_support/core_ext/array/conversions'
require 'active_support/core_ext/string/inflections'
require 'active_support/core_ext/object/deep_dup'
+require 'active_support/core_ext/string/filters'
module ActiveModel
# == Active \Model \Errors
@@ -33,11 +34,11 @@ module ActiveModel
# send(attr)
# end
#
- # def Person.human_attribute_name(attr, options = {})
+ # def self.human_attribute_name(attr, options = {})
# attr
# end
#
- # def Person.lookup_ancestors
+ # def self.lookup_ancestors
# [self]
# end
# end
@@ -101,9 +102,7 @@ module ActiveModel
def include?(attribute)
messages[attribute].present?
end
- # aliases include?
alias :has_key? :include?
- # aliases include?
alias :key? :include?
# Get messages for +key+.
@@ -123,9 +122,9 @@ module ActiveModel
# Set messages for +key+ to +value+.
#
- # person.errors.get(:name) # => ["cannot be nil"]
+ # person.errors[:name] # => ["cannot be nil"]
# person.errors.set(:name, ["can't be nil"])
- # person.errors.get(:name) # => ["can't be nil"]
+ # person.errors[:name] # => ["can't be nil"]
def set(key, value)
ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
ActiveModel::Errors#set is deprecated and will be removed in Rails 5.1.
@@ -138,12 +137,12 @@ module ActiveModel
# Delete messages for +key+. Returns the deleted messages.
#
- # person.errors.get(:name) # => ["cannot be nil"]
+ # person.errors[:name] # => ["cannot be nil"]
# person.errors.delete(:name) # => ["cannot be nil"]
- # person.errors.get(:name) # => []
+ # person.errors[:name] # => []
def delete(key)
- messages.delete(key)
details.delete(key)
+ messages.delete(key)
end
# When passed a symbol or a name of a method, returns an array of errors
@@ -198,6 +197,7 @@ module ActiveModel
def size
values.flatten.size
end
+ alias :count :size
# Returns all message values.
#
@@ -215,35 +215,15 @@ module ActiveModel
messages.keys
end
- # Returns an array of error messages, with the attribute name included.
- #
- # person.errors.add(:name, :blank, message: "can't be blank")
- # person.errors.add(:name, :not_specified, message: "must be specified")
- # person.errors.to_a # => ["name can't be blank", "name must be specified"]
- def to_a
- full_messages
- end
-
- # Returns the number of error messages.
- #
- # person.errors.add(:name, :blank, message: "can't be blank")
- # person.errors.count # => 1
- # person.errors.add(:name, :not_specified, message: "must be specified")
- # person.errors.count # => 2
- def count
- to_a.size
- end
-
# Returns +true+ if no errors are found, +false+ otherwise.
# If the error message is a string it can be empty.
#
# person.errors.full_messages # => ["name cannot be nil"]
# person.errors.empty? # => false
def empty?
- all? { |k, v| v && v.empty? && !v.is_a?(String) }
+ size.zero?
end
- # aliases empty?
- alias_method :blank?, :empty?
+ alias :blank? :empty?
# Returns an xml formatted representation of the Errors hash.
#
@@ -406,6 +386,7 @@ module ActiveModel
def full_messages
map { |attribute, message| full_message(attribute, message) }
end
+ alias :to_a :full_messages
# Returns all the full error messages for a given attribute in an array.
#
diff --git a/activemodel/lib/active_model/secure_password.rb b/activemodel/lib/active_model/secure_password.rb
index 871031ece4..89da74efa8 100644
--- a/activemodel/lib/active_model/secure_password.rb
+++ b/activemodel/lib/active_model/secure_password.rb
@@ -26,7 +26,7 @@ module ActiveModel
# it). When this attribute has a +nil+ value, the validation will not be
# triggered.
#
- # For further customizability, it is possible to supress the default
+ # For further customizability, it is possible to suppress the default
# validations by passing <tt>validations: false</tt> as an argument.
#
# Add bcrypt (~> 3.1.7) to Gemfile to use #has_secure_password:
diff --git a/activemodel/lib/active_model/validations/length.rb b/activemodel/lib/active_model/validations/length.rb
index 23201b264a..060919fac3 100644
--- a/activemodel/lib/active_model/validations/length.rb
+++ b/activemodel/lib/active_model/validations/length.rb
@@ -1,3 +1,5 @@
+require "active_support/core_ext/string/strip"
+
module ActiveModel
# == Active \Model Length Validator
@@ -18,6 +20,27 @@ module ActiveModel
options[:minimum] = 1
end
+ if options[:tokenizer]
+ ActiveSupport::Deprecation.warn(<<-EOS.strip_heredoc)
+ The `:tokenizer` option is deprecated, and will be removed in Rails 5.1.
+ You can achieve the same functionality be defining an instance method
+ with the value that you want to validate the length of. For example,
+
+ validates_length_of :essay, minimum: 100,
+ tokenizer: ->(str) { str.scan(/\w+/) }
+
+ should be written as
+
+ validates_length_of :words_in_essay, minimum: 100
+
+ private
+
+ def words_in_essay
+ essay.scan(/\w+/)
+ end
+ EOS
+ end
+
super
end
@@ -88,8 +111,13 @@ module ActiveModel
# validates_length_of :user_name, within: 6..20, too_long: 'pick a shorter name', too_short: 'pick a longer name'
# validates_length_of :zip_code, minimum: 5, too_short: 'please enter at least 5 characters'
# validates_length_of :smurf_leader, is: 4, message: "papa is spelled with 4 characters... don't play me."
- # validates_length_of :essay, minimum: 100, too_short: 'Your essay must be at least 100 words.',
- # tokenizer: ->(str) { str.scan(/\w+/) }
+ # validates_length_of :words_in_essay, minimum: 100, too_short: 'Your essay must be at least 100 words.'
+ #
+ # private
+ #
+ # def words_in_essay
+ # essay.scan(/\w+/)
+ # end
# end
#
# Configuration options:
@@ -112,12 +140,6 @@ module ActiveModel
# * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>,
# <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate
# <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message.
- # * <tt>:tokenizer</tt> - A method (as a symbol), proc or string to
- # specify how to split up the attribute string. (e.g.
- # <tt>tokenizer: :word_tokenizer</tt> to call the +word_tokenizer+ method
- # or <tt>tokenizer: ->(str) { str.scan(/\w+/) }</tt> to count words as in
- # above example). Defaults to <tt>->(value) { value.split(//) }</tt> which
- # counts individual characters.
#
# There is also a list of default options supported by every validator:
# +:if+, +:unless+, +:on+ and +:strict+.
diff --git a/activemodel/test/cases/errors_test.rb b/activemodel/test/cases/errors_test.rb
index da142ea2c0..f781a0017f 100644
--- a/activemodel/test/cases/errors_test.rb
+++ b/activemodel/test/cases/errors_test.rb
@@ -212,6 +212,12 @@ class ErrorsTest < ActiveModel::TestCase
assert_equal 1, person.errors.size
end
+ test "count calculates the number of error messages" do
+ person = Person.new
+ person.errors.add(:name, "cannot be blank")
+ assert_equal 1, person.errors.count
+ end
+
test "to_a returns the list of errors with complete messages containing the attribute names" do
person = Person.new
person.errors.add(:name, "cannot be blank")
@@ -377,6 +383,12 @@ class ErrorsTest < ActiveModel::TestCase
assert_empty errors.details[:name]
end
+ test "delete returns the deleted messages" do
+ errors = ActiveModel::Errors.new(Person.new)
+ errors.add(:name, :invalid)
+ assert_equal ["is invalid"], errors.delete(:name)
+ end
+
test "clear removes details" do
person = Person.new
person.errors.add(:name, :invalid)
diff --git a/activemodel/test/cases/helper.rb b/activemodel/test/cases/helper.rb
index 3276f69f09..2b9de5e5d2 100644
--- a/activemodel/test/cases/helper.rb
+++ b/activemodel/test/cases/helper.rb
@@ -22,8 +22,3 @@ end
def jruby_skip(message = '')
skip message if defined?(JRUBY_VERSION)
end
-
-# FIXME: we have tests that depend on run order, we should fix that and
-# remove this method call.
-require 'active_support/test_case'
-ActiveSupport::TestCase.test_order = :sorted
diff --git a/activemodel/test/cases/validations/length_validation_test.rb b/activemodel/test/cases/validations/length_validation_test.rb
index 209903898e..ee901b75fb 100644
--- a/activemodel/test/cases/validations/length_validation_test.rb
+++ b/activemodel/test/cases/validations/length_validation_test.rb
@@ -319,8 +319,14 @@ class LengthValidationTest < ActiveModel::TestCase
end
def test_validates_length_of_with_block
- Topic.validates_length_of :content, minimum: 5, too_short: "Your essay must be at least %{count} words.",
- tokenizer: lambda {|str| str.scan(/\w+/) }
+ assert_deprecated do
+ Topic.validates_length_of(
+ :content,
+ minimum: 5,
+ too_short: "Your essay must be at least %{count} words.",
+ tokenizer: lambda {|str| str.scan(/\w+/) },
+ )
+ end
t = Topic.new(content: "this content should be long enough")
assert t.valid?
@@ -332,8 +338,14 @@ class LengthValidationTest < ActiveModel::TestCase
def test_validates_length_of_with_symbol
- Topic.validates_length_of :content, minimum: 5, too_short: "Your essay must be at least %{count} words.",
- tokenizer: :my_word_tokenizer
+ assert_deprecated do
+ Topic.validates_length_of(
+ :content,
+ minimum: 5,
+ too_short: "Your essay must be at least %{count} words.",
+ tokenizer: :my_word_tokenizer,
+ )
+ end
t = Topic.new(content: "this content should be long enough")
assert t.valid?
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index b5dd19988d..8793d6de70 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,5 +1,75 @@
-* Dont enroll records in the transaction if they dont have commit callbacks.
- That was causing a memory grow problem when creating a lot of records inside a transaction.
+* Reduce memory usage from loading types on pg.
+
+ Fixes #19578.
+
+ *Sean Griffin*
+
+* Add `config.active_record.warn_on_records_fetched_greater_than` option
+
+ When set to an integer, a warning will be logged whenever a result set
+ larger than the specified size is returned by a query. Fixes #16463
+
+ *Jason Nochlin*
+
+* Ignore psqlrc when loading database structure.
+
+ *Jason Weathered*
+
+* Fix referencing wrong table aliases while joining tables of has many through
+ association (only when calling calculation methods).
+
+ Fixes #19276.
+
+ *pinglamb*
+
+* Correctly persist a serialized attribute that has been returned to
+ its default value by an in-place modification.
+
+ Fixes #19467.
+
+ *Matthew Draper*
+
+* Fix generating the schema file when using PostgreSQL `BigInt[]` data type.
+ Previously the `limit: 8` was not coming through, and this caused it to
+ become `Int[]` data type after rebuilding from the schema.
+
+ Fixes #19420.
+
+ *Jake Waller*
+
+* Reuse the `CollectionAssociation#reader` cache when the foreign key is
+ available prior to save.
+
+ *Ben Woosley*
+
+* Add `config.active_record.dump_schemas` to fix `db:structure:dump`
+ when using schema_search_path and PostgreSQL extensions.
+
+ Fixes #17157.
+
+ *Ryan Wallace*
+
+* Renaming `use_transactional_fixtures` to `use_transactional_tests` for clarity.
+
+ Fixes #18864.
+
+ *Brandon Weiss*
+
+* Increase pg gem version requirement to `~> 0.18`. Earlier versions of the
+ pg gem are known to have problems with Ruby 2.2.
+
+ *Matt Brictson*
+
+* Correctly dump `serial` and `bigserial`.
+
+ *Ryuta Kamizono*
+
+* Fix default `format` value in `ActiveRecord::Tasks::DatabaseTasks#schema_file`.
+
+ *James Cox*
+
+* Don't enroll records in the transaction if they don't have commit callbacks.
+ This was causing a memory leak when creating many records inside a transaction.
Fixes #15549.
@@ -12,11 +82,11 @@
*Sean Griffin*
-* Add `SchemaMigration.create_table` support any unicode charsets for MySQL.
+* Add `SchemaMigration.create_table` support for any unicode charsets with MySQL.
*Ryuta Kamizono*
-* PostgreSQL, no longer disables user triggers if system triggers can't be
+* PostgreSQL no longer disables user triggers if system triggers can't be
disabled. Disabling user triggers does not fulfill what the method promises.
Rails currently requires superuser privileges for this method.
@@ -30,12 +100,12 @@
*Toby Ovod-Everett*, *Yves Senn*
-* PostgreSQL, print warning message if `disable_referential_integrity` fails
- due to missing permissions.
+* In PostgreSQL, print a warning message if `disable_referential_integrity`
+ fails due to missing permissions.
*Andrey Nering*, *Yves Senn*
-* Allow `:limit` option for MySQL bigint primary key support.
+* Allow a `:limit` option for MySQL bigint primary key support.
Example:
@@ -58,7 +128,7 @@
*Josef Šimánek*
* Fixed ActiveRecord::Relation#becomes! and changed_attributes issues for type
- column.
+ columns.
Fixes #17139.
@@ -68,7 +138,7 @@
*Ryuta Kamizono*
-* Allow `:precision` option for time type columns.
+* Allow a `:precision` option for time type columns.
*Ryuta Kamizono*
@@ -85,10 +155,10 @@
recipients: commentable.recipients }
end
- That's what you want the bulk of the time. New comment creates a new
- Notification. But there may well be off cases, like copying a commentable
- and its comments, where you don't want that. So you'd have a concern
- something like this:
+ That's what you want the bulk of the time. A new comment creates a new
+ Notification. There may be edge cases where you don't want that, like
+ when copying a commentable and its comments, in which case write a
+ concern with something like this:
module Copyable
def copy_to(destination)
@@ -107,7 +177,7 @@
*Hyonjee Joo*
-* Deprecated passing of `start` value to `find_in_batches` and `find_each`
+* Deprecate passing of `start` value to `find_in_batches` and `find_each`
in favour of `begin_at` value.
*Vipul A M*
@@ -116,9 +186,10 @@
*Tõnis Simo*
-* Use SQL COUNT and LIMIT 1 queries for `none?` and `one?` methods if no block or limit is given,
- instead of loading the entire collection to memory.
- This applies to relations (e.g. `User.all`) as well as associations (e.g. `account.users`)
+* Use SQL COUNT and LIMIT 1 queries for `none?` and `one?` methods
+ if no block or limit is given, instead of loading the entire
+ collection into memory. This applies to relations (e.g. `User.all`)
+ as well as associations (e.g. `account.users`)
# Before:
@@ -167,16 +238,16 @@
*Vipul A M*
-* Fix rounding problem for PostgreSQL timestamp column.
+* Fix a rounding problem for PostgreSQL timestamp columns.
- If timestamp column have the precision, it need to format according to
- the precision of timestamp column.
+ If a timestamp column has a precision specified, it needs to
+ format according to that.
*Ryuta Kamizono*
* Respect the database default charset for `schema_migrations` table.
- The charset of `version` column in `schema_migrations` table is depend
+ The charset of `version` column in `schema_migrations` table depends
on the database default charset and collation rather than the encoding
of the connection.
@@ -184,12 +255,12 @@
* Raise `ArgumentError` when passing `nil` or `false` to `Relation#merge`.
- These are not valid values to merge in a relation so it should warn the users
+ These are not valid values to merge in a relation, so it should warn users
early.
*Rafael Mendonça França*
-* Use `SCHEMA` instead of `DB_STRUCTURE` for specifying structure file.
+* Use `SCHEMA` instead of `DB_STRUCTURE` for specifying a structure file.
This makes the db:structure tasks consistent with test:load_structure.
@@ -201,7 +272,7 @@
*Sean Griffin*
-* Fixed several edge cases which could result in a counter cache updating
+* Fix several edge cases which could result in a counter cache updating
twice or not updating at all for `has_many` and `has_many :through`.
Fixes #10865.
@@ -234,11 +305,13 @@
*Sammy Larbi*
* Change the default error message from `can't be blank` to `must exist` for
- the presence validator of the `:required` option on `belongs_to`/`has_one` associations.
+ the presence validator of the `:required` option on `belongs_to`/`has_one`
+ associations.
*Henrik Nygren*
-* Fixed ActiveRecord::Relation#group method when argument is SQL reserved key word:
+* Fixed ActiveRecord::Relation#group method when an argument is an SQL
+ reserved key word:
Example:
@@ -369,7 +442,7 @@
*Yves Senn*
-* Remove deprecation when modifying a relation with cached arel.
+* Remove deprecation when modifying a relation with cached Arel.
This raises an `ImmutableRelation` error instead.
*Yves Senn*
@@ -459,13 +532,13 @@
*Florian Weingarten*
-* Fixed setting of foreign_key for through associations while building of new record.
+* Fix setting of foreign_key for through associations when building a new record.
Fixes #12698.
*Ivan Antropov*
-* Improve a dump of the primary key support. If it is not a default primary key,
+* Improve dumping of the primary key. If it is not a default primary key,
correctly dump the type and options.
Fixes #14169, #16599.
@@ -483,18 +556,18 @@
*Ryuta Kamizono*
-* Allow precision option for MySQL datetimes.
+* Allow a precision option for MySQL datetimes.
*Ryuta Kamizono*
-* Fixed automatic inverse_of for models nested in module.
+* Fixed automatic `inverse_of` for models nested in a module.
*Andrew McCloud*
* Change `ActiveRecord::Relation#update` behavior so that it can
be called without passing ids of the records to be updated.
- This change allows to update multiple records returned by
+ This change allows updating multiple records returned by
`ActiveRecord::Relation` with callbacks and validations.
# Before
@@ -526,6 +599,13 @@
*Rafael Mendonça França*
+* Fix change detection problem for PostgreSQL bytea type and
+ `ArgumentError: string contains null byte` exception with pg-0.18.
+
+ Fixes #17680.
+
+ *Lars Kanis*
+
* When a table has a composite primary key, the `primary_key` method for
SQLite3 and PostgreSQL adapters was only returning the first field of the key.
Ensures that it will return nil instead, as Active Record doesn't support
@@ -535,7 +615,7 @@
*arthurnn*
-* `validates_size_of` / `validates_length_of` do not count records,
+* `validates_size_of` / `validates_length_of` do not count records
which are `marked_for_destruction?`.
Fixes #7247.
@@ -577,7 +657,7 @@
*Ryuta Kamizono*
-* Support for any type primary key.
+* Support for any type of primary key.
Fixes #14194.
@@ -603,7 +683,7 @@
*Yves Senn*
-* Fixes bug with 'ActiveRecord::Type::Numeric' that causes negative values to
+* Fix bug with 'ActiveRecord::Type::Numeric' that caused negative values to
be marked as having changed when set to the same negative value.
Closes #18161.
diff --git a/activerecord/Rakefile b/activerecord/Rakefile
index 976b559da9..f1facac21b 100644
--- a/activerecord/Rakefile
+++ b/activerecord/Rakefile
@@ -51,7 +51,7 @@ end
t.libs << 'test'
t.test_files = (Dir.glob( "test/cases/**/*_test.rb" ).reject {
|x| x =~ /\/adapters\//
- } + Dir.glob("test/cases/adapters/#{adapter_short}/**/*_test.rb")).sort
+ } + Dir.glob("test/cases/adapters/#{adapter_short}/**/*_test.rb"))
t.warning = true
t.verbose = true
diff --git a/activerecord/activerecord.gemspec b/activerecord/activerecord.gemspec
index c5cd0c89f7..c88b9e8718 100644
--- a/activerecord/activerecord.gemspec
+++ b/activerecord/activerecord.gemspec
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
s.summary = 'Object-relational mapper framework (part of Rails).'
s.description = 'Databases on Rails. Build a persistent domain model by mapping database tables to Ruby classes. Strong conventions for associations, validations, aggregations, migrations, and testing come baked-in.'
- s.required_ruby_version = '>= 2.2.0'
+ s.required_ruby_version = '>= 2.2.1'
s.license = 'MIT'
diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb
index ef14e065ae..58a4694880 100644
--- a/activerecord/lib/active_record.rb
+++ b/activerecord/lib/active_record.rb
@@ -43,6 +43,7 @@ module ActiveRecord
autoload :Explain
autoload :Inheritance
autoload :Integration
+ autoload :LegacyYamlAdapter
autoload :Migration
autoload :Migrator, 'active_record/migration'
autoload :ModelSchema
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index cecb2dbd0b..5e3e5f709b 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -113,19 +113,19 @@ module ActiveRecord
# These classes will be loaded when associations are created.
# So there is no need to eager load them.
- autoload :Association, 'active_record/associations/association'
- autoload :SingularAssociation, 'active_record/associations/singular_association'
- autoload :CollectionAssociation, 'active_record/associations/collection_association'
- autoload :ForeignAssociation, 'active_record/associations/foreign_association'
- autoload :CollectionProxy, 'active_record/associations/collection_proxy'
+ autoload :Association
+ autoload :SingularAssociation
+ autoload :CollectionAssociation
+ autoload :ForeignAssociation
+ autoload :CollectionProxy
- autoload :BelongsToAssociation, 'active_record/associations/belongs_to_association'
- autoload :BelongsToPolymorphicAssociation, 'active_record/associations/belongs_to_polymorphic_association'
- autoload :HasManyAssociation, 'active_record/associations/has_many_association'
- autoload :HasManyThroughAssociation, 'active_record/associations/has_many_through_association'
- autoload :HasOneAssociation, 'active_record/associations/has_one_association'
- autoload :HasOneThroughAssociation, 'active_record/associations/has_one_through_association'
- autoload :ThroughAssociation, 'active_record/associations/through_association'
+ autoload :BelongsToAssociation
+ autoload :BelongsToPolymorphicAssociation
+ autoload :HasManyAssociation
+ autoload :HasManyThroughAssociation
+ autoload :HasOneAssociation
+ autoload :HasOneThroughAssociation
+ autoload :ThroughAssociation
module Builder #:nodoc:
autoload :Association, 'active_record/associations/builder/association'
@@ -139,10 +139,10 @@ module ActiveRecord
end
eager_autoload do
- autoload :Preloader, 'active_record/associations/preloader'
- autoload :JoinDependency, 'active_record/associations/join_dependency'
- autoload :AssociationScope, 'active_record/associations/association_scope'
- autoload :AliasTracker, 'active_record/associations/alias_tracker'
+ autoload :Preloader
+ autoload :JoinDependency
+ autoload :AssociationScope
+ autoload :AliasTracker
end
# Returns the association instance for the given name, instantiating it if it doesn't already exist
diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb
index 0d8e4ba870..930f678ae8 100644
--- a/activerecord/lib/active_record/associations/association.rb
+++ b/activerecord/lib/active_record/associations/association.rb
@@ -8,12 +8,12 @@ module ActiveRecord
#
# Association
# SingularAssociation
- # HasOneAssociation
+ # HasOneAssociation + ForeignAssociation
# HasOneThroughAssociation + ThroughAssociation
# BelongsToAssociation
# BelongsToPolymorphicAssociation
# CollectionAssociation
- # HasManyAssociation
+ # HasManyAssociation + ForeignAssociation
# HasManyThroughAssociation + ThroughAssociation
class Association #:nodoc:
attr_reader :owner, :target, :reflection
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index 0ba03338f6..88531205a1 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -33,10 +33,10 @@ module ActiveRecord
reload
end
- if owner.new_record?
+ if null_scope?
# Cache the proxy separately before the owner has an id
# or else a post-save proxy will still lack the id
- @new_record_proxy ||= CollectionProxy.create(klass, self)
+ @null_proxy ||= CollectionProxy.create(klass, self)
else
@proxy ||= CollectionProxy.create(klass, self)
end
@@ -432,8 +432,7 @@ module ActiveRecord
def get_records
if reflection.scope_chain.any?(&:any?) ||
scope.eager_loading? ||
- klass.current_scope ||
- klass.default_scopes.any?
+ klass.scope_attributes?
return scope.to_a
end
diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb
index e11c9490b7..685c3a5f17 100644
--- a/activerecord/lib/active_record/associations/collection_proxy.rb
+++ b/activerecord/lib/active_record/associations/collection_proxy.rb
@@ -976,6 +976,9 @@ module ActiveRecord
# Equivalent to +delete_all+. The difference is that returns +self+, instead
# of an array with the deleted objects, so methods can be chained. See
# +delete_all+ for more information.
+ # Note that because +delete_all+ removes records by directly
+ # running an SQL query into the database, the +updated_at+ column of
+ # the object is not changed.
def clear
delete_all
self
diff --git a/activerecord/lib/active_record/associations/singular_association.rb b/activerecord/lib/active_record/associations/singular_association.rb
index c44242a0f0..58d0f7d65d 100644
--- a/activerecord/lib/active_record/associations/singular_association.rb
+++ b/activerecord/lib/active_record/associations/singular_association.rb
@@ -41,8 +41,7 @@ module ActiveRecord
def get_records
if reflection.scope_chain.any?(&:any?) ||
scope.eager_loading? ||
- klass.current_scope ||
- klass.default_scopes.any?
+ klass.scope_attributes?
return scope.limit(1).to_a
end
diff --git a/activerecord/lib/active_record/associations/through_association.rb b/activerecord/lib/active_record/associations/through_association.rb
index 3ce9cffdbc..af1bce523c 100644
--- a/activerecord/lib/active_record/associations/through_association.rb
+++ b/activerecord/lib/active_record/associations/through_association.rb
@@ -33,7 +33,7 @@ module ActiveRecord
# Construct attributes for :through pointing to owner and associate. This is used by the
# methods which create and delete records on the association.
#
- # We only support indirectly modifying through associations which has a belongs_to source.
+ # We only support indirectly modifying through associations which have a belongs_to source.
# This is the "has_many :tags, through: :taggings" situation, where the join model
# typically has a belongs_to on both side. In other words, associations which could also
# be represented as has_and_belongs_to_many associations.
diff --git a/activerecord/lib/active_record/attributes.rb b/activerecord/lib/active_record/attributes.rb
index c8979a60d7..50339b6f69 100644
--- a/activerecord/lib/active_record/attributes.rb
+++ b/activerecord/lib/active_record/attributes.rb
@@ -28,15 +28,18 @@ module ActiveRecord
# information about providing custom type objects.
#
# ==== Options
+ #
# The following options are accepted:
#
# +default+ The default value to use when no value is provided. If this option
# is not passed, the previous default value (if any) will be used.
# Otherwise, the default will be +nil+.
#
- # +array+ (PG only) specifies that the type should be an array (see the examples below).
+ # +array+ (PG only) specifies that the type should be an array (see the
+ # examples below).
#
- # +range+ (PG only) specifies that the type should be a range (see the examples below).
+ # +range+ (PG only) specifies that the type should be a range (see the
+ # examples below).
#
# ==== Examples
#
@@ -101,12 +104,11 @@ module ActiveRecord
# ==== Creating Custom Types
#
# Users may also define their own custom types, as long as they respond
- # to the methods defined on the value type. The method
- # +deserialize+ or +cast+ will be called on
- # your type object, with raw input from the database or from your
- # controllers. See ActiveRecord::Type::Value for the expected API. It is
- # recommended that your type objects inherit from an existing type, or
- # from ActiveRecord::Type::Value
+ # to the methods defined on the value type. The method +deserialize+ or
+ # +cast+ will be called on your type object, with raw input from the
+ # database or from your controllers. See ActiveRecord::Type::Value for the
+ # expected API. It is recommended that your type objects inherit from an
+ # existing type, or from ActiveRecord::Type::Value
#
# class MoneyType < ActiveRecord::Type::Integer
# def cast(value)
@@ -150,7 +152,7 @@ module ActiveRecord
# end
#
# # value will be the result of +deserialize+ or
- # # +cast+. Assumed to be in instance of +Money+ in
+ # # +cast+. Assumed to be an instance of +Money+ in
# # this case.
# def serialize(value)
# value_in_bitcoins = @currency_converter.convert_to_bitcoins(value)
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index cc03e37a12..93550a69f1 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -258,7 +258,7 @@ module ActiveRecord #:nodoc:
# <tt>attributes=</tt> method. The +errors+ property of this exception contains an array of
# AttributeAssignmentError
# objects that should be inspected to determine which attributes triggered the errors.
- # * RecordInvalid - raised by save! and create! when the record is invalid.
+ # * RecordInvalid - raised by <tt>save!</tt> and <tt>create!</tt> when the record is invalid.
# * RecordNotFound - No record responded to the +find+ method. Either the row with the given ID doesn't exist
# or the row didn't meet the additional restrictions. Some +find+ calls do not raise this exception to signal
# nothing was found, please check its documentation for further details.
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
index 42ad285340..42c794c828 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -136,7 +136,7 @@ module ActiveRecord
#
# In order to get around this problem, #transaction will emulate the effect
# of nested transactions, by using savepoints:
- # http://dev.mysql.com/doc/refman/5.0/en/savepoint.html
+ # http://dev.mysql.com/doc/refman/5.6/en/savepoint.html
# Savepoints are supported by MySQL and PostgreSQL. SQLite3 version >= '3.6.8'
# supports savepoints.
#
@@ -189,7 +189,7 @@ module ActiveRecord
# semantics of these different levels:
#
# * http://www.postgresql.org/docs/9.1/static/transaction-iso.html
- # * https://dev.mysql.com/doc/refman/5.0/en/set-transaction.html
+ # * https://dev.mysql.com/doc/refman/5.6/en/set-transaction.html
#
# An <tt>ActiveRecord::TransactionIsolationError</tt> will be raised if:
#
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 8231f44b4e..a768ee2d70 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -535,6 +535,8 @@ module ActiveRecord
# Checks to see if a column exists.
#
+ # t.string(:name) unless t.column_exists?(:name, :string)
+ #
# See SchemaStatements#column_exists?
def column_exists?(column_name, type = nil, options = {})
@base.column_exists?(name, column_name, type, options)
@@ -554,6 +556,10 @@ module ActiveRecord
# Checks to see if an index exists.
#
+ # unless t.index_exists?(:branch_id)
+ # t.index(:branch_id)
+ # end
+ #
# See SchemaStatements#index_exists?
def index_exists?(column_name, options = {})
@base.index_exists?(name, column_name, options)
@@ -667,10 +673,20 @@ module ActiveRecord
end
alias :remove_belongs_to :remove_references
+ # Adds a foreign key.
+ #
+ # t.foreign_key(:authors)
+ #
+ # See SchemaStatements#add_foreign_key
def foreign_key(*args) # :nodoc:
@base.add_foreign_key(name, *args)
end
+ # Checks to see if a foreign key exists.
+ #
+ # t.foreign_key(:authors) unless t.foreign_key_exists?(:authors)
+ #
+ # See SchemaStatements#foreign_key_exists?
def foreign_key_exists?(*args) # :nodoc:
@base.foreign_key_exists?(name, *args)
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
index af7ef7cbaa..999cb0ec5a 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
@@ -24,7 +24,7 @@ module ActiveRecord
def prepare_column_options(column)
spec = {}
spec[:name] = column.name.inspect
- spec[:type] = column.type.to_s
+ spec[:type] = schema_type(column)
spec[:null] = 'false' unless column.null
limit = column.limit || native_database_types[column.type][:limit]
@@ -45,6 +45,10 @@ module ActiveRecord
private
+ def schema_type(column)
+ column.type.to_s
+ end
+
def schema_default(column)
type = lookup_cast_type_from_column(column)
default = type.deserialize(column.default)
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 d42f9a894b..72e019066e 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -652,7 +652,7 @@ module ActiveRecord
alias :add_belongs_to :add_reference
# Removes the reference(s). Also removes a +type+ column if one exists.
- # <tt>remove_reference</tt>, <tt>remove_references</tt> and <tt>remove_belongs_to</tt> are acceptable.
+ # <tt>remove_reference</tt> and <tt>remove_belongs_to</tt> are acceptable.
#
# ====== Remove the reference
#
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb
index c74f4e8fa5..295a7bed87 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb
@@ -44,11 +44,12 @@ module ActiveRecord
attr_reader :connection, :state, :records, :savepoint_name
attr_writer :joinable
- def initialize(connection, options)
+ def initialize(connection, options, run_commit_callbacks: false)
@connection = connection
@state = TransactionState.new
@records = []
@joinable = options.fetch(:joinable, true)
+ @run_commit_callbacks = run_commit_callbacks
end
def add_record(record)
@@ -75,18 +76,21 @@ module ActiveRecord
end
def before_commit_records
- records.uniq.each(&:before_committed!)
+ records.uniq.each(&:before_committed!) if @run_commit_callbacks
end
def commit_records
ite = records.uniq
while record = ite.shift
- record.committed!
+ if @run_commit_callbacks
+ record.committed!
+ else
+ # if not running callbacks, only adds the record to the parent transaction
+ record.add_to_transaction
+ end
end
ensure
- ite.each do |i|
- i.committed!(should_run_callbacks: false)
- end
+ ite.each { |i| i.committed!(should_run_callbacks: false) }
end
def full_rollback?; true; end
@@ -97,8 +101,8 @@ module ActiveRecord
class SavepointTransaction < Transaction
- def initialize(connection, savepoint_name, options)
- super(connection, options)
+ def initialize(connection, savepoint_name, options, *args)
+ super(connection, options, *args)
if options[:isolation]
raise ActiveRecord::TransactionIsolationError, "cannot set transaction isolation in a nested transaction"
end
@@ -120,7 +124,7 @@ module ActiveRecord
class RealTransaction < Transaction
- def initialize(connection, options)
+ def initialize(connection, options, *args)
super
if options[:isolation]
connection.begin_isolated_db_transaction(options[:isolation])
@@ -147,11 +151,13 @@ module ActiveRecord
end
def begin_transaction(options = {})
+ run_commit_callbacks = !current_transaction.joinable?
transaction =
if @stack.empty?
- RealTransaction.new(@connection, options)
+ RealTransaction.new(@connection, options, run_commit_callbacks: run_commit_callbacks)
else
- SavepointTransaction.new(@connection, "active_record_#{@stack.size}", options)
+ SavepointTransaction.new(@connection, "active_record_#{@stack.size}", options,
+ run_commit_callbacks: run_commit_callbacks)
end
@stack.push(transaction)
@@ -159,18 +165,11 @@ module ActiveRecord
end
def commit_transaction
- inner_transaction = @stack.pop
-
- if current_transaction.joinable?
- inner_transaction.commit
- inner_transaction.records.each do |r|
- r.add_to_transaction
- end
- else
- inner_transaction.before_commit_records
- inner_transaction.commit
- inner_transaction.commit_records
- end
+ transaction = @stack.last
+ transaction.before_commit_records
+ @stack.pop
+ transaction.commit
+ transaction.commit_records
end
def rollback_transaction(transaction = nil)
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index c084431588..b7c7ff1187 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -86,8 +86,8 @@ module ActiveRecord
def column_spec_for_primary_key(column)
spec = {}
if column.auto_increment?
- return unless column.limit == 8
- spec[:id] = ':bigint'
+ spec[:id] = ':bigint' if column.bigint?
+ return if spec.empty?
else
spec[:id] = column.type.inspect
spec.merge!(prepare_column_options(column).delete_if { |key, _| [:name, :type, :null].include?(key) })
@@ -785,7 +785,9 @@ module ActiveRecord
subselect = Arel::SelectManager.new(select.engine)
subselect.project Arel.sql(key.name)
- subselect.from subsubselect.as('__active_record_temp')
+ # Materialized subquery by adding distinct
+ # to work with MySQL 5.7.6 which sets optimizer_switch='derived_merge=on'
+ subselect.from subsubselect.distinct.as('__active_record_temp')
end
def add_index_length(option_strings, column_names, options = {})
@@ -903,8 +905,7 @@ module ActiveRecord
def configure_connection
variables = @config.fetch(:variables, {}).stringify_keys
- # By default, MySQL 'where id is null' selects the last inserted id.
- # Turn this off. http://dev.rubyonrails.org/ticket/6778
+ # By default, MySQL 'where id is null' selects the last inserted id; Turn this off.
variables['sql_auto_is_null'] = 0
# Increase timeout so the server doesn't disconnect us.
@@ -913,14 +914,14 @@ module ActiveRecord
variables['wait_timeout'] = self.class.type_cast_config_to_integer(wait_timeout)
# Make MySQL reject illegal values rather than truncating or blanking them, see
- # http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html#sqlmode_strict_all_tables
+ # http://dev.mysql.com/doc/refman/5.6/en/sql-mode.html#sqlmode_strict_all_tables
# If the user has provided another value for sql_mode, don't replace it.
unless variables.has_key?('sql_mode')
variables['sql_mode'] = strict_mode? ? 'STRICT_ALL_TABLES' : ''
end
# NAMES does not have an equals sign, see
- # http://dev.mysql.com/doc/refman/5.0/en/set-statement.html#id944430
+ # http://dev.mysql.com/doc/refman/5.6/en/set-statement.html#id944430
# (trailing comma because variable_assignments will always have content)
if @config[:encoding]
encoding = "NAMES #{@config[:encoding]}"
diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb
index fa5ed07b8a..a67127bd71 100644
--- a/activerecord/lib/active_record/connection_adapters/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/column.rb
@@ -31,7 +31,11 @@ module ActiveRecord
end
def has_default?
- !default.nil?
+ !default.nil? || default_function
+ end
+
+ def bigint?
+ /bigint/ === sql_type
end
# Returns the human name of the column name.
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index 64985ee933..45b935f1d6 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -56,9 +56,9 @@ module ActiveRecord
# * <tt>:password</tt> - Defaults to nothing.
# * <tt>:database</tt> - The name of the database. No default, must be provided.
# * <tt>:encoding</tt> - (Optional) Sets the client encoding by executing "SET NAMES <encoding>" after connection.
- # * <tt>:reconnect</tt> - Defaults to false (See MySQL documentation: http://dev.mysql.com/doc/refman/5.0/en/auto-reconnect.html).
- # * <tt>:strict</tt> - Defaults to true. Enable STRICT_ALL_TABLES. (See MySQL documentation: http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html)
- # * <tt>:variables</tt> - (Optional) A hash session variables to send as <tt>SET @@SESSION.key = value</tt> on each database connection. Use the value +:default+ to set a variable to its DEFAULT value. (See MySQL documentation: http://dev.mysql.com/doc/refman/5.0/en/set-statement.html).
+ # * <tt>:reconnect</tt> - Defaults to false (See MySQL documentation: http://dev.mysql.com/doc/refman/5.6/en/auto-reconnect.html).
+ # * <tt>:strict</tt> - Defaults to true. Enable STRICT_ALL_TABLES. (See MySQL documentation: http://dev.mysql.com/doc/refman/5.6/en/sql-mode.html)
+ # * <tt>:variables</tt> - (Optional) A hash session variables to send as <tt>SET @@SESSION.key = value</tt> on each database connection. Use the value +:default+ to set a variable to its DEFAULT value. (See MySQL documentation: http://dev.mysql.com/doc/refman/5.6/en/set-statement.html).
# * <tt>:sslca</tt> - Necessary to use MySQL with an SSL connection.
# * <tt>:sslkey</tt> - Necessary to use MySQL with an SSL connection.
# * <tt>:sslcert</tt> - Necessary to use MySQL with an SSL connection.
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/array_parser.rb b/activerecord/lib/active_record/connection_adapters/postgresql/array_parser.rb
deleted file mode 100644
index 1b74c039ce..0000000000
--- a/activerecord/lib/active_record/connection_adapters/postgresql/array_parser.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-module ActiveRecord
- module ConnectionAdapters
- module PostgreSQL
- module ArrayParser # :nodoc:
-
- DOUBLE_QUOTE = '"'
- BACKSLASH = "\\"
- COMMA = ','
- BRACKET_OPEN = '{'
- BRACKET_CLOSE = '}'
-
- def parse_pg_array(string) # :nodoc:
- local_index = 0
- array = []
- while(local_index < string.length)
- case string[local_index]
- when BRACKET_OPEN
- local_index,array = parse_array_contents(array, string, local_index + 1)
- when BRACKET_CLOSE
- return array
- end
- local_index += 1
- end
-
- array
- end
-
- private
-
- def parse_array_contents(array, string, index)
- is_escaping = false
- is_quoted = false
- was_quoted = false
- current_item = ''
-
- local_index = index
- while local_index
- token = string[local_index]
- if is_escaping
- current_item << token
- is_escaping = false
- else
- if is_quoted
- case token
- when DOUBLE_QUOTE
- is_quoted = false
- was_quoted = true
- when BACKSLASH
- is_escaping = true
- else
- current_item << token
- end
- else
- case token
- when BACKSLASH
- is_escaping = true
- when COMMA
- add_item_to_array(array, current_item, was_quoted)
- current_item = ''
- was_quoted = false
- when DOUBLE_QUOTE
- is_quoted = true
- when BRACKET_OPEN
- internal_items = []
- local_index,internal_items = parse_array_contents(internal_items, string, local_index + 1)
- array.push(internal_items)
- when BRACKET_CLOSE
- add_item_to_array(array, current_item, was_quoted)
- return local_index,array
- else
- current_item << token
- end
- end
- end
-
- local_index += 1
- end
- return local_index,array
- end
-
- def add_item_to_array(array, current_item, quoted)
- return if !quoted && current_item.length == 0
-
- if !quoted && current_item == 'NULL'
- array.push nil
- else
- array.push current_item
- end
- end
- end
- end
- end
-end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
index 0eb4fb468c..be13ead120 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
@@ -6,7 +6,9 @@ module ActiveRecord
alias :array? :array
def serial?
- default_function && default_function =~ /\Anextval\(.*\)\z/
+ return unless default_function
+
+ %r{\Anextval\('(?<table_name>.+)_#{name}_seq'::regclass\)\z} === default_function
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
index fb4e0de2a8..3de794f797 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
@@ -5,29 +5,20 @@ module ActiveRecord
class Array < Type::Value # :nodoc:
include Type::Helpers::Mutable
- # Loads pg_array_parser if available. String parsing can be
- # performed quicker by a native extension, which will not create
- # a large amount of Ruby objects that will need to be garbage
- # collected. pg_array_parser has a C and Java extension
- begin
- require 'pg_array_parser'
- include PgArrayParser
- rescue LoadError
- require 'active_record/connection_adapters/postgresql/array_parser'
- include PostgreSQL::ArrayParser
- end
-
attr_reader :subtype, :delimiter
- delegate :type, :user_input_in_time_zone, to: :subtype
+ delegate :type, :user_input_in_time_zone, :limit, to: :subtype
def initialize(subtype, delimiter = ',')
@subtype = subtype
@delimiter = delimiter
+
+ @pg_encoder = PG::TextEncoder::Array.new name: "#{type}[]", delimiter: delimiter
+ @pg_decoder = PG::TextDecoder::Array.new name: "#{type}[]", delimiter: delimiter
end
def deserialize(value)
if value.is_a?(::String)
- type_cast_array(parse_pg_array(value), :deserialize)
+ type_cast_array(@pg_decoder.decode(value), :deserialize)
else
super
end
@@ -35,14 +26,14 @@ module ActiveRecord
def cast(value)
if value.is_a?(::String)
- value = parse_pg_array(value)
+ value = @pg_decoder.decode(value)
end
type_cast_array(value, :cast)
end
def serialize(value)
if value.is_a?(::Array)
- cast_value_for_database(value)
+ @pg_encoder.encode(type_cast_array(value, :serialize))
else
super
end
@@ -63,41 +54,6 @@ module ActiveRecord
@subtype.public_send(method, value)
end
end
-
- def cast_value_for_database(value)
- if value.is_a?(::Array)
- casted_values = value.map { |item| cast_value_for_database(item) }
- "{#{casted_values.join(delimiter)}}"
- else
- quote_and_escape(subtype.serialize(value))
- end
- end
-
- ARRAY_ESCAPE = "\\" * 2 * 2 # escape the backslash twice for PG arrays
-
- def quote_and_escape(value)
- case value
- when ::String
- if string_requires_quoting?(value)
- value = value.gsub(/\\/, ARRAY_ESCAPE)
- value.gsub!(/"/,"\\\"")
- %("#{value}")
- else
- value
- end
- when nil then "NULL"
- else value
- end
- end
-
- # See http://www.postgresql.org/docs/9.2/static/arrays.html#ARRAYS-IO
- # for a list of all cases in which strings will be quoted.
- def string_requires_quoting?(string)
- string.empty? ||
- string == "NULL" ||
- string =~ /[\{\}"\\\s]/ ||
- string.include?(delimiter)
- end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb
index b3b610a5f6..91d339f32c 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb
@@ -7,7 +7,9 @@ module ActiveRecord
:enum
end
- def cast(value)
+ private
+
+ def cast_value(value)
value.to_s
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb
index 9b3de41fab..191c828e60 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb
@@ -15,11 +15,11 @@ module ActiveRecord
def run(records)
nodes = records.reject { |row| @store.key? row['oid'].to_i }
mapped, nodes = nodes.partition { |row| @store.key? row['typname'] }
- ranges, nodes = nodes.partition { |row| row['typtype'] == 'r' }
- enums, nodes = nodes.partition { |row| row['typtype'] == 'e' }
- domains, nodes = nodes.partition { |row| row['typtype'] == 'd' }
- arrays, nodes = nodes.partition { |row| row['typinput'] == 'array_in' }
- composites, nodes = nodes.partition { |row| row['typelem'] != '0' }
+ ranges, nodes = nodes.partition { |row| row['typtype'] == 'r'.freeze }
+ enums, nodes = nodes.partition { |row| row['typtype'] == 'e'.freeze }
+ domains, nodes = nodes.partition { |row| row['typtype'] == 'd'.freeze }
+ arrays, nodes = nodes.partition { |row| row['typinput'] == 'array_in'.freeze }
+ composites, nodes = nodes.partition { |row| row['typelem'].to_i != 0 }
mapped.each { |row| register_mapped_type(row) }
enums.each { |row| register_enum_type(row) }
@@ -29,6 +29,18 @@ module ActiveRecord
composites.each { |row| register_composite_type(row) }
end
+ def query_conditions_for_initial_load(type_map)
+ known_type_names = type_map.keys.map { |n| "'#{n}'" }
+ known_type_types = %w('r' 'e' 'd')
+ <<-SQL % [known_type_names.join(", "), known_type_types.join(", ")]
+ WHERE
+ t.typname IN (%s)
+ OR t.typtype IN (%s)
+ OR t.typinput::varchar = 'array_in'
+ OR t.typelem != 0
+ SQL
+ end
+
private
def register_mapped_type(row)
alias_type row['oid'], row['typname']
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/referential_integrity.rb b/activerecord/lib/active_record/connection_adapters/postgresql/referential_integrity.rb
index c1835380f9..44a7338bf5 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/referential_integrity.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/referential_integrity.rb
@@ -14,7 +14,7 @@ module ActiveRecord
transaction(requires_new: true) do
execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
end
- rescue => e
+ rescue ActiveRecord::ActiveRecordError => e
original_exception = e
end
@@ -34,10 +34,10 @@ Rails needs superuser privileges to disable referential integrity.
end
begin
- transaction(require_new: true) do
+ transaction(requires_new: true) do
execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} ENABLE TRIGGER ALL" }.join(";"))
end
- rescue
+ rescue ActiveRecord::ActiveRecordError
end
else
yield
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
index eeb141dd1e..cb0b9cdbe9 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -129,8 +129,8 @@ module ActiveRecord
result.map do |row|
index_name = row[0]
- unique = row[1] == 't'
- indkey = row[2].split(" ")
+ unique = row[1]
+ indkey = row[2].split(" ").map(&:to_i)
inddef = row[3]
oid = row[4]
@@ -164,7 +164,7 @@ module ActiveRecord
type_metadata = fetch_type_metadata(column_name, type, oid, fmod)
default_value = extract_value_from_default(default)
default_function = extract_default_function(default_value, default)
- new_column(column_name, default_value, type_metadata, notnull == 'f', default_function)
+ new_column(column_name, default_value, type_metadata, !notnull, default_function)
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 6d25b53b21..00fc69c878 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -1,3 +1,7 @@
+# Make sure we're using pg high enough for type casts and Ruby 2.2+ compatibility
+gem 'pg', '~> 0.18'
+require 'pg'
+
require "active_record/connection_adapters/abstract_adapter"
require "active_record/connection_adapters/postgresql/column"
require "active_record/connection_adapters/postgresql/database_statements"
@@ -12,10 +16,6 @@ require "active_record/connection_adapters/statement_pool"
require 'arel/visitors/bind_visitor'
-# Make sure we're using pg high enough for PGResult#values
-gem 'pg', '~> 0.15'
-require 'pg'
-
require 'ipaddr'
module ActiveRecord
@@ -128,7 +128,7 @@ module ActiveRecord
def column_spec_for_primary_key(column)
spec = {}
if column.serial?
- return unless column.sql_type == 'bigint'
+ return unless column.bigint?
spec[:id] = ':bigserial'
elsif column.type == :uuid
spec[:id] = ':uuid'
@@ -145,7 +145,6 @@ module ActiveRecord
def prepare_column_options(column) # :nodoc:
spec = super
spec[:array] = 'true' if column.array?
- spec[:default] = "\"#{column.default_function}\"" if column.default_function
spec
end
@@ -154,6 +153,26 @@ module ActiveRecord
super + [:array]
end
+ def schema_type(column)
+ return super unless column.serial?
+
+ if column.bigint?
+ 'bigserial'
+ else
+ 'serial'
+ end
+ end
+ private :schema_type
+
+ def schema_default(column)
+ if column.default_function
+ column.default_function.inspect unless column.serial?
+ else
+ super
+ end
+ end
+ private :schema_default
+
# Returns +true+, since this connection adapter supports prepared statement
# caching.
def supports_statement_cache?
@@ -259,8 +278,7 @@ module ActiveRecord
@table_alias_length = nil
connect
- add_pg_decoders
-
+ add_pg_encoders
@statements = StatementPool.new @connection,
self.class.type_cast_config_to_integer(config.fetch(:statement_limit) { 1000 })
@@ -268,6 +286,8 @@ module ActiveRecord
raise "Your version of PostgreSQL (#{postgresql_version}) is too old, please upgrade!"
end
+ add_pg_decoders
+
@type_map = Type::HashLookupTypeMap.new
initialize_type_map(type_map)
@local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"]
@@ -574,6 +594,8 @@ module ActiveRecord
end
def load_additional_types(type_map, oids = nil) # :nodoc:
+ initializer = OID::TypeMapInitializer.new(type_map)
+
if supports_ranges?
query = <<-SQL
SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
@@ -589,11 +611,13 @@ module ActiveRecord
if oids
query += "WHERE t.oid::integer IN (%s)" % oids.join(", ")
+ else
+ query += initializer.query_conditions_for_initial_load(type_map)
end
- initializer = OID::TypeMapInitializer.new(type_map)
- records = execute(query, 'SCHEMA')
- initializer.run(records)
+ execute_and_clear(query, 'SCHEMA', []) do |records|
+ initializer.run(records)
+ end
end
FEATURE_NOT_SUPPORTED = "0A000" #:nodoc:
@@ -779,11 +803,20 @@ module ActiveRecord
)
end_sql
execute_and_clear(sql, "SCHEMA", []) do |result|
- result.getvalue(0, 0) == 't'
+ result.getvalue(0, 0)
end
end
end
+ def add_pg_encoders
+ map = PG::TypeMapByClass.new
+ map[Integer] = PG::TextEncoder::Integer.new
+ map[TrueClass] = PG::TextEncoder::Boolean.new
+ map[FalseClass] = PG::TextEncoder::Boolean.new
+ map[Float] = PG::TextEncoder::Float.new
+ @connection.type_map_for_queries = map
+ end
+
def add_pg_decoders
coders_by_name = {
'int2' => PG::TextDecoder::Integer,
@@ -794,13 +827,15 @@ module ActiveRecord
'float8' => PG::TextDecoder::Float,
'bool' => PG::TextDecoder::Boolean,
}
- query = <<-SQL
- SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, t.typtype, t.typbasetype
+ known_coder_types = coders_by_name.keys.map { |n| quote(n) }
+ query = <<-SQL % known_coder_types.join(", ")
+ SELECT t.oid, t.typname
FROM pg_type as t
+ WHERE t.typname IN (%s)
SQL
coders = execute_and_clear(query, "SCHEMA", []) do |result|
result
- .map { |row| construct_coder(row, coders_by_name['typname']) }
+ .map { |row| construct_coder(row, coders_by_name[row['typname']]) }
.compact
end
@@ -811,7 +846,7 @@ module ActiveRecord
def construct_coder(row, coder_class)
return unless coder_class
- coder_class.new(oid: row['oid'], name: row['typname'])
+ coder_class.new(oid: row['oid'].to_i, name: row['typname'])
end
ActiveRecord::Type.add_modifier({ array: true }, OID::Array, adapter: :postgresql)
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index 97ce4642aa..9b7cba08de 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -85,6 +85,24 @@ module ActiveRecord
mattr_accessor :dump_schema_after_migration, instance_writer: false
self.dump_schema_after_migration = true
+ ##
+ # :singleton-method:
+ # Specifies which database schemas to dump when calling db:structure:dump.
+ # If :schema_search_path (the default), it will dumps any schemas listed in schema_search_path.
+ # Use :all to always dumps all schemas regardless of the schema_search_path.
+ # A string of comma separated schemas can also be used to pass a custom list of schemas.
+ mattr_accessor :dump_schemas, instance_writer: false
+ self.dump_schemas = :schema_search_path
+
+ ##
+ # :singleton-method:
+ # Specify a threshold for the size of query result sets. If the number of
+ # records in the set exceeds the threshold, a warning is logged. This can
+ # be used to identify queries which load thousands of records and
+ # potentially cause memory bloat.
+ mattr_accessor :warn_on_records_fetched_greater_than, instance_writer: false
+ self.warn_on_records_fetched_greater_than = nil
+
mattr_accessor :maintain_test_schema, instance_accessor: false
mattr_accessor :belongs_to_required_by_default, instance_accessor: false
@@ -123,8 +141,7 @@ module ActiveRecord
return super unless ids.length == 1
return super if block_given? ||
primary_key.nil? ||
- default_scopes.any? ||
- current_scope ||
+ scope_attributes? ||
columns_hash.include?(inheritance_column) ||
ids.first.kind_of?(Array)
@@ -152,8 +169,7 @@ module ActiveRecord
end
def find_by(*args) # :nodoc:
- return super if current_scope || !(Hash === args.first) || reflect_on_all_aggregations.any?
- return super if default_scopes.any?
+ return super if scope_attributes? || !(Hash === args.first) || reflect_on_all_aggregations.any?
hash = args.first
@@ -289,17 +305,22 @@ module ActiveRecord
_run_initialize_callbacks
end
- # Initialize an empty model object from +coder+. +coder+ must contain
- # the attributes necessary for initializing an empty model object. For
- # example:
+ # Initialize an empty model object from +coder+. +coder+ should be
+ # the result of previously encoding an Active Record model, using
+ # `encode_with`
#
# class Post < ActiveRecord::Base
# end
#
+ # old_post = Post.new(title: "hello world")
+ # coder = {}
+ # old_post.encode_with(coder)
+ #
# post = Post.allocate
- # post.init_with('attributes' => { 'title' => 'hello world' })
+ # post.init_with(coder)
# post.title # => 'hello world'
def init_with(coder)
+ coder = LegacyYamlAdapter.convert(self.class, coder)
@attributes = coder['attributes']
init_internals
@@ -370,6 +391,7 @@ module ActiveRecord
coder['raw_attributes'] = attributes_before_type_cast
coder['attributes'] = @attributes
coder['new_record'] = new_record?
+ coder['active_record_yaml_version'] = 1
end
# Returns true if +comparison_object+ is the same exact object, or +comparison_object+
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 18775caad2..2c1771dd6c 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -139,13 +139,13 @@ module ActiveRecord
# name: kitten.png
# sha: <%= file_sha 'files/kitten.png' %>
#
- # = Transactional Fixtures
+ # = Transactional Tests
#
# Test cases can use begin+rollback to isolate their changes to the database instead of having to
# delete+insert for every test case.
#
# class FooTest < ActiveSupport::TestCase
- # self.use_transactional_fixtures = true
+ # self.use_transactional_tests = true
#
# test "godzilla" do
# assert !Foo.all.empty?
@@ -159,14 +159,14 @@ module ActiveRecord
# end
#
# If you preload your test database with all fixture data (probably in the rake task) and use
- # transactional fixtures, then you may omit all fixtures declarations in your test cases since
+ # transactional tests, then you may omit all fixtures declarations in your test cases since
# all the data's already there and every case rolls back its changes.
#
# In order to use instantiated fixtures with preloaded data, set +self.pre_loaded_fixtures+ to
# true. This will provide access to fixture data for every table that has been loaded through
# fixtures (depending on the value of +use_instantiated_fixtures+).
#
- # When *not* to use transactional fixtures:
+ # When *not* to use transactional tests:
#
# 1. You're testing whether a transaction works correctly. Nested transactions don't commit until
# all parent transactions commit, particularly, the fixtures transaction which is begun in setup
@@ -835,13 +835,15 @@ module ActiveRecord
class_attribute :fixture_path, :instance_writer => false
class_attribute :fixture_table_names
class_attribute :fixture_class_names
+ class_attribute :use_transactional_tests
class_attribute :use_transactional_fixtures
class_attribute :use_instantiated_fixtures # true, false, or :no_instances
class_attribute :pre_loaded_fixtures
class_attribute :config
+ singleton_class.deprecate 'use_transactional_fixtures=' => 'use use_transactional_tests= instead'
+
self.fixture_table_names = []
- self.use_transactional_fixtures = true
self.use_instantiated_fixtures = false
self.pre_loaded_fixtures = false
self.config = ActiveRecord::Base
@@ -849,6 +851,16 @@ module ActiveRecord
self.fixture_class_names = Hash.new do |h, fixture_set_name|
h[fixture_set_name] = ActiveRecord::FixtureSet.default_fixture_model_name(fixture_set_name, self.config)
end
+
+ silence_warnings do
+ define_singleton_method :use_transactional_tests do
+ if use_transactional_fixtures.nil?
+ true
+ else
+ use_transactional_fixtures
+ end
+ end
+ end
end
module ClassMethods
@@ -919,13 +931,13 @@ module ActiveRecord
end
def run_in_transaction?
- use_transactional_fixtures &&
+ use_transactional_tests &&
!self.class.uses_transaction?(method_name)
end
def setup_fixtures(config = ActiveRecord::Base)
- if pre_loaded_fixtures && !use_transactional_fixtures
- raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_fixtures'
+ if pre_loaded_fixtures && !use_transactional_tests
+ raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_tests'
end
@fixture_cache = {}
diff --git a/activerecord/lib/active_record/legacy_yaml_adapter.rb b/activerecord/lib/active_record/legacy_yaml_adapter.rb
new file mode 100644
index 0000000000..89dee58423
--- /dev/null
+++ b/activerecord/lib/active_record/legacy_yaml_adapter.rb
@@ -0,0 +1,46 @@
+module ActiveRecord
+ module LegacyYamlAdapter
+ def self.convert(klass, coder)
+ return coder unless coder.is_a?(Psych::Coder)
+
+ case coder["active_record_yaml_version"]
+ when 1 then coder
+ else
+ if coder["attributes"].is_a?(AttributeSet)
+ Rails420.convert(klass, coder)
+ else
+ Rails41.convert(klass, coder)
+ end
+ end
+ end
+
+ module Rails420
+ def self.convert(klass, coder)
+ attribute_set = coder["attributes"]
+
+ klass.attribute_names.each do |attr_name|
+ attribute = attribute_set[attr_name]
+ if attribute.type.is_a?(Delegator)
+ type_from_klass = klass.type_for_attribute(attr_name)
+ attribute_set[attr_name] = attribute.with_type(type_from_klass)
+ end
+ end
+
+ coder
+ end
+ end
+
+ module Rails41
+ def self.convert(klass, coder)
+ attributes = klass.attributes_builder
+ .build_from_database(coder["attributes"])
+ new_record = coder["attributes"][klass.primary_key].blank?
+
+ {
+ "attributes" => attributes,
+ "new_record" => new_record,
+ }
+ end
+ end
+ end
+end
diff --git a/activerecord/lib/active_record/locking/pessimistic.rb b/activerecord/lib/active_record/locking/pessimistic.rb
index ff7102d35b..3d95c54ef3 100644
--- a/activerecord/lib/active_record/locking/pessimistic.rb
+++ b/activerecord/lib/active_record/locking/pessimistic.rb
@@ -51,7 +51,7 @@ module ActiveRecord
# end
#
# Database-specific information on row locking:
- # MySQL: http://dev.mysql.com/doc/refman/5.1/en/innodb-locking-reads.html
+ # MySQL: http://dev.mysql.com/doc/refman/5.6/en/innodb-locking-reads.html
# PostgreSQL: http://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE
module Pessimistic
# Obtain a row lock on this record. Reloads the record to obtain the requested
diff --git a/activerecord/lib/active_record/null_relation.rb b/activerecord/lib/active_record/null_relation.rb
index fa6eaa7e64..74894d0c37 100644
--- a/activerecord/lib/active_record/null_relation.rb
+++ b/activerecord/lib/active_record/null_relation.rb
@@ -14,7 +14,7 @@ module ActiveRecord
0
end
- def update_all(_updates, _conditions = nil, _options = {})
+ def update_all(_updates)
0
end
@@ -80,7 +80,7 @@ module ActiveRecord
end
end
- def exists?(_id = false)
+ def exists?(_conditions = :none)
false
end
diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb
index b6de90e89d..7e907beec0 100644
--- a/activerecord/lib/active_record/railtie.rb
+++ b/activerecord/lib/active_record/railtie.rb
@@ -58,9 +58,6 @@ module ActiveRecord
require "active_record/railties/console_sandbox" if app.sandbox?
require "active_record/base"
console = ActiveSupport::Logger.new(STDERR)
- console.formatter = Rails.logger.formatter
- console.level = Rails.logger.level
-
Rails.logger.extend ActiveSupport::Logger.broadcast console
end
@@ -105,6 +102,14 @@ module ActiveRecord
end
end
+ initializer "active_record.warn_on_records_fetched_greater_than" do
+ if config.active_record.warn_on_records_fetched_greater_than
+ ActiveSupport.on_load(:active_record) do
+ require 'active_record/relation/record_fetch_warning'
+ end
+ end
+ end
+
initializer "active_record.set_configs" do |app|
ActiveSupport.on_load(:active_record) do
app.config.active_record.each do |k,v|
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index dab5a502a5..4265afc0a5 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -166,8 +166,8 @@ module ActiveRecord
# AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.
#
# MacroReflection
+ # AggregateReflection
# AssociationReflection
- # AggregateReflection
# HasManyReflection
# HasOneReflection
# BelongsToReflection
@@ -370,6 +370,12 @@ module ActiveRecord
[self]
end
+ # This is for clearing cache on the reflection. Useful for tests that need to compare
+ # SQL queries on associations.
+ def clear_association_scope_cache # :nodoc:
+ @association_scope_cache.clear
+ end
+
def nested?
false
end
@@ -694,7 +700,7 @@ module ActiveRecord
def chain
@chain ||= begin
a = source_reflection.chain
- b = through_reflection.chain
+ b = through_reflection.chain.map(&:dup)
if options[:source_type]
b[0] = PolymorphicReflection.new(b[0], self)
@@ -706,6 +712,15 @@ module ActiveRecord
end
end
+ # This is for clearing cache on the reflection. Useful for tests that need to compare
+ # SQL queries on associations.
+ def clear_association_scope_cache # :nodoc:
+ @chain = nil
+ delegate_reflection.clear_association_scope_cache
+ source_reflection.clear_association_scope_cache
+ through_reflection.clear_association_scope_cache
+ end
+
# Consider the following example:
#
# class Person
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 6bbec7c0c0..85648a7f8f 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -205,7 +205,9 @@ module ActiveRecord
# constraint an exception may be raised, just retry:
#
# begin
- # CreditAccount.find_or_create_by(user_id: user.id)
+ # CreditAccount.transaction(requires_new: true) do
+ # CreditAccount.find_or_create_by(user_id: user.id)
+ # end
# rescue ActiveRecord::RecordNotUnique
# retry
# end
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index 7f27e7b463..8f16de3519 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -182,7 +182,7 @@ module ActiveRecord
private
def has_include?(column_name)
- eager_loading? || (includes_values.present? && ((column_name && column_name != :all) || references_eager_loaded_tables?))
+ eager_loading? || (includes_values.present? && column_name && column_name != :all)
end
def perform_calculation(operation, column_name)
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 7bd091b66c..6a3a56f1cc 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -5,7 +5,7 @@ module ActiveRecord
ONE_AS_ONE = '1 AS one'
# Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]).
- # If no record can be found for all of the listed ids, then RecordNotFound will be raised. If the primary key
+ # If one or more records can not be found for the requested ids, then RecordNotFound will be raised. If the primary key
# is an integer, find by id coerces its arguments using +to_i+.
#
# Person.find(1) # returns the object for ID = 1
@@ -16,8 +16,6 @@ module ActiveRecord
# Person.find([1]) # returns an array for the object with ID = 1
# Person.where("administrator = 1").order("created_on DESC").find(1)
#
- # <tt>ActiveRecord::RecordNotFound</tt> will be raised if one or more ids are not found.
- #
# NOTE: The returned records may not be in the same order as the ids you
# provide since database rows are unordered. You'd need to provide an explicit <tt>order</tt>
# option if you want the results are sorted.
@@ -378,7 +376,7 @@ module ActiveRecord
def construct_relation_for_association_calculations
from = arel.froms.first
if Arel::Table === from
- apply_join_dependency(self, construct_join_dependency)
+ apply_join_dependency(self, construct_join_dependency(joins_values))
else
# FIXME: as far as I can tell, `from` will always be an Arel::Table.
# There are no tests that test this branch, but presumably it's
diff --git a/activerecord/lib/active_record/relation/record_fetch_warning.rb b/activerecord/lib/active_record/relation/record_fetch_warning.rb
new file mode 100644
index 0000000000..14e1bf89fa
--- /dev/null
+++ b/activerecord/lib/active_record/relation/record_fetch_warning.rb
@@ -0,0 +1,49 @@
+module ActiveRecord
+ class Relation
+ module RecordFetchWarning
+ # When this module is prepended to ActiveRecord::Relation and
+ # `config.active_record.warn_on_records_fetched_greater_than` is
+ # set to an integer, if the number of records a query returns is
+ # greater than the value of `warn_on_records_fetched_greater_than`,
+ # a warning is logged. This allows for the detection of queries that
+ # return a large number of records, which could cause memory bloat.
+ #
+ # In most cases, fetching large number of records can be performed
+ # efficiently using the ActiveRecord::Batches methods.
+ # See active_record/lib/relation/batches.rb for more information.
+ def exec_queries
+ QueryRegistry.reset
+
+ super.tap do
+ if logger && warn_on_records_fetched_greater_than
+ if @records.length > warn_on_records_fetched_greater_than
+ logger.warn "Query fetched #{@records.size} #{@klass} records: #{QueryRegistry.queries.join(";")}"
+ end
+ end
+ end
+ end
+
+ ActiveSupport::Notifications.subscribe("sql.active_record") do |*args|
+ payload = args.last
+
+ QueryRegistry.queries << payload[:sql]
+ end
+
+ class QueryRegistry # :nodoc:
+ extend ActiveSupport::PerThreadRegistry
+
+ attr_accessor :queries
+
+ def initialize
+ reset
+ end
+
+ def reset
+ @queries = []
+ end
+ end
+ end
+ end
+end
+
+ActiveRecord::Relation.prepend ActiveRecord::Relation::RecordFetchWarning
diff --git a/activerecord/lib/active_record/scoping.rb b/activerecord/lib/active_record/scoping.rb
index fca4f1c9d3..f049b658c4 100644
--- a/activerecord/lib/active_record/scoping.rb
+++ b/activerecord/lib/active_record/scoping.rb
@@ -17,6 +17,17 @@ module ActiveRecord
def current_scope=(scope) #:nodoc:
ScopeRegistry.set_value_for(:current_scope, self.to_s, scope)
end
+
+ # Collects attributes from scopes that should be applied when creating
+ # an AR instance for the particular class this is called on.
+ def scope_attributes # :nodoc:
+ all.scope_for_create
+ end
+
+ # Are there attributes associated with this scope?
+ def scope_attributes? # :nodoc:
+ current_scope
+ end
end
def populate_with_current_scope_attributes
diff --git a/activerecord/lib/active_record/scoping/default.rb b/activerecord/lib/active_record/scoping/default.rb
index 18190cb535..5ec2c88b47 100644
--- a/activerecord/lib/active_record/scoping/default.rb
+++ b/activerecord/lib/active_record/scoping/default.rb
@@ -33,6 +33,11 @@ module ActiveRecord
block_given? ? relation.scoping { yield } : relation
end
+ # Are there attributes associated with this scope?
+ def scope_attributes? # :nodoc:
+ super || default_scopes.any?
+ end
+
def before_remove_const #:nodoc:
self.current_scope = nil
end
diff --git a/activerecord/lib/active_record/scoping/named.rb b/activerecord/lib/active_record/scoping/named.rb
index 43c7b1c574..7b62626896 100644
--- a/activerecord/lib/active_record/scoping/named.rb
+++ b/activerecord/lib/active_record/scoping/named.rb
@@ -39,17 +39,6 @@ module ActiveRecord
end
end
- # Collects attributes from scopes that should be applied when creating
- # an AR instance for the particular class this is called on.
- def scope_attributes # :nodoc:
- all.scope_for_create
- end
-
- # Are there default attributes associated with this scope?
- def scope_attributes? # :nodoc:
- current_scope || default_scopes.any?
- end
-
# Adds a class method for retrieving and querying objects. A \scope
# represents a narrowing of a database query, such as
# <tt>where(color: :red).select('shirts.*').includes(:washing_instructions)</tt>.
diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb
index 69aceb66b1..683741768b 100644
--- a/activerecord/lib/active_record/tasks/database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/database_tasks.rb
@@ -212,7 +212,7 @@ module ActiveRecord
load_schema(*args)
end
- def schema_file(format = ActiveSupport::Base.schema_format)
+ def schema_file(format = ActiveRecord::Base.schema_format)
case format
when :ruby
File.join(db_dir, "schema.rb")
diff --git a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
index ce1de4b76e..d7da95c8a9 100644
--- a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
@@ -46,7 +46,15 @@ module ActiveRecord
def structure_dump(filename)
set_psql_env
- search_path = configuration['schema_search_path']
+
+ search_path = case ActiveRecord::Base.dump_schemas
+ when :schema_search_path
+ configuration['schema_search_path']
+ when :all
+ nil
+ when String
+ ActiveRecord::Base.dump_schemas
+ end
unless search_path.blank?
search_path = search_path.split(",").map{|search_path_part| "--schema=#{Shellwords.escape(search_path_part.strip)}" }.join(" ")
end
@@ -59,7 +67,7 @@ module ActiveRecord
def structure_load(filename)
set_psql_env
- Kernel.system("psql -q -f #{Shellwords.escape(filename)} #{configuration['database']}")
+ Kernel.system("psql -X -q -f #{Shellwords.escape(filename)} #{configuration['database']}")
end
private
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb
index ffe7c4ae42..2293d1b258 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -227,8 +227,6 @@ module ActiveRecord
# after_commit :do_foo_bar, on: [:create, :update]
# after_commit :do_bar_baz, on: [:update, :destroy]
#
- # Note that transactional fixtures do not play well with this feature. Please
- # use the +test_after_commit+ gem to have these hooks fired in tests.
def after_commit(*args, &block)
set_options_for_callbacks!(args)
set_callback(:commit, :after, *args, &block)
@@ -356,6 +354,7 @@ module ActiveRecord
if has_transactional_callbacks?
self.class.connection.add_transaction_record(self)
else
+ sync_with_transaction_state
set_transaction_state(self.class.connection.transaction_state)
end
remember_transaction_record_state
@@ -413,13 +412,14 @@ module ActiveRecord
transaction_level = (@_start_transaction_state[:level] || 0) - 1
if transaction_level < 1 || force
restore_state = @_start_transaction_state
- thaw unless restore_state[:frozen?]
+ thaw
@new_record = restore_state[:new_record]
@destroyed = restore_state[:destroyed]
pk = self.class.primary_key
if pk && read_attribute(pk) != restore_state[:id]
write_attribute(pk, restore_state[:id])
end
+ freeze if restore_state[:frozen?]
end
end
end
@@ -454,13 +454,13 @@ module ActiveRecord
end
# Updates the attributes on this particular ActiveRecord object so that
- # if it is associated with a transaction, then the state of the AR object
- # will be updated to reflect the current state of the transaction
+ # if it's associated with a transaction, then the state of the ActiveRecord
+ # object will be updated to reflect the current state of the transaction
#
# The @transaction_state variable stores the states of the associated
# transaction. This relies on the fact that a transaction can only be in
# one rollback or commit (otherwise a list of states would be required)
- # Each AR object inside of a transaction carries that transaction's
+ # Each ActiveRecord object inside of a transaction carries that transaction's
# TransactionState.
#
# This method checks to see if the ActiveRecord object's state reflects
diff --git a/activerecord/lib/active_record/type/hash_lookup_type_map.rb b/activerecord/lib/active_record/type/hash_lookup_type_map.rb
index 82d9327fc0..3b01e3f8ca 100644
--- a/activerecord/lib/active_record/type/hash_lookup_type_map.rb
+++ b/activerecord/lib/active_record/type/hash_lookup_type_map.rb
@@ -1,12 +1,18 @@
module ActiveRecord
module Type
class HashLookupTypeMap < TypeMap # :nodoc:
- delegate :key?, to: :@mapping
-
def alias_type(type, alias_type)
register_type(type) { |_, *args| lookup(alias_type, *args) }
end
+ def key?(key)
+ @mapping.key?(key)
+ end
+
+ def keys
+ @mapping.keys
+ end
+
private
def perform_fetch(type, *args, &block)
diff --git a/activerecord/lib/active_record/type/serialized.rb b/activerecord/lib/active_record/type/serialized.rb
index 732029c723..ea3e0d6a45 100644
--- a/activerecord/lib/active_record/type/serialized.rb
+++ b/activerecord/lib/active_record/type/serialized.rb
@@ -26,9 +26,15 @@ module ActiveRecord
end
end
+ def inspect
+ Kernel.instance_method(:inspect).bind(self).call
+ end
+
def changed_in_place?(raw_old_value, value)
return false if value.nil?
- subtype.changed_in_place?(raw_old_value, serialize(value))
+ raw_new_value = serialize(value)
+ raw_old_value.nil? != raw_new_value.nil? ||
+ subtype.changed_in_place?(raw_old_value, raw_new_value)
end
def accessor
diff --git a/activerecord/lib/active_record/type/value.rb b/activerecord/lib/active_record/type/value.rb
index fc3ef5e83b..6b9d147ecc 100644
--- a/activerecord/lib/active_record/type/value.rb
+++ b/activerecord/lib/active_record/type/value.rb
@@ -12,7 +12,7 @@ module ActiveRecord
def type # :nodoc:
end
- # Convert a value from database input to the appropriate ruby type. The
+ # Converts a value from database input to the appropriate ruby type. The
# return value of this method will be returned from
# ActiveRecord::AttributeMethods::Read#read_attribute. The default
# implementation just calls Value#cast.
@@ -36,7 +36,7 @@ module ActiveRecord
cast_value(value) unless value.nil?
end
- # Cast a value from the ruby type to a type that the database knows how
+ # Casts a value from the ruby type to a type that the database knows how
# to understand. The returned value from this method should be a
# +String+, +Numeric+, +Date+, +Time+, +Symbol+, +true+, +false+, or
# +nil+.
@@ -44,7 +44,7 @@ module ActiveRecord
value
end
- # Type cast a value for schema dumping. This method is private, as we are
+ # Type casts a value for schema dumping. This method is private, as we are
# hoping to remove it entirely.
def type_cast_for_schema(value) # :nodoc:
value.inspect
diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb
index ecf1368a91..1712ff0ac6 100644
--- a/activerecord/test/cases/adapter_test.rb
+++ b/activerecord/test/cases/adapter_test.rb
@@ -226,7 +226,7 @@ module ActiveRecord
end
class AdapterTestWithoutTransaction < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
class Klass < ActiveRecord::Base
end
diff --git a/activerecord/test/cases/adapters/mysql/consistency_test.rb b/activerecord/test/cases/adapters/mysql/consistency_test.rb
index e972d6b330..ae190b728d 100644
--- a/activerecord/test/cases/adapters/mysql/consistency_test.rb
+++ b/activerecord/test/cases/adapters/mysql/consistency_test.rb
@@ -1,7 +1,7 @@
require "cases/helper"
class MysqlConsistencyTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
class Consistency < ActiveRecord::Base
self.table_name = "mysql_consistency"
diff --git a/activerecord/test/cases/adapters/mysql/reserved_word_test.rb b/activerecord/test/cases/adapters/mysql/reserved_word_test.rb
index 2f9c070255..ec1c394f40 100644
--- a/activerecord/test/cases/adapters/mysql/reserved_word_test.rb
+++ b/activerecord/test/cases/adapters/mysql/reserved_word_test.rb
@@ -71,7 +71,7 @@ class MysqlReservedWordTest < ActiveRecord::TestCase
#fixtures
self.use_instantiated_fixtures = true
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
#activerecord model class with reserved-word table name
def test_activerecord_model
diff --git a/activerecord/test/cases/adapters/mysql/unsigned_type_test.rb b/activerecord/test/cases/adapters/mysql/unsigned_type_test.rb
index 8f521e9181..e9edc53f93 100644
--- a/activerecord/test/cases/adapters/mysql/unsigned_type_test.rb
+++ b/activerecord/test/cases/adapters/mysql/unsigned_type_test.rb
@@ -1,7 +1,7 @@
require "cases/helper"
class UnsignedTypeTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
class UnsignedType < ActiveRecord::Base
end
diff --git a/activerecord/test/cases/adapters/mysql2/boolean_test.rb b/activerecord/test/cases/adapters/mysql2/boolean_test.rb
index 0e641ba3bf..0d81dd6eee 100644
--- a/activerecord/test/cases/adapters/mysql2/boolean_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/boolean_test.rb
@@ -1,7 +1,7 @@
require "cases/helper"
class Mysql2BooleanTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
class BooleanType < ActiveRecord::Base
self.table_name = "mysql_booleans"
diff --git a/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb
index beb829fc46..799e60a683 100644
--- a/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb
@@ -71,7 +71,7 @@ class MysqlReservedWordTest < ActiveRecord::TestCase
#fixtures
self.use_instantiated_fixtures = true
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
#activerecord model class with reserved-word table name
def test_activerecord_model
diff --git a/activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb b/activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb
index 8f521e9181..e9edc53f93 100644
--- a/activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb
@@ -1,7 +1,7 @@
require "cases/helper"
class UnsignedTypeTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
class UnsignedType < ActiveRecord::Base
end
diff --git a/activerecord/test/cases/adapters/postgresql/array_test.rb b/activerecord/test/cases/adapters/postgresql/array_test.rb
index 2163e35e70..6edbd9c3a6 100644
--- a/activerecord/test/cases/adapters/postgresql/array_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/array_test.rb
@@ -23,6 +23,7 @@ class PostgresqlArrayTest < ActiveRecord::TestCase
t.hstore :hstores, array: true
end
end
+ PgArray.reset_column_information
@column = PgArray.columns_hash['tags']
@type = PgArray.type_for_attribute("tags")
end
diff --git a/activerecord/test/cases/adapters/postgresql/datatype_test.rb b/activerecord/test/cases/adapters/postgresql/datatype_test.rb
index 4f48a7bce3..2c14252ae4 100644
--- a/activerecord/test/cases/adapters/postgresql/datatype_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/datatype_test.rb
@@ -12,7 +12,7 @@ class PostgresqlLtree < ActiveRecord::Base
end
class PostgresqlDataTypeTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
def setup
@connection = ActiveRecord::Base.connection
diff --git a/activerecord/test/cases/adapters/postgresql/enum_test.rb b/activerecord/test/cases/adapters/postgresql/enum_test.rb
index 7458de23d8..ed084483bc 100644
--- a/activerecord/test/cases/adapters/postgresql/enum_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/enum_test.rb
@@ -80,4 +80,12 @@ class PostgresqlEnumTest < ActiveRecord::TestCase
assert_equal "happy", enum.current_mood
end
+
+ def test_assigning_enum_to_nil
+ model = PostgresqlEnum.new(current_mood: nil)
+
+ assert_nil model.current_mood
+ assert model.save
+ assert_nil model.reload.current_mood
+ end
end
diff --git a/activerecord/test/cases/adapters/postgresql/extension_migration_test.rb b/activerecord/test/cases/adapters/postgresql/extension_migration_test.rb
index 7b99fcdda0..06d427f464 100644
--- a/activerecord/test/cases/adapters/postgresql/extension_migration_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/extension_migration_test.rb
@@ -1,7 +1,7 @@
require "cases/helper"
class PostgresqlExtensionMigrationTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
class EnableHstore < ActiveRecord::Migration
def change
diff --git a/activerecord/test/cases/adapters/postgresql/hstore_test.rb b/activerecord/test/cases/adapters/postgresql/hstore_test.rb
index e6835031c3..ad9dd311a6 100644
--- a/activerecord/test/cases/adapters/postgresql/hstore_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/hstore_test.rb
@@ -27,6 +27,7 @@ if ActiveRecord::Base.connection.supports_extensions?
t.hstore 'settings'
end
end
+ Hstore.reset_column_information
@column = Hstore.columns_hash['tags']
@type = Hstore.type_for_attribute("tags")
end
diff --git a/activerecord/test/cases/adapters/postgresql/infinity_test.rb b/activerecord/test/cases/adapters/postgresql/infinity_test.rb
index 24199c69b8..d9d7832094 100644
--- a/activerecord/test/cases/adapters/postgresql/infinity_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/infinity_test.rb
@@ -24,6 +24,15 @@ class PostgresqlInfinityTest < ActiveRecord::TestCase
assert_equal Float::INFINITY, record.float
end
+ test "type casting string on a float column" do
+ record = PostgresqlInfinity.new(float: 'Infinity')
+ assert_equal Float::INFINITY, record.float
+ record = PostgresqlInfinity.new(float: '-Infinity')
+ assert_equal(-Float::INFINITY, record.float)
+ record = PostgresqlInfinity.new(float: 'NaN')
+ assert_send [record.float, :nan?]
+ end
+
test "update_all with infinity on a float column" do
record = PostgresqlInfinity.create!
PostgresqlInfinity.update_all(float: Float::INFINITY)
diff --git a/activerecord/test/cases/adapters/postgresql/json_test.rb b/activerecord/test/cases/adapters/postgresql/json_test.rb
index d8fded16b4..6878516aeb 100644
--- a/activerecord/test/cases/adapters/postgresql/json_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/json_test.rb
@@ -21,11 +21,11 @@ module PostgresqlJSONSharedTestCases
rescue ActiveRecord::StatementInvalid
skip "do not test on PostgreSQL without #{column_type} type."
end
- @column = JsonDataType.columns_hash['payload']
end
def teardown
@connection.drop_table :json_data_type, if_exists: true
+ JsonDataType.reset_column_information
end
def test_column
diff --git a/activerecord/test/cases/adapters/postgresql/numbers_test.rb b/activerecord/test/cases/adapters/postgresql/numbers_test.rb
index 093b81fe8d..d8e01e3b89 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::TestCase
assert_equal 123456.789, first.double
assert_equal(-::Float::INFINITY, second.single)
assert_equal ::Float::INFINITY, second.double
- assert_same ::Float::NAN, third.double
+ assert_send [third.double, :nan?]
end
def test_update
diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
index a934180a43..9a1b889d4d 100644
--- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
@@ -68,7 +68,7 @@ module ActiveRecord
def test_insert_sql_with_proprietary_returning_clause
with_example_table do
id = @connection.insert_sql("insert into ex (number) values(5150)", nil, "number")
- assert_equal "5150", id
+ assert_equal 5150, id
end
end
@@ -106,21 +106,21 @@ module ActiveRecord
connection = connection_without_insert_returning
id = connection.insert_sql("insert into postgresql_partitioned_table_parent (number) VALUES (1)")
expect = connection.query('select max(id) from postgresql_partitioned_table_parent').first.first
- assert_equal expect, id
+ assert_equal expect.to_i, id
end
def test_exec_insert_with_returning_disabled
connection = connection_without_insert_returning
result = connection.exec_insert("insert into postgresql_partitioned_table_parent (number) VALUES (1)", nil, [], 'id', 'postgresql_partitioned_table_parent_id_seq')
expect = connection.query('select max(id) from postgresql_partitioned_table_parent').first.first
- assert_equal expect, result.rows.first.first
+ assert_equal expect.to_i, result.rows.first.first
end
def test_exec_insert_with_returning_disabled_and_no_sequence_name_given
connection = connection_without_insert_returning
result = connection.exec_insert("insert into postgresql_partitioned_table_parent (number) VALUES (1)", nil, [], 'id')
expect = connection.query('select max(id) from postgresql_partitioned_table_parent').first.first
- assert_equal expect, result.rows.first.first
+ assert_equal expect.to_i, result.rows.first.first
end
def test_sql_for_insert_with_returning_disabled
@@ -238,7 +238,7 @@ module ActiveRecord
result = @connection.exec_query('SELECT number FROM ex WHERE number = 10')
assert_equal 1, result.rows.length
- assert_equal "10", result.rows.last.last
+ assert_equal 10, result.rows.last.last
end
end
@@ -274,7 +274,7 @@ module ActiveRecord
assert_equal 1, result.rows.length
assert_equal 2, result.columns.length
- assert_equal [['1', 'foo']], result.rows
+ assert_equal [[1, 'foo']], result.rows
end
end
@@ -288,7 +288,7 @@ module ActiveRecord
assert_equal 1, result.rows.length
assert_equal 2, result.columns.length
- assert_equal [['1', 'foo']], result.rows
+ assert_equal [[1, 'foo']], result.rows
end
end
@@ -304,7 +304,7 @@ module ActiveRecord
assert_equal 1, result.rows.length
assert_equal 2, result.columns.length
- assert_equal [['1', 'foo']], result.rows
+ assert_equal [[1, 'foo']], result.rows
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/range_test.rb b/activerecord/test/cases/adapters/postgresql/range_test.rb
index b6b451ca5c..bbf96278b0 100644
--- a/activerecord/test/cases/adapters/postgresql/range_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/range_test.rb
@@ -7,7 +7,7 @@ if ActiveRecord::Base.connection.supports_ranges?
end
class PostgresqlRangeTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
include ConnectionHelper
def setup
diff --git a/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb b/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb
index 98291f1bbf..7200ed2771 100644
--- a/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb
@@ -2,13 +2,17 @@ require 'cases/helper'
require 'support/connection_helper'
class PostgreSQLReferentialIntegrityTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
include ConnectionHelper
+ IS_REFERENTIAL_INTEGRITY_SQL = lambda do |sql|
+ sql.match(/DISABLE TRIGGER ALL/) || sql.match(/ENABLE TRIGGER ALL/)
+ end
+
module MissingSuperuserPrivileges
def execute(sql)
- if sql.match(/DISABLE TRIGGER ALL/) || sql.match(/ENABLE TRIGGER ALL/)
+ if IS_REFERENTIAL_INTEGRITY_SQL.call(sql)
super "BROKEN;" rescue nil # put transaction in broken state
raise ActiveRecord::StatementInvalid, 'PG::InsufficientPrivilege'
else
@@ -17,6 +21,16 @@ class PostgreSQLReferentialIntegrityTest < ActiveRecord::TestCase
end
end
+ module ProgrammerMistake
+ def execute(sql)
+ if IS_REFERENTIAL_INTEGRITY_SQL.call(sql)
+ raise ArgumentError, 'something is not right.'
+ else
+ super
+ end
+ end
+ end
+
def setup
@connection = ActiveRecord::Base.connection
end
@@ -81,9 +95,17 @@ class PostgreSQLReferentialIntegrityTest < ActiveRecord::TestCase
end
end
+ def test_only_catch_active_record_errors_others_bubble_up
+ @connection.extend ProgrammerMistake
+
+ assert_raises ArgumentError do
+ @connection.disable_referential_integrity {}
+ end
+ end
+
private
def assert_transaction_is_not_broken
- assert_equal "1", @connection.select_value("SELECT 1")
+ assert_equal 1, @connection.select_value("SELECT 1")
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb b/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb
index 6937145439..359a45bbd1 100644
--- a/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb
@@ -4,7 +4,7 @@ class SchemaThing < ActiveRecord::Base
end
class SchemaAuthorizationTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
TABLE_NAME = 'schema_things'
COLUMNS = [
diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb
index 77ff6d01bc..f925dcad97 100644
--- a/activerecord/test/cases/adapters/postgresql/schema_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb
@@ -3,7 +3,7 @@ require 'models/default'
require 'support/schema_dumping_helper'
class SchemaTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
SCHEMA_NAME = 'test_schema'
SCHEMA2_NAME = 'test_schema2'
@@ -384,16 +384,16 @@ class SchemaTest < ActiveRecord::TestCase
def test_reset_pk_sequence
sequence_name = "#{SCHEMA_NAME}.#{UNMATCHED_SEQUENCE_NAME}"
@connection.execute "SELECT setval('#{sequence_name}', 123)"
- assert_equal "124", @connection.select_value("SELECT nextval('#{sequence_name}')")
+ assert_equal 124, @connection.select_value("SELECT nextval('#{sequence_name}')")
@connection.reset_pk_sequence!("#{SCHEMA_NAME}.#{UNMATCHED_PK_TABLE_NAME}")
- assert_equal "1", @connection.select_value("SELECT nextval('#{sequence_name}')")
+ assert_equal 1, @connection.select_value("SELECT nextval('#{sequence_name}')")
end
def test_set_pk_sequence
table_name = "#{SCHEMA_NAME}.#{PK_TABLE_NAME}"
_, sequence_name = @connection.pk_and_sequence_for table_name
@connection.set_pk_sequence! table_name, 123
- assert_equal "124", @connection.select_value("SELECT nextval('#{sequence_name}')")
+ assert_equal 124, @connection.select_value("SELECT nextval('#{sequence_name}')")
@connection.reset_pk_sequence! table_name
end
diff --git a/activerecord/test/cases/adapters/postgresql/serial_test.rb b/activerecord/test/cases/adapters/postgresql/serial_test.rb
new file mode 100644
index 0000000000..458a8dae6c
--- /dev/null
+++ b/activerecord/test/cases/adapters/postgresql/serial_test.rb
@@ -0,0 +1,60 @@
+require "cases/helper"
+require 'support/schema_dumping_helper'
+
+class PostgresqlSerialTest < ActiveRecord::TestCase
+ include SchemaDumpingHelper
+
+ class PostgresqlSerial < ActiveRecord::Base; end
+
+ setup do
+ @connection = ActiveRecord::Base.connection
+ @connection.create_table "postgresql_serials", force: true do |t|
+ t.serial :seq
+ end
+ end
+
+ teardown do
+ @connection.drop_table "postgresql_serials", if_exists: true
+ end
+
+ def test_serial_column
+ column = PostgresqlSerial.columns_hash["seq"]
+ assert_equal :integer, column.type
+ assert_equal "integer", column.sql_type
+ assert column.serial?
+ end
+
+ def test_schema_dump_with_shorthand
+ output = dump_table_schema "postgresql_serials"
+ assert_match %r{t\.serial\s+"seq"}, output
+ end
+end
+
+class PostgresqlBigSerialTest < ActiveRecord::TestCase
+ include SchemaDumpingHelper
+
+ class PostgresqlBigSerial < ActiveRecord::Base; end
+
+ setup do
+ @connection = ActiveRecord::Base.connection
+ @connection.create_table "postgresql_big_serials", force: true do |t|
+ t.bigserial :seq
+ end
+ end
+
+ teardown do
+ @connection.drop_table "postgresql_big_serials", if_exists: true
+ end
+
+ def test_bigserial_column
+ column = PostgresqlBigSerial.columns_hash["seq"]
+ assert_equal :integer, column.type
+ assert_equal "bigint", column.sql_type
+ assert column.serial?
+ end
+
+ def test_schema_dump_with_shorthand
+ output = dump_table_schema "postgresql_big_serials"
+ assert_match %r{t\.bigserial\s+"seq"}, output
+ end
+end
diff --git a/activerecord/test/cases/adapters/postgresql/timestamp_test.rb b/activerecord/test/cases/adapters/postgresql/timestamp_test.rb
index da14063e20..a639f98272 100644
--- a/activerecord/test/cases/adapters/postgresql/timestamp_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/timestamp_test.rb
@@ -5,7 +5,7 @@ require 'models/topic'
class PostgresqlTimestampTest < ActiveRecord::TestCase
class PostgresqlTimestampWithZone < ActiveRecord::Base; end
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
setup do
@connection = ActiveRecord::Base.connection
diff --git a/activerecord/test/cases/adapters/postgresql/uuid_test.rb b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
index 1219e197ab..e9379a1019 100644
--- a/activerecord/test/cases/adapters/postgresql/uuid_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
@@ -135,26 +135,6 @@ class PostgresqlUUIDTest < ActiveRecord::TestCase
end
end
-class PostgresqlLargeKeysTest < ActiveRecord::TestCase
- include PostgresqlUUIDHelper
- include SchemaDumpingHelper
-
- def setup
- connection.create_table('big_serials', id: :bigserial) do |t|
- t.string 'name'
- end
- end
-
- def test_omg
- schema = dump_table_schema "big_serials"
- assert_match "create_table \"big_serials\", id: :bigserial", schema
- end
-
- def teardown
- drop_table "big_serials"
- end
-end
-
class PostgresqlUUIDGenerationTest < ActiveRecord::TestCase
include PostgresqlUUIDHelper
include SchemaDumpingHelper
diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
index 5ca3c92027..27f4ba8eb6 100644
--- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
@@ -8,7 +8,7 @@ module ActiveRecord
class SQLite3AdapterTest < ActiveRecord::TestCase
include DdlHelper
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
class DualEncoding < ActiveRecord::Base
end
diff --git a/activerecord/test/cases/ar_schema_test.rb b/activerecord/test/cases/ar_schema_test.rb
index f4e8003bc3..9d5327bf35 100644
--- a/activerecord/test/cases/ar_schema_test.rb
+++ b/activerecord/test/cases/ar_schema_test.rb
@@ -3,7 +3,7 @@ require "cases/helper"
if ActiveRecord::Base.connection.supports_migrations?
class ActiveRecordSchemaTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
setup do
@original_verbose = ActiveRecord::Migration.verbose
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index 675bed9bfa..290b2a0d6b 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -532,9 +532,21 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_update_all_on_association_accessed_before_save
firm = Firm.new(name: 'Firm')
+ clients_proxy_id = firm.clients.object_id
firm.clients << Client.first
firm.save!
assert_equal firm.clients.count, firm.clients.update_all(description: 'Great!')
+ assert_not_equal clients_proxy_id, firm.clients.object_id
+ end
+
+ def test_update_all_on_association_accessed_before_save_with_explicit_foreign_key
+ # We can use the same cached proxy object because the id is available for the scope
+ firm = Firm.new(name: 'Firm', id: 100)
+ clients_proxy_id = firm.clients.object_id
+ firm.clients << Client.first
+ firm.save!
+ assert_equal firm.clients.count, firm.clients.update_all(description: 'Great!')
+ assert_equal clients_proxy_id, firm.clients.object_id
end
def test_belongs_to_sanity
diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb
index 7dc9266074..5c2e5e7b43 100644
--- a/activerecord/test/cases/associations/has_one_associations_test.rb
+++ b/activerecord/test/cases/associations/has_one_associations_test.rb
@@ -12,7 +12,7 @@ require 'models/image'
require 'models/post'
class HasOneAssociationsTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false unless supports_savepoints?
+ self.use_transactional_tests = false unless supports_savepoints?
fixtures :accounts, :companies, :developers, :projects, :developers_projects, :ships, :pirates
def setup
diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb
index 9918601623..213be50e67 100644
--- a/activerecord/test/cases/associations/join_model_test.rb
+++ b/activerecord/test/cases/associations/join_model_test.rb
@@ -17,7 +17,7 @@ require 'models/engine'
require 'models/car'
class AssociationsJoinModelTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false unless supports_savepoints?
+ self.use_transactional_tests = false unless supports_savepoints?
fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices, :items, :books,
# Reload edges table from fixtures as otherwise repeated test was failing
diff --git a/activerecord/test/cases/associations/required_test.rb b/activerecord/test/cases/associations/required_test.rb
index 8b765a2e0c..3e5494e897 100644
--- a/activerecord/test/cases/associations/required_test.rb
+++ b/activerecord/test/cases/associations/required_test.rb
@@ -1,7 +1,7 @@
require "cases/helper"
class RequiredAssociationsTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
class Parent < ActiveRecord::Base
end
diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb
index 859afc4553..8f0d7bd037 100644
--- a/activerecord/test/cases/autosave_association_test.rb
+++ b/activerecord/test/cases/autosave_association_test.rb
@@ -629,7 +629,7 @@ class TestDefaultAutosaveAssociationOnNewRecord < ActiveRecord::TestCase
end
class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
setup do
@pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?")
@@ -637,7 +637,7 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase
end
teardown do
- # We are running without transactional fixtures and need to cleanup.
+ # We are running without transactional tests and need to cleanup.
Bird.delete_all
Parrot.delete_all
@ship.delete
@@ -1009,7 +1009,7 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase
end
class TestAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase
- self.use_transactional_fixtures = false unless supports_savepoints?
+ self.use_transactional_tests = false unless supports_savepoints?
def setup
super
@@ -1145,7 +1145,7 @@ class TestAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase
end
class TestAutosaveAssociationOnAHasOneThroughAssociation < ActiveRecord::TestCase
- self.use_transactional_fixtures = false unless supports_savepoints?
+ self.use_transactional_tests = false unless supports_savepoints?
def setup
super
@@ -1166,7 +1166,7 @@ class TestAutosaveAssociationOnAHasOneThroughAssociation < ActiveRecord::TestCas
end
class TestAutosaveAssociationOnABelongsToAssociation < ActiveRecord::TestCase
- self.use_transactional_fixtures = false unless supports_savepoints?
+ self.use_transactional_tests = false unless supports_savepoints?
def setup
super
@@ -1414,7 +1414,7 @@ module AutosaveAssociationOnACollectionAssociationTests
end
class TestAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCase
- self.use_transactional_fixtures = false unless supports_savepoints?
+ self.use_transactional_tests = false unless supports_savepoints?
def setup
super
@@ -1430,7 +1430,7 @@ class TestAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCase
end
class TestAutosaveAssociationOnAHasAndBelongsToManyAssociation < ActiveRecord::TestCase
- self.use_transactional_fixtures = false unless supports_savepoints?
+ self.use_transactional_tests = false unless supports_savepoints?
def setup
super
@@ -1447,7 +1447,7 @@ class TestAutosaveAssociationOnAHasAndBelongsToManyAssociation < ActiveRecord::T
end
class TestAutosaveAssociationOnAHasAndBelongsToManyAssociationWithAcceptsNestedAttributes < ActiveRecord::TestCase
- self.use_transactional_fixtures = false unless supports_savepoints?
+ self.use_transactional_tests = false unless supports_savepoints?
def setup
super
@@ -1464,7 +1464,7 @@ class TestAutosaveAssociationOnAHasAndBelongsToManyAssociationWithAcceptsNestedA
end
class TestAutosaveAssociationValidationsOnAHasManyAssociation < ActiveRecord::TestCase
- self.use_transactional_fixtures = false unless supports_savepoints?
+ self.use_transactional_tests = false unless supports_savepoints?
def setup
super
@@ -1481,7 +1481,7 @@ class TestAutosaveAssociationValidationsOnAHasManyAssociation < ActiveRecord::Te
end
class TestAutosaveAssociationValidationsOnAHasOneAssociation < ActiveRecord::TestCase
- self.use_transactional_fixtures = false unless supports_savepoints?
+ self.use_transactional_tests = false unless supports_savepoints?
def setup
super
@@ -1504,7 +1504,7 @@ class TestAutosaveAssociationValidationsOnAHasOneAssociation < ActiveRecord::Tes
end
class TestAutosaveAssociationValidationsOnABelongsToAssociation < ActiveRecord::TestCase
- self.use_transactional_fixtures = false unless supports_savepoints?
+ self.use_transactional_tests = false unless supports_savepoints?
def setup
super
@@ -1525,7 +1525,7 @@ class TestAutosaveAssociationValidationsOnABelongsToAssociation < ActiveRecord::
end
class TestAutosaveAssociationValidationsOnAHABTMAssociation < ActiveRecord::TestCase
- self.use_transactional_fixtures = false unless supports_savepoints?
+ self.use_transactional_tests = false unless supports_savepoints?
def setup
super
@@ -1548,7 +1548,7 @@ class TestAutosaveAssociationValidationsOnAHABTMAssociation < ActiveRecord::Test
end
class TestAutosaveAssociationValidationMethodsGeneration < ActiveRecord::TestCase
- self.use_transactional_fixtures = false unless supports_savepoints?
+ self.use_transactional_tests = false unless supports_savepoints?
def setup
super
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 993350ebd6..4306738670 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
require "cases/helper"
require 'active_support/concurrency/latch'
@@ -1008,54 +1009,61 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_switching_between_table_name
+ k = Class.new(Joke)
+
assert_difference("GoodJoke.count") do
- Joke.table_name = "cold_jokes"
- Joke.create
+ k.table_name = "cold_jokes"
+ k.create
- Joke.table_name = "funny_jokes"
- Joke.create
+ k.table_name = "funny_jokes"
+ k.create
end
end
def test_clear_cash_when_setting_table_name
- Joke.table_name = "cold_jokes"
- before_columns = Joke.columns
- before_seq = Joke.sequence_name
+ original_table_name = Joke.table_name
Joke.table_name = "funny_jokes"
+ before_columns = Joke.columns
+ before_seq = Joke.sequence_name
+
+ Joke.table_name = "cold_jokes"
after_columns = Joke.columns
- after_seq = Joke.sequence_name
+ after_seq = Joke.sequence_name
assert_not_equal before_columns, after_columns
assert_not_equal before_seq, after_seq unless before_seq.nil? && after_seq.nil?
+ ensure
+ Joke.table_name = original_table_name
end
def test_dont_clear_sequence_name_when_setting_explicitly
- Joke.sequence_name = "black_jokes_seq"
- Joke.table_name = "cold_jokes"
- before_seq = Joke.sequence_name
+ k = Class.new(Joke)
+ k.sequence_name = "black_jokes_seq"
+ k.table_name = "cold_jokes"
+ before_seq = k.sequence_name
- Joke.table_name = "funny_jokes"
- after_seq = Joke.sequence_name
+ k.table_name = "funny_jokes"
+ after_seq = k.sequence_name
assert_equal before_seq, after_seq unless before_seq.nil? && after_seq.nil?
- ensure
- Joke.reset_sequence_name
end
def test_dont_clear_inheritance_column_when_setting_explicitly
- Joke.inheritance_column = "my_type"
- before_inherit = Joke.inheritance_column
+ k = Class.new(Joke)
+ k.inheritance_column = "my_type"
+ before_inherit = k.inheritance_column
- Joke.reset_column_information
- after_inherit = Joke.inheritance_column
+ k.reset_column_information
+ after_inherit = k.inheritance_column
assert_equal before_inherit, after_inherit unless before_inherit.blank? && after_inherit.blank?
end
def test_set_table_name_symbol_converted_to_string
- Joke.table_name = :cold_jokes
- assert_equal 'cold_jokes', Joke.table_name
+ k = Class.new(Joke)
+ k.table_name = :cold_jokes
+ assert_equal 'cold_jokes', k.table_name
end
def test_quoted_table_name_after_set_table_name
diff --git a/activerecord/test/cases/batches_test.rb b/activerecord/test/cases/batches_test.rb
index 9e428098e4..0791dde1f2 100644
--- a/activerecord/test/cases/batches_test.rb
+++ b/activerecord/test/cases/batches_test.rb
@@ -190,8 +190,9 @@ class EachTest < ActiveRecord::TestCase
def test_find_in_batches_should_use_any_column_as_primary_key_when_start_is_not_specified
assert_queries(Subscriber.count + 1) do
- Subscriber.find_each(:batch_size => 1) do |subscriber|
- assert_kind_of Subscriber, subscriber
+ Subscriber.find_in_batches(batch_size: 1) do |batch|
+ assert_kind_of Array, batch
+ assert_kind_of Subscriber, batch.first
end
end
end
diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb
index f0393aa6b1..8fc996ee74 100644
--- a/activerecord/test/cases/calculations_test.rb
+++ b/activerecord/test/cases/calculations_test.rb
@@ -11,6 +11,10 @@ require 'models/minivan'
require 'models/speedometer'
require 'models/ship_part'
require 'models/treasure'
+require 'models/developer'
+require 'models/comment'
+require 'models/rating'
+require 'models/post'
class NumericData < ActiveRecord::Base
self.table_name = 'numeric_data'
@@ -636,4 +640,11 @@ class CalculationsTest < ActiveRecord::TestCase
Client.update_all(client_of: nil)
assert_equal({ nil => Client.count }, Client.group(:firm).count)
end
+
+ def test_should_reference_correct_aliases_while_joining_tables_of_has_many_through_association
+ assert_nothing_raised ActiveRecord::StatementInvalid do
+ developer = Developer.create!(name: 'developer')
+ developer.ratings.includes(comment: :post).where(posts: { id: 1 }).count
+ end
+ end
end
diff --git a/activerecord/test/cases/date_time_precision_test.rb b/activerecord/test/cases/date_time_precision_test.rb
index 6a4e64b22c..698f1b852e 100644
--- a/activerecord/test/cases/date_time_precision_test.rb
+++ b/activerecord/test/cases/date_time_precision_test.rb
@@ -4,7 +4,7 @@ require 'support/schema_dumping_helper'
if ActiveRecord::Base.connection.supports_datetime_with_precision?
class DateTimePrecisionTest < ActiveRecord::TestCase
include SchemaDumpingHelper
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
class Foo < ActiveRecord::Base; end
diff --git a/activerecord/test/cases/defaults_test.rb b/activerecord/test/cases/defaults_test.rb
index b9db0d0123..67fddebf45 100644
--- a/activerecord/test/cases/defaults_test.rb
+++ b/activerecord/test/cases/defaults_test.rb
@@ -90,14 +90,14 @@ end
if current_adapter?(:MysqlAdapter, :Mysql2Adapter)
class DefaultsTestWithoutTransactionalFixtures < ActiveRecord::TestCase
# ActiveRecord::Base#create! (and #save and other related methods) will
- # open a new transaction. When in transactional fixtures mode, this will
+ # open a new transaction. When in transactional tests mode, this will
# cause Active Record to create a new savepoint. However, since MySQL doesn't
# support DDL transactions, creating a table will result in any created
# savepoints to be automatically released. This in turn causes the savepoint
# release code in AbstractAdapter#transaction to fail.
#
- # We don't want that to happen, so we disable transactional fixtures here.
- self.use_transactional_fixtures = false
+ # We don't want that to happen, so we disable transactional tests here.
+ self.use_transactional_tests = false
def using_strict(strict)
connection = ActiveRecord::Base.remove_connection
diff --git a/activerecord/test/cases/disconnected_test.rb b/activerecord/test/cases/disconnected_test.rb
index 94447addc1..55f0e51717 100644
--- a/activerecord/test/cases/disconnected_test.rb
+++ b/activerecord/test/cases/disconnected_test.rb
@@ -4,7 +4,7 @@ class TestRecord < ActiveRecord::Base
end
class TestDisconnectedAdapter < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
def setup
@connection = ActiveRecord::Base.connection
diff --git a/activerecord/test/cases/enum_test.rb b/activerecord/test/cases/enum_test.rb
index 3b7bbcf47a..eea184e530 100644
--- a/activerecord/test/cases/enum_test.rb
+++ b/activerecord/test/cases/enum_test.rb
@@ -341,4 +341,18 @@ class EnumTest < ActiveRecord::TestCase
book2.status = :uploaded
assert_equal ['drafted', 'uploaded'], book2.status_change
end
+
+ test "declare multiple enums at a time" do
+ klass = Class.new(ActiveRecord::Base) do
+ self.table_name = "books"
+ enum status: [:proposed, :written, :published],
+ nullable_status: [:single, :married]
+ end
+
+ book1 = klass.proposed.create!
+ assert book1.proposed?
+
+ book2 = klass.single.create!
+ assert book2.single?
+ end
end
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index 39308866ee..4b819a82e8 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -947,7 +947,6 @@ class FinderTest < ActiveRecord::TestCase
end
end
- # http://dev.rubyonrails.org/ticket/6778
def test_find_ignores_previously_inserted_record
Post.create!(:title => 'test', :body => 'it out')
assert_equal [], Post.where(id: nil)
diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb
index d1add21219..f8acdcb51e 100644
--- a/activerecord/test/cases/fixtures_test.rb
+++ b/activerecord/test/cases/fixtures_test.rb
@@ -28,7 +28,7 @@ require 'tempfile'
class FixturesTest < ActiveRecord::TestCase
self.use_instantiated_fixtures = true
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
# other_topics fixture should not be included here
fixtures :topics, :developers, :accounts, :tasks, :categories, :funny_jokes, :binaries, :traffic_lights
@@ -419,7 +419,7 @@ end
class TransactionalFixturesTest < ActiveRecord::TestCase
self.use_instantiated_fixtures = true
- self.use_transactional_fixtures = true
+ self.use_transactional_tests = true
fixtures :topics
@@ -511,7 +511,7 @@ class CheckSetTableNameFixturesTest < ActiveRecord::TestCase
fixtures :funny_jokes
# Set to false to blow away fixtures cache and ensure our fixtures are loaded
# and thus takes into account our set_fixture_class
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
def test_table_method
assert_kind_of Joke, funny_jokes(:a_joke)
@@ -523,7 +523,7 @@ class FixtureNameIsNotTableNameFixturesTest < ActiveRecord::TestCase
fixtures :items
# Set to false to blow away fixtures cache and ensure our fixtures are loaded
# and thus takes into account our set_fixture_class
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
def test_named_accessor
assert_kind_of Book, items(:dvd)
@@ -535,7 +535,7 @@ class FixtureNameIsNotTableNameMultipleFixturesTest < ActiveRecord::TestCase
fixtures :items, :funny_jokes
# Set to false to blow away fixtures cache and ensure our fixtures are loaded
# and thus takes into account our set_fixture_class
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
def test_named_accessor_of_differently_named_fixture
assert_kind_of Book, items(:dvd)
@@ -549,7 +549,7 @@ end
class CustomConnectionFixturesTest < ActiveRecord::TestCase
set_fixture_class :courses => Course
fixtures :courses
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
def test_leaky_destroy
assert_nothing_raised { courses(:ruby) }
@@ -564,7 +564,7 @@ end
class TransactionalFixturesOnCustomConnectionTest < ActiveRecord::TestCase
set_fixture_class :courses => Course
fixtures :courses
- self.use_transactional_fixtures = true
+ self.use_transactional_tests = true
def test_leaky_destroy
assert_nothing_raised { courses(:ruby) }
@@ -580,7 +580,7 @@ class InvalidTableNameFixturesTest < ActiveRecord::TestCase
fixtures :funny_jokes
# Set to false to blow away fixtures cache and ensure our fixtures are loaded
# and thus takes into account our lack of set_fixture_class
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
def test_raises_error
assert_raise ActiveRecord::FixtureClassNotFound do
@@ -594,7 +594,7 @@ class CheckEscapedYamlFixturesTest < ActiveRecord::TestCase
fixtures :funny_jokes
# Set to false to blow away fixtures cache and ensure our fixtures are loaded
# and thus takes into account our set_fixture_class
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
def test_proper_escaped_fixture
assert_equal "The \\n Aristocrats\nAte the candy\n", funny_jokes(:another_joke).name
@@ -664,7 +664,7 @@ class LoadAllFixturesWithPathnameTest < ActiveRecord::TestCase
end
class FasterFixturesTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
fixtures :categories, :authors
def load_extra_fixture(name)
diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb
index f2ba28a32f..12c793c408 100644
--- a/activerecord/test/cases/helper.rb
+++ b/activerecord/test/cases/helper.rb
@@ -143,7 +143,7 @@ class ActiveSupport::TestCase
self.fixture_path = FIXTURES_ROOT
self.use_instantiated_fixtures = false
- self.use_transactional_fixtures = true
+ self.use_transactional_tests = true
def create_fixtures(*fixture_set_names, &block)
ActiveRecord::FixtureSet.create_fixtures(ActiveSupport::TestCase.fixture_path, fixture_set_names, fixture_class_names, &block)
@@ -203,8 +203,3 @@ module InTimeZone
end
require 'mocha/setup' # FIXME: stop using mocha
-
-# FIXME: we have tests that depend on run order, we should fix that and
-# remove this method call.
-require 'active_support/test_case'
-ActiveSupport::TestCase.test_order = :sorted
diff --git a/activerecord/test/cases/hot_compatibility_test.rb b/activerecord/test/cases/hot_compatibility_test.rb
index b4617cf6f9..5ba9a1029a 100644
--- a/activerecord/test/cases/hot_compatibility_test.rb
+++ b/activerecord/test/cases/hot_compatibility_test.rb
@@ -1,7 +1,7 @@
require 'cases/helper'
class HotCompatibilityTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
setup do
@klass = Class.new(ActiveRecord::Base) do
diff --git a/activerecord/test/cases/invalid_connection_test.rb b/activerecord/test/cases/invalid_connection_test.rb
index 8416c81f45..6523fc29fd 100644
--- a/activerecord/test/cases/invalid_connection_test.rb
+++ b/activerecord/test/cases/invalid_connection_test.rb
@@ -1,7 +1,7 @@
require "cases/helper"
class TestAdapterWithInvalidConnection < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
class Bird < ActiveRecord::Base
end
diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb
index 848174df06..9e4998a946 100644
--- a/activerecord/test/cases/locking_test.rb
+++ b/activerecord/test/cases/locking_test.rb
@@ -285,10 +285,10 @@ end
class OptimisticLockingWithSchemaChangeTest < ActiveRecord::TestCase
fixtures :people, :legacy_things, :references
- # need to disable transactional fixtures, because otherwise the sqlite3
+ # need to disable transactional tests, because otherwise the sqlite3
# adapter (at least) chokes when we try and change the schema in the middle
# of a test (see test_increment_counter_*).
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
{ :lock_version => Person, :custom_lock_version => LegacyThing }.each do |name, model|
define_method("test_increment_counter_updates_#{name}") do
@@ -365,7 +365,7 @@ end
# (See exec vs. async_exec in the PostgreSQL adapter.)
unless in_memory_db?
class PessimisticLockingTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
fixtures :people, :readers
def setup
diff --git a/activerecord/test/cases/migration/change_schema_test.rb b/activerecord/test/cases/migration/change_schema_test.rb
index 30c91dfdcb..46a62c272f 100644
--- a/activerecord/test/cases/migration/change_schema_test.rb
+++ b/activerecord/test/cases/migration/change_schema_test.rb
@@ -426,7 +426,7 @@ module ActiveRecord
if ActiveRecord::Base.connection.supports_foreign_keys?
class ChangeSchemaWithDependentObjectsTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
setup do
@connection = ActiveRecord::Base.connection
diff --git a/activerecord/test/cases/migration/column_attributes_test.rb b/activerecord/test/cases/migration/column_attributes_test.rb
index 763aa88f72..8d8e661aa5 100644
--- a/activerecord/test/cases/migration/column_attributes_test.rb
+++ b/activerecord/test/cases/migration/column_attributes_test.rb
@@ -5,7 +5,7 @@ module ActiveRecord
class ColumnAttributesTest < ActiveRecord::TestCase
include ActiveRecord::Migration::TestHelper
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
def test_add_column_newline_default
string = "foo\nbar"
diff --git a/activerecord/test/cases/migration/columns_test.rb b/activerecord/test/cases/migration/columns_test.rb
index e5ccfe0f91..5fc7702dfa 100644
--- a/activerecord/test/cases/migration/columns_test.rb
+++ b/activerecord/test/cases/migration/columns_test.rb
@@ -5,7 +5,7 @@ module ActiveRecord
class ColumnsTest < ActiveRecord::TestCase
include ActiveRecord::Migration::TestHelper
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
# FIXME: this is more of an integration test with AR::Base and the
# schema modifications. Maybe we should move this?
diff --git a/activerecord/test/cases/migration/logger_test.rb b/activerecord/test/cases/migration/logger_test.rb
index 319d3e1af3..bf6e684887 100644
--- a/activerecord/test/cases/migration/logger_test.rb
+++ b/activerecord/test/cases/migration/logger_test.rb
@@ -4,7 +4,7 @@ module ActiveRecord
class Migration
class LoggerTest < ActiveRecord::TestCase
# MySQL can't roll back ddl changes
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
Migration = Struct.new(:name, :version) do
def disable_ddl_transaction; false end
diff --git a/activerecord/test/cases/migration/references_statements_test.rb b/activerecord/test/cases/migration/references_statements_test.rb
index 988bd9c89f..f613fd66c3 100644
--- a/activerecord/test/cases/migration/references_statements_test.rb
+++ b/activerecord/test/cases/migration/references_statements_test.rb
@@ -5,7 +5,7 @@ module ActiveRecord
class ReferencesStatementsTest < ActiveRecord::TestCase
include ActiveRecord::Migration::TestHelper
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
def setup
super
diff --git a/activerecord/test/cases/migration/rename_table_test.rb b/activerecord/test/cases/migration/rename_table_test.rb
index 3eef308428..6d742d3f2f 100644
--- a/activerecord/test/cases/migration/rename_table_test.rb
+++ b/activerecord/test/cases/migration/rename_table_test.rb
@@ -5,7 +5,7 @@ module ActiveRecord
class RenameTableTest < ActiveRecord::TestCase
include ActiveRecord::Migration::TestHelper
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
def setup
super
diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
index 3b73685a2c..b2f209fe97 100644
--- a/activerecord/test/cases/migration_test.rb
+++ b/activerecord/test/cases/migration_test.rb
@@ -24,7 +24,7 @@ class Reminder < ActiveRecord::Base; end
class Thing < ActiveRecord::Base; end
class MigrationTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
fixtures :people
diff --git a/activerecord/test/cases/migrator_test.rb b/activerecord/test/cases/migrator_test.rb
index 1760314099..2ff6938e7b 100644
--- a/activerecord/test/cases/migrator_test.rb
+++ b/activerecord/test/cases/migrator_test.rb
@@ -2,7 +2,7 @@ require "cases/helper"
require "cases/migration/helper"
class MigratorTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
# Use this class to sense if migrations have gone
# up or down.
diff --git a/activerecord/test/cases/mixin_test.rb b/activerecord/test/cases/mixin_test.rb
index 7ddb2bfee1..7ebdcac711 100644
--- a/activerecord/test/cases/mixin_test.rb
+++ b/activerecord/test/cases/mixin_test.rb
@@ -61,8 +61,6 @@ class TouchTest < ActiveRecord::TestCase
# Make sure Mixin.record_timestamps gets reset, even if this test fails,
# so that other tests do not fail because Mixin.record_timestamps == false
- rescue Exception => e
- raise e
ensure
Mixin.record_timestamps = true
end
diff --git a/activerecord/test/cases/modules_test.rb b/activerecord/test/cases/modules_test.rb
index 6f65bf80eb..7f31325f47 100644
--- a/activerecord/test/cases/modules_test.rb
+++ b/activerecord/test/cases/modules_test.rb
@@ -68,8 +68,7 @@ class ModulesTest < ActiveRecord::TestCase
end
end
- # need to add an eager loading condition to force the eager loading model into
- # the old join model, to test that. See http://dev.rubyonrails.org/ticket/9640
+ # An eager loading condition to force the eager loading model into the old join model.
def test_eager_loading_in_modules
clients = []
diff --git a/activerecord/test/cases/multiple_db_test.rb b/activerecord/test/cases/multiple_db_test.rb
index f9bc266e84..39cdcf5403 100644
--- a/activerecord/test/cases/multiple_db_test.rb
+++ b/activerecord/test/cases/multiple_db_test.rb
@@ -4,7 +4,7 @@ require 'models/bird'
require 'models/course'
class MultipleDbTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
def setup
@courses = create_fixtures("courses") { Course.retrieve_connection }
diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb
index c5f6589c22..6b4addd52f 100644
--- a/activerecord/test/cases/nested_attributes_test.rb
+++ b/activerecord/test/cases/nested_attributes_test.rb
@@ -943,7 +943,7 @@ class TestNestedAttributesWithNonStandardPrimaryKeys < ActiveRecord::TestCase
end
class TestHasOneAutosaveAssociationWhichItselfHasAutosaveAssociations < ActiveRecord::TestCase
- self.use_transactional_fixtures = false unless supports_savepoints?
+ self.use_transactional_tests = false unless supports_savepoints?
def setup
@pirate = Pirate.create!(:catchphrase => "My baby takes tha mornin' train!")
@@ -983,7 +983,7 @@ class TestHasOneAutosaveAssociationWhichItselfHasAutosaveAssociations < ActiveRe
end
class TestHasManyAutosaveAssociationWhichItselfHasAutosaveAssociations < ActiveRecord::TestCase
- self.use_transactional_fixtures = false unless supports_savepoints?
+ self.use_transactional_tests = false unless supports_savepoints?
def setup
@ship = Ship.create!(:name => "The good ship Dollypop")
diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb
index 2803ad2de0..2370077eb0 100644
--- a/activerecord/test/cases/persistence_test.rb
+++ b/activerecord/test/cases/persistence_test.rb
@@ -366,6 +366,12 @@ class PersistenceTest < ActiveRecord::TestCase
end
end
+ def test_update_does_not_run_sql_if_record_has_not_changed
+ topic = Topic.create(title: 'Another New Topic')
+ assert_queries(0) { topic.update(title: 'Another New Topic') }
+ assert_queries(0) { topic.update_attributes(title: 'Another New Topic') }
+ end
+
def test_delete
topic = Topic.find(1)
assert_equal topic, topic.delete, 'topic.delete did not return self'
@@ -892,7 +898,7 @@ class PersistenceTest < ActiveRecord::TestCase
end
class SaveTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
def test_save_touch_false
widget = Class.new(ActiveRecord::Base) do
diff --git a/activerecord/test/cases/pooled_connections_test.rb b/activerecord/test/cases/pooled_connections_test.rb
index 287a3f33ea..daa3271777 100644
--- a/activerecord/test/cases/pooled_connections_test.rb
+++ b/activerecord/test/cases/pooled_connections_test.rb
@@ -3,7 +3,7 @@ require "models/project"
require "timeout"
class PooledConnectionsTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
def setup
@per_test_teardown = []
diff --git a/activerecord/test/cases/primary_keys_test.rb b/activerecord/test/cases/primary_keys_test.rb
index 1ea1ef5e12..3664a2af70 100644
--- a/activerecord/test/cases/primary_keys_test.rb
+++ b/activerecord/test/cases/primary_keys_test.rb
@@ -178,7 +178,7 @@ class PrimaryKeysTest < ActiveRecord::TestCase
end
class PrimaryKeyWithNoConnectionTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
unless in_memory_db?
def test_set_primary_key_with_no_connection
@@ -199,7 +199,7 @@ end
class PrimaryKeyAnyTypeTest < ActiveRecord::TestCase
include SchemaDumpingHelper
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
class Barcode < ActiveRecord::Base
end
@@ -229,7 +229,7 @@ end
if current_adapter?(:MysqlAdapter, :Mysql2Adapter)
class PrimaryKeyWithAnsiQuotesTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
def test_primary_key_method_with_ansi_quotes
con = ActiveRecord::Base.connection
@@ -245,7 +245,7 @@ if current_adapter?(:PostgreSQLAdapter, :MysqlAdapter, :Mysql2Adapter)
class PrimaryKeyBigSerialTest < ActiveRecord::TestCase
include SchemaDumpingHelper
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
class Widget < ActiveRecord::Base
end
diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb
index 744f9edc47..2f0b5df286 100644
--- a/activerecord/test/cases/query_cache_test.rb
+++ b/activerecord/test/cases/query_cache_test.rb
@@ -184,7 +184,7 @@ class QueryCacheTest < ActiveRecord::TestCase
# Oracle adapter returns count() as Fixnum or Float
if current_adapter?(:OracleAdapter)
assert_kind_of Numeric, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
- elsif current_adapter?(:SQLite3Adapter, :Mysql2Adapter)
+ elsif current_adapter?(:SQLite3Adapter, :Mysql2Adapter, :PostgreSQLAdapter)
# Future versions of the sqlite3 adapter will return numeric
assert_instance_of Fixnum,
Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb
index 67e9bef808..7b47c80331 100644
--- a/activerecord/test/cases/reflection_test.rb
+++ b/activerecord/test/cases/reflection_test.rb
@@ -23,6 +23,7 @@ require 'models/chef'
require 'models/department'
require 'models/cake_designer'
require 'models/drink_designer'
+require 'models/recipe'
class ReflectionTest < ActiveRecord::TestCase
include ActiveRecord::Reflection
@@ -277,6 +278,22 @@ class ReflectionTest < ActiveRecord::TestCase
assert_equal 2, @hotel.chefs.size
end
+ def test_scope_chain_of_polymorphic_association_does_not_leak_into_other_hmt_associations
+ hotel = Hotel.create!
+ department = hotel.departments.create!
+ drink = department.chefs.create!(employable: DrinkDesigner.create!)
+ Recipe.create!(chef_id: drink.id, hotel_id: hotel.id)
+
+ expected_sql = capture_sql { hotel.recipes.to_a }
+
+ Hotel.reflect_on_association(:recipes).clear_association_scope_cache
+ hotel.reload
+ hotel.drink_designers.to_a
+ loaded_sql = capture_sql { hotel.recipes.to_a }
+
+ assert_equal expected_sql, loaded_sql
+ end
+
def test_nested?
assert !Author.reflect_on_association(:comments).nested?
assert Author.reflect_on_association(:tags).nested?
diff --git a/activerecord/test/cases/relation/record_fetch_warning_test.rb b/activerecord/test/cases/relation/record_fetch_warning_test.rb
new file mode 100644
index 0000000000..62f0a7cc49
--- /dev/null
+++ b/activerecord/test/cases/relation/record_fetch_warning_test.rb
@@ -0,0 +1,28 @@
+require 'cases/helper'
+require 'models/post'
+
+module ActiveRecord
+ class RecordFetchWarningTest < ActiveRecord::TestCase
+ fixtures :posts
+
+ def test_warn_on_records_fetched_greater_than
+ original_logger = ActiveRecord::Base.logger
+ orginal_warn_on_records_fetched_greater_than = ActiveRecord::Base.warn_on_records_fetched_greater_than
+
+ log = StringIO.new
+ ActiveRecord::Base.logger = ActiveSupport::Logger.new(log)
+ ActiveRecord::Base.logger.level = Logger::WARN
+
+ require 'active_record/relation/record_fetch_warning'
+
+ ActiveRecord::Base.warn_on_records_fetched_greater_than = 1
+
+ Post.all.to_a
+
+ assert_match(/Query fetched/, log.string)
+ ensure
+ ActiveRecord::Base.logger = original_logger
+ ActiveRecord::Base.warn_on_records_fetched_greater_than = orginal_warn_on_records_fetched_greater_than
+ end
+ end
+end
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index 513f65f707..6c099719c0 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -3,7 +3,7 @@ require 'support/schema_dumping_helper'
class SchemaDumperTest < ActiveRecord::TestCase
include SchemaDumpingHelper
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
setup do
ActiveRecord::SchemaMigration.create_table
@@ -248,6 +248,11 @@ class SchemaDumperTest < ActiveRecord::TestCase
assert_match %r{t\.integer\s+"bigint_default",\s+limit: 8,\s+default: 0}, output
end
+ def test_schema_dump_includes_limit_on_array_type
+ output = standard_dump
+ assert_match %r{t\.integer\s+"big_int_data_points\",\s+limit: 8,\s+array: true}, output
+ end
+
if ActiveRecord::Base.connection.supports_extensions?
def test_schema_dump_includes_extensions
connection = ActiveRecord::Base.connection
diff --git a/activerecord/test/cases/serialized_attribute_test.rb b/activerecord/test/cases/serialized_attribute_test.rb
index e29f7462c8..7c92453ee3 100644
--- a/activerecord/test/cases/serialized_attribute_test.rb
+++ b/activerecord/test/cases/serialized_attribute_test.rb
@@ -264,4 +264,14 @@ class SerializedAttributeTest < ActiveRecord::TestCase
Topic.serialize(:content, Regexp)
end
end
+
+ def test_newly_emptied_serialized_hash_is_changed
+ Topic.serialize(:content, Hash)
+ topic = Topic.create(content: { "things" => "stuff" })
+ topic.content.delete("things")
+ topic.save!
+ topic.reload
+
+ assert_equal({}, topic.content)
+ end
end
diff --git a/activerecord/test/cases/tasks/database_tasks_test.rb b/activerecord/test/cases/tasks/database_tasks_test.rb
index 2fa033ed45..38164b2228 100644
--- a/activerecord/test/cases/tasks/database_tasks_test.rb
+++ b/activerecord/test/cases/tasks/database_tasks_test.rb
@@ -377,4 +377,20 @@ module ActiveRecord
ActiveRecord::Tasks::DatabaseTasks.check_schema_file("awesome-file.sql")
end
end
+
+ class DatabaseTasksCheckSchemaFileDefaultsTest < ActiveRecord::TestCase
+ def test_check_schema_file_defaults
+ ActiveRecord::Tasks::DatabaseTasks.stubs(:db_dir).returns('/tmp')
+ assert_equal '/tmp/schema.rb', ActiveRecord::Tasks::DatabaseTasks.schema_file
+ end
+ end
+
+ class DatabaseTasksCheckSchemaFileSpecifiedFormatsTest < ActiveRecord::TestCase
+ {ruby: 'schema.rb', sql: 'structure.sql'}.each_pair do |fmt, filename|
+ define_method("test_check_schema_file_for_#{fmt}_format") do
+ ActiveRecord::Tasks::DatabaseTasks.stubs(:db_dir).returns('/tmp')
+ assert_equal "/tmp/#{filename}", ActiveRecord::Tasks::DatabaseTasks.schema_file(fmt)
+ end
+ end
+ end
end
diff --git a/activerecord/test/cases/tasks/postgresql_rake_test.rb b/activerecord/test/cases/tasks/postgresql_rake_test.rb
index 0d574d071c..084302cde5 100644
--- a/activerecord/test/cases/tasks/postgresql_rake_test.rb
+++ b/activerecord/test/cases/tasks/postgresql_rake_test.rb
@@ -195,21 +195,54 @@ module ActiveRecord
'adapter' => 'postgresql',
'database' => 'my-app-db'
}
+ @filename = "awesome-file.sql"
ActiveRecord::Base.stubs(:connection).returns(@connection)
ActiveRecord::Base.stubs(:establish_connection).returns(true)
Kernel.stubs(:system)
+ File.stubs(:open)
end
def test_structure_dump
- filename = "awesome-file.sql"
- Kernel.expects(:system).with("pg_dump -i -s -x -O -f #{filename} my-app-db").returns(true)
- @connection.expects(:schema_search_path).returns("foo")
+ Kernel.expects(:system).with("pg_dump -i -s -x -O -f #{@filename} my-app-db").returns(true)
+
+ ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename)
+ end
+
+ def test_structure_dump_with_schema_search_path
+ @configuration['schema_search_path'] = 'foo,bar'
+
+ Kernel.expects(:system).with("pg_dump -i -s -x -O -f #{@filename} --schema=foo --schema=bar my-app-db").returns(true)
+
+ ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename)
+ end
+
+ def test_structure_dump_with_schema_search_path_and_dump_schemas_all
+ @configuration['schema_search_path'] = 'foo,bar'
+
+ Kernel.expects(:system).with("pg_dump -i -s -x -O -f #{@filename} my-app-db").returns(true)
+
+ with_dump_schemas(:all) do
+ ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename)
+ end
+ end
+
+ def test_structure_dump_with_dump_schemas_string
+ Kernel.expects(:system).with("pg_dump -i -s -x -O -f #{@filename} --schema=foo --schema=bar my-app-db").returns(true)
+
+ with_dump_schemas('foo,bar') do
+ ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename)
+ end
+ end
+
+ private
- ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, filename)
- assert File.exist?(filename)
+ def with_dump_schemas(value, &block)
+ old_dump_schemas = ActiveRecord::Base.dump_schemas
+ ActiveRecord::Base.dump_schemas = value
+ yield
ensure
- FileUtils.rm(filename)
+ ActiveRecord::Base.dump_schemas = old_dump_schemas
end
end
@@ -228,14 +261,14 @@ module ActiveRecord
def test_structure_load
filename = "awesome-file.sql"
- Kernel.expects(:system).with("psql -q -f #{filename} my-app-db")
+ Kernel.expects(:system).with("psql -X -q -f #{filename} my-app-db")
ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename)
end
def test_structure_load_accepts_path_with_spaces
filename = "awesome file.sql"
- Kernel.expects(:system).with("psql -q -f awesome\\ file.sql my-app-db")
+ Kernel.expects(:system).with("psql -X -q -f awesome\\ file.sql my-app-db")
ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename)
end
diff --git a/activerecord/test/cases/test_fixtures_test.rb b/activerecord/test/cases/test_fixtures_test.rb
new file mode 100644
index 0000000000..3f4baf8378
--- /dev/null
+++ b/activerecord/test/cases/test_fixtures_test.rb
@@ -0,0 +1,36 @@
+require 'cases/helper'
+
+class TestFixturesTest < ActiveRecord::TestCase
+ setup do
+ @klass = Class.new
+ @klass.send(:include, ActiveRecord::TestFixtures)
+ end
+
+ def test_deprecated_use_transactional_fixtures=
+ assert_deprecated 'use use_transactional_tests= instead' do
+ @klass.use_transactional_fixtures = true
+ end
+ end
+
+ def test_use_transactional_tests_prefers_use_transactional_fixtures
+ ActiveSupport::Deprecation.silence do
+ @klass.use_transactional_fixtures = false
+ end
+
+ assert_equal false, @klass.use_transactional_tests
+ end
+
+ def test_use_transactional_tests_defaults_to_true
+ ActiveSupport::Deprecation.silence do
+ @klass.use_transactional_fixtures = nil
+ end
+
+ assert_equal true, @klass.use_transactional_tests
+ end
+
+ def test_use_transactional_tests_can_be_overriden
+ @klass.use_transactional_tests = "foobar"
+
+ assert_equal "foobar", @klass.use_transactional_tests
+ end
+end
diff --git a/activerecord/test/cases/time_precision_test.rb b/activerecord/test/cases/time_precision_test.rb
index ff4e5ecec5..ff7a81fe60 100644
--- a/activerecord/test/cases/time_precision_test.rb
+++ b/activerecord/test/cases/time_precision_test.rb
@@ -4,7 +4,7 @@ require 'support/schema_dumping_helper'
if ActiveRecord::Base.connection.supports_datetime_with_precision?
class TimePrecisionTest < ActiveRecord::TestCase
include SchemaDumpingHelper
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
class Foo < ActiveRecord::Base; end
diff --git a/activerecord/test/cases/timestamp_test.rb b/activerecord/test/cases/timestamp_test.rb
index c0c62527df..7c89b4b9e8 100644
--- a/activerecord/test/cases/timestamp_test.rb
+++ b/activerecord/test/cases/timestamp_test.rb
@@ -450,7 +450,7 @@ end
class TimestampsWithoutTransactionTest < ActiveRecord::TestCase
include DdlHelper
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
class TimestampAttributePost < ActiveRecord::Base
attr_accessor :created_at, :updated_at
diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb
index e868022fed..f2229939c8 100644
--- a/activerecord/test/cases/transaction_callbacks_test.rb
+++ b/activerecord/test/cases/transaction_callbacks_test.rb
@@ -367,7 +367,7 @@ class TransactionCallbacksTest < ActiveRecord::TestCase
end
class CallbacksOnMultipleActionsTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
class TopicWithCallbacksOnMultipleActions < ActiveRecord::Base
self.table_name = :topics
@@ -376,6 +376,9 @@ class CallbacksOnMultipleActionsTest < ActiveRecord::TestCase
after_commit(on: [:create, :update]) { |record| record.history << :create_and_update }
after_commit(on: [:update, :destroy]) { |record| record.history << :update_and_destroy }
+ before_commit(if: :save_before_commit_history) { |record| record.history << :before_commit }
+ before_commit(if: :update_title) { |record| record.update(title: "before commit title") }
+
def clear_history
@history = []
end
@@ -383,6 +386,8 @@ class CallbacksOnMultipleActionsTest < ActiveRecord::TestCase
def history
@history ||= []
end
+
+ attr_accessor :save_before_commit_history, :update_title
end
def test_after_commit_on_multiple_actions
@@ -399,6 +404,23 @@ class CallbacksOnMultipleActionsTest < ActiveRecord::TestCase
topic.destroy
assert_equal [:update_and_destroy, :create_and_destroy], topic.history
end
+
+ def test_before_commit_actions
+ topic = TopicWithCallbacksOnMultipleActions.new
+ topic.save_before_commit_history = true
+ topic.save
+
+ assert_equal [:before_commit, :create_and_update, :create_and_destroy], topic.history
+ end
+
+ def test_before_commit_update_in_same_transaction
+ topic = TopicWithCallbacksOnMultipleActions.new
+ topic.update_title = true
+ topic.save
+
+ assert_equal "before commit title", topic.title
+ assert_equal "before commit title", topic.reload.title
+ end
end
diff --git a/activerecord/test/cases/transaction_isolation_test.rb b/activerecord/test/cases/transaction_isolation_test.rb
index f89c26532d..2f7d208ed2 100644
--- a/activerecord/test/cases/transaction_isolation_test.rb
+++ b/activerecord/test/cases/transaction_isolation_test.rb
@@ -2,7 +2,7 @@ require 'cases/helper'
unless ActiveRecord::Base.connection.supports_transaction_isolation?
class TransactionIsolationUnsupportedTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
class Tag < ActiveRecord::Base
end
@@ -17,7 +17,7 @@ end
if ActiveRecord::Base.connection.supports_transaction_isolation?
class TransactionIsolationTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
class Tag < ActiveRecord::Base
self.table_name = 'tags'
diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb
index 88e595c39f..2468a91969 100644
--- a/activerecord/test/cases/transactions_test.rb
+++ b/activerecord/test/cases/transactions_test.rb
@@ -9,7 +9,7 @@ require 'models/post'
require 'models/movie'
class TransactionTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
fixtures :topics, :developers, :authors, :posts
def setup
@@ -584,6 +584,24 @@ class TransactionTest < ActiveRecord::TestCase
assert_not topic.frozen?
end
+ def test_rollback_of_frozen_records
+ topic = Topic.create.freeze
+ Topic.transaction do
+ topic.destroy
+ raise ActiveRecord::Rollback
+ end
+ assert topic.frozen?, 'frozen'
+ end
+
+ def test_rollback_for_freshly_persisted_records
+ topic = Topic.create
+ Topic.transaction do
+ topic.destroy
+ raise ActiveRecord::Rollback
+ end
+ assert topic.persisted?, 'persisted'
+ end
+
def test_sqlite_add_column_in_transaction
return true unless current_adapter?(:SQLite3Adapter)
@@ -685,7 +703,7 @@ class TransactionTest < ActiveRecord::TestCase
end
class TransactionsWithTransactionalFixturesTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = true
+ self.use_transactional_tests = true
fixtures :topics
def test_automatic_savepoint_in_outer_transaction
diff --git a/activerecord/test/cases/unconnected_test.rb b/activerecord/test/cases/unconnected_test.rb
index afb893a52c..b210584644 100644
--- a/activerecord/test/cases/unconnected_test.rb
+++ b/activerecord/test/cases/unconnected_test.rb
@@ -4,7 +4,7 @@ class TestRecord < ActiveRecord::Base
end
class TestUnconnectedAdapter < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
def setup
@underlying = ActiveRecord::Base.connection
diff --git a/activerecord/test/cases/validations/length_validation_test.rb b/activerecord/test/cases/validations/length_validation_test.rb
index 952e1681a7..f95f8f0b8f 100644
--- a/activerecord/test/cases/validations/length_validation_test.rb
+++ b/activerecord/test/cases/validations/length_validation_test.rb
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
require "cases/helper"
require 'models/owner'
require 'models/pet'
@@ -5,49 +6,49 @@ require 'models/person'
class LengthValidationTest < ActiveRecord::TestCase
fixtures :owners
- repair_validations(Owner)
- def test_validates_size_of_association
- repair_validations Owner do
- assert_nothing_raised { Owner.validates_size_of :pets, :minimum => 1 }
- o = Owner.new('name' => 'nopets')
- assert !o.save
- assert o.errors[:pets].any?
- o.pets.build('name' => 'apet')
- assert o.valid?
+ setup do
+ @owner = Class.new(Owner) do
+ def self.name; 'Owner'; end
end
end
+
+ def test_validates_size_of_association
+ assert_nothing_raised { @owner.validates_size_of :pets, minimum: 1 }
+ o = @owner.new('name' => 'nopets')
+ assert !o.save
+ assert o.errors[:pets].any?
+ o.pets.build('name' => 'apet')
+ assert o.valid?
+ end
+
def test_validates_size_of_association_using_within
- repair_validations Owner do
- assert_nothing_raised { Owner.validates_size_of :pets, :within => 1..2 }
- o = Owner.new('name' => 'nopets')
- assert !o.save
- assert o.errors[:pets].any?
+ assert_nothing_raised { @owner.validates_size_of :pets, within: 1..2 }
+ o = @owner.new('name' => 'nopets')
+ assert !o.save
+ assert o.errors[:pets].any?
- o.pets.build('name' => 'apet')
- assert o.valid?
+ o.pets.build('name' => 'apet')
+ assert o.valid?
- 2.times { o.pets.build('name' => 'apet') }
- assert !o.save
- assert o.errors[:pets].any?
- end
+ 2.times { o.pets.build('name' => 'apet') }
+ assert !o.save
+ assert o.errors[:pets].any?
end
def test_validates_size_of_association_utf8
- repair_validations Owner do
- Owner.validates_size_of :pets, :minimum => 1
- o = Owner.new('name' => 'あいうえおかきくけこ')
- assert !o.save
- assert o.errors[:pets].any?
- o.pets.build('name' => 'あいうえおかきくけこ')
- assert o.valid?
- end
+ @owner.validates_size_of :pets, minimum: 1
+ o = @owner.new('name' => 'あいうえおかきくけこ')
+ assert !o.save
+ assert o.errors[:pets].any?
+ o.pets.build('name' => 'あいうえおかきくけこ')
+ assert o.valid?
end
def test_validates_size_of_respects_records_marked_for_destruction
- Owner.validates_size_of :pets, minimum: 1
- owner = Owner.new
+ @owner.validates_size_of :pets, minimum: 1
+ owner = @owner.new
assert_not owner.save
assert owner.errors[:pets].any?
pet = owner.pets.build
@@ -62,8 +63,8 @@ class LengthValidationTest < ActiveRecord::TestCase
end
def test_does_not_validate_length_of_if_parent_record_is_validate_false
- Owner.validates_length_of :name, minimum: 1
- owner = Owner.new
+ @owner.validates_length_of :name, minimum: 1
+ owner = @owner.new
owner.save!(validate: false)
assert owner.persisted?
diff --git a/activerecord/test/cases/yaml_serialization_test.rb b/activerecord/test/cases/yaml_serialization_test.rb
index bce59b4fcd..56909a8630 100644
--- a/activerecord/test/cases/yaml_serialization_test.rb
+++ b/activerecord/test/cases/yaml_serialization_test.rb
@@ -83,4 +83,39 @@ class YamlSerializationTest < ActiveRecord::TestCase
assert_equal 5, author.posts_count
assert_equal 5, dumped.posts_count
end
+
+ def test_a_yaml_version_is_provided_for_future_backwards_compat
+ coder = {}
+ Topic.first.encode_with(coder)
+
+ assert coder['active_record_yaml_version']
+ end
+
+ def test_deserializing_rails_41_yaml
+ topic = YAML.load(yaml_fixture("rails_4_1"))
+
+ assert topic.new_record?
+ assert_equal nil, topic.id
+ assert_equal "The First Topic", topic.title
+ assert_equal({ omg: :lol }, topic.content)
+ end
+
+ def test_deserializing_rails_4_2_0_yaml
+ topic = YAML.load(yaml_fixture("rails_4_2_0"))
+
+ assert_not topic.new_record?
+ assert_equal 1, topic.id
+ assert_equal "The First Topic", topic.title
+ assert_equal("Have a nice day", topic.content)
+ end
+
+ private
+
+ def yaml_fixture(file_name)
+ path = File.expand_path(
+ "../../support/yaml_compatibility_fixtures/#{file_name}.yml",
+ __FILE__
+ )
+ File.read(path)
+ end
end
diff --git a/activerecord/test/models/chef.rb b/activerecord/test/models/chef.rb
index 67a4e54f06..698a52e045 100644
--- a/activerecord/test/models/chef.rb
+++ b/activerecord/test/models/chef.rb
@@ -1,3 +1,4 @@
class Chef < ActiveRecord::Base
belongs_to :employable, polymorphic: true
+ has_many :recipes
end
diff --git a/activerecord/test/models/hotel.rb b/activerecord/test/models/hotel.rb
index b352cd22f3..491f8dfde3 100644
--- a/activerecord/test/models/hotel.rb
+++ b/activerecord/test/models/hotel.rb
@@ -3,4 +3,5 @@ class Hotel < ActiveRecord::Base
has_many :chefs, through: :departments
has_many :cake_designers, source_type: 'CakeDesigner', source: :employable, through: :chefs
has_many :drink_designers, source_type: 'DrinkDesigner', source: :employable, through: :chefs
+ has_many :recipes, through: :chefs
end
diff --git a/activerecord/test/models/recipe.rb b/activerecord/test/models/recipe.rb
new file mode 100644
index 0000000000..c387230603
--- /dev/null
+++ b/activerecord/test/models/recipe.rb
@@ -0,0 +1,3 @@
+class Recipe < ActiveRecord::Base
+ belongs_to :chef
+end
diff --git a/activerecord/test/schema/postgresql_specific_schema.rb b/activerecord/test/schema/postgresql_specific_schema.rb
index f84be0e7f4..008503bc24 100644
--- a/activerecord/test/schema/postgresql_specific_schema.rb
+++ b/activerecord/test/schema/postgresql_specific_schema.rb
@@ -93,4 +93,8 @@ _SQL
t.binary :binary, limit: 100_000
t.text :text, limit: 100_000
end
+
+ create_table :bigint_array, force: true do |t|
+ t.integer :big_int_data_points, limit: 8, array: true
+ end
end
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 5e5f7a798e..7b42f8a4a5 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -886,6 +886,10 @@ ActiveRecord::Schema.define do
t.string :employable_type
t.integer :department_id
end
+ create_table :recipes, force: true do |t|
+ t.integer :chef_id
+ t.integer :hotel_id
+ end
create_table :records, force: true do |t|
end
diff --git a/activerecord/test/support/yaml_compatibility_fixtures/rails_4_1.yml b/activerecord/test/support/yaml_compatibility_fixtures/rails_4_1.yml
new file mode 100644
index 0000000000..20b128db9c
--- /dev/null
+++ b/activerecord/test/support/yaml_compatibility_fixtures/rails_4_1.yml
@@ -0,0 +1,22 @@
+--- !ruby/object:Topic
+ attributes:
+ id:
+ title: The First Topic
+ author_name: David
+ author_email_address: david@loudthinking.com
+ written_on: 2003-07-16 14:28:11.223300000 Z
+ bonus_time: 2000-01-01 14:28:00.000000000 Z
+ last_read: 2004-04-15
+ content: |
+ ---
+ :omg: :lol
+ important:
+ approved: false
+ replies_count: 1
+ unique_replies_count: 0
+ parent_id:
+ parent_title:
+ type:
+ group:
+ created_at: 2015-03-10 17:05:42.000000000 Z
+ updated_at: 2015-03-10 17:05:42.000000000 Z
diff --git a/activerecord/test/support/yaml_compatibility_fixtures/rails_4_2_0.yml b/activerecord/test/support/yaml_compatibility_fixtures/rails_4_2_0.yml
new file mode 100644
index 0000000000..b3d3b33141
--- /dev/null
+++ b/activerecord/test/support/yaml_compatibility_fixtures/rails_4_2_0.yml
@@ -0,0 +1,182 @@
+--- !ruby/object:Topic
+raw_attributes:
+ id: 1
+ title: The First Topic
+ author_name: David
+ author_email_address: david@loudthinking.com
+ written_on: '2003-07-16 14:28:11.223300'
+ bonus_time: '2005-01-30 14:28:00.000000'
+ last_read: '2004-04-15'
+ content: |
+ --- Have a nice day
+ ...
+ important:
+ approved: f
+ replies_count: 1
+ unique_replies_count: 0
+ parent_id:
+ parent_title:
+ type:
+ group:
+ created_at: '2015-03-10 17:44:41'
+ updated_at: '2015-03-10 17:44:41'
+attributes: !ruby/object:ActiveRecord::AttributeSet
+ attributes: !ruby/object:ActiveRecord::LazyAttributeHash
+ types:
+ id: &5 !ruby/object:ActiveRecord::Type::Integer
+ precision:
+ scale:
+ limit:
+ range: !ruby/range
+ begin: -2147483648
+ end: 2147483648
+ excl: true
+ title: &6 !ruby/object:ActiveRecord::Type::String
+ precision:
+ scale:
+ limit: 250
+ author_name: &1 !ruby/object:ActiveRecord::Type::String
+ precision:
+ scale:
+ limit:
+ author_email_address: *1
+ written_on: &4 !ruby/object:ActiveRecord::Type::DateTime
+ precision:
+ scale:
+ limit:
+ bonus_time: &7 !ruby/object:ActiveRecord::Type::Time
+ precision:
+ scale:
+ limit:
+ last_read: &8 !ruby/object:ActiveRecord::Type::Date
+ precision:
+ scale:
+ limit:
+ content: !ruby/object:ActiveRecord::Type::Serialized
+ coder: &9 !ruby/object:ActiveRecord::Coders::YAMLColumn
+ object_class: !ruby/class 'Object'
+ subtype: &2 !ruby/object:ActiveRecord::Type::Text
+ precision:
+ scale:
+ limit:
+ important: *2
+ approved: &10 !ruby/object:ActiveRecord::Type::Boolean
+ precision:
+ scale:
+ limit:
+ replies_count: &3 !ruby/object:ActiveRecord::Type::Integer
+ precision:
+ scale:
+ limit:
+ range: !ruby/range
+ begin: -2147483648
+ end: 2147483648
+ excl: true
+ unique_replies_count: *3
+ parent_id: *3
+ parent_title: *1
+ type: *1
+ group: *1
+ created_at: *4
+ updated_at: *4
+ values:
+ id: 1
+ title: The First Topic
+ author_name: David
+ author_email_address: david@loudthinking.com
+ written_on: '2003-07-16 14:28:11.223300'
+ bonus_time: '2005-01-30 14:28:00.000000'
+ last_read: '2004-04-15'
+ content: |
+ --- Have a nice day
+ ...
+ important:
+ approved: f
+ replies_count: 1
+ unique_replies_count: 0
+ parent_id:
+ parent_title:
+ type:
+ group:
+ created_at: '2015-03-10 17:44:41'
+ updated_at: '2015-03-10 17:44:41'
+ additional_types: {}
+ materialized: true
+ delegate_hash:
+ id: !ruby/object:ActiveRecord::Attribute::FromDatabase
+ name: id
+ value_before_type_cast: 1
+ type: *5
+ title: !ruby/object:ActiveRecord::Attribute::FromDatabase
+ name: title
+ value_before_type_cast: The First Topic
+ type: *6
+ author_name: !ruby/object:ActiveRecord::Attribute::FromDatabase
+ name: author_name
+ value_before_type_cast: David
+ type: *1
+ author_email_address: !ruby/object:ActiveRecord::Attribute::FromDatabase
+ name: author_email_address
+ value_before_type_cast: david@loudthinking.com
+ type: *1
+ written_on: !ruby/object:ActiveRecord::Attribute::FromDatabase
+ name: written_on
+ value_before_type_cast: '2003-07-16 14:28:11.223300'
+ type: *4
+ bonus_time: !ruby/object:ActiveRecord::Attribute::FromDatabase
+ name: bonus_time
+ value_before_type_cast: '2005-01-30 14:28:00.000000'
+ type: *7
+ last_read: !ruby/object:ActiveRecord::Attribute::FromDatabase
+ name: last_read
+ value_before_type_cast: '2004-04-15'
+ type: *8
+ content: !ruby/object:ActiveRecord::Attribute::FromDatabase
+ name: content
+ value_before_type_cast: |
+ --- Have a nice day
+ ...
+ type: !ruby/object:ActiveRecord::Type::Serialized
+ coder: *9
+ subtype: *2
+ important: !ruby/object:ActiveRecord::Attribute::FromDatabase
+ name: important
+ value_before_type_cast:
+ type: *2
+ approved: !ruby/object:ActiveRecord::Attribute::FromDatabase
+ name: approved
+ value_before_type_cast: f
+ type: *10
+ replies_count: !ruby/object:ActiveRecord::Attribute::FromDatabase
+ name: replies_count
+ value_before_type_cast: 1
+ type: *3
+ unique_replies_count: !ruby/object:ActiveRecord::Attribute::FromDatabase
+ name: unique_replies_count
+ value_before_type_cast: 0
+ type: *3
+ parent_id: !ruby/object:ActiveRecord::Attribute::FromDatabase
+ name: parent_id
+ value_before_type_cast:
+ type: *3
+ parent_title: !ruby/object:ActiveRecord::Attribute::FromDatabase
+ name: parent_title
+ value_before_type_cast:
+ type: *1
+ type: !ruby/object:ActiveRecord::Attribute::FromDatabase
+ name: type
+ value_before_type_cast:
+ type: *1
+ group: !ruby/object:ActiveRecord::Attribute::FromDatabase
+ name: group
+ value_before_type_cast:
+ type: *1
+ created_at: !ruby/object:ActiveRecord::Attribute::FromDatabase
+ name: created_at
+ value_before_type_cast: '2015-03-10 17:44:41'
+ type: *4
+ updated_at: !ruby/object:ActiveRecord::Attribute::FromDatabase
+ name: updated_at
+ value_before_type_cast: '2015-03-10 17:44:41'
+ type: *4
+new_record: false
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 43fb87f203..7eaad6340f 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,3 +1,27 @@
+* Added `ActiveSupport::ArrayInquirer` and `Array#inquiry`.
+
+ Wrapping an array in an `ArrayInquirer` gives a friendlier way to check its
+ contents:
+
+ variants = ActiveSupport::ArrayInquirer.new([:phone, :tablet])
+
+ variants.phone? # => true
+ variants.tablet? # => true
+ variants.desktop? # => false
+
+ variants.any?(:phone, :tablet) # => true
+ variants.any?(:phone, :desktop) # => true
+ variants.any?(:desktop, :watch) # => false
+
+ `Array#inquiry` is a shortcut for wrapping the receiving array in an
+ `ArrayInquirer`.
+
+ *George Claghorn*
+
+* Deprecate `alias_method_chain` in favour of `Module#prepend` introduced in Ruby 2.0
+
+ *Kir Shatrov*
+
* Added `#without` on `Enumerable` and `Array` to return a copy of an
enumerable without the specified elements.
diff --git a/activesupport/activesupport.gemspec b/activesupport/activesupport.gemspec
index a5339e6475..2cb455cb41 100644
--- a/activesupport/activesupport.gemspec
+++ b/activesupport/activesupport.gemspec
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
s.summary = 'A toolkit of support libraries and Ruby core extensions extracted from the Rails framework.'
s.description = 'A toolkit of support libraries and Ruby core extensions extracted from the Rails framework. Rich support for multibyte strings, internationalization, time zones, and testing.'
- s.required_ruby_version = '>= 2.2.0'
+ s.required_ruby_version = '>= 2.2.1'
s.license = 'MIT'
diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb
index 290920dbf8..9af3f8b447 100644
--- a/activesupport/lib/active_support.rb
+++ b/activesupport/lib/active_support.rb
@@ -59,6 +59,7 @@ module ActiveSupport
autoload :StringInquirer
autoload :TaggedLogging
autoload :XmlMini
+ autoload :ArrayInquirer
end
autoload :Rescuable
diff --git a/activesupport/lib/active_support/array_inquirer.rb b/activesupport/lib/active_support/array_inquirer.rb
new file mode 100644
index 0000000000..0ae534da00
--- /dev/null
+++ b/activesupport/lib/active_support/array_inquirer.rb
@@ -0,0 +1,38 @@
+module ActiveSupport
+ # Wrapping an array in an +ArrayInquirer+ gives a friendlier way to check
+ # its string-like contents:
+ #
+ # variants = ActiveSupport::ArrayInquirer.new([:phone, :tablet])
+ #
+ # variants.phone? # => true
+ # variants.tablet? # => true
+ # variants.desktop? # => false
+ #
+ # variants.any?(:phone, :tablet) # => true
+ # variants.any?(:phone, :desktop) # => true
+ # variants.any?(:desktop, :watch) # => false
+ class ArrayInquirer < Array
+ def any?(*candidates, &block)
+ if candidates.none?
+ super
+ else
+ candidates.any? do |candidate|
+ include?(candidate) || include?(candidate.to_sym)
+ end
+ end
+ end
+
+ private
+ def respond_to_missing?(name, include_private = false)
+ name[-1] == '?'
+ end
+
+ def method_missing(name, *args)
+ if name[-1] == '?'
+ any?(name[0..-2])
+ else
+ super
+ end
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb
index fdef9cbfc0..837974bc85 100644
--- a/activesupport/lib/active_support/cache.rb
+++ b/activesupport/lib/active_support/cache.rb
@@ -353,8 +353,11 @@ module ActiveSupport
# Returns a hash with the data for each of the names. For example:
#
# cache.write("bim", "bam")
- # cache.fetch_multi("bim", "boom") { |key| key * 2 }
- # # => { "bam" => "bam", "boom" => "boomboom" }
+ # cache.fetch_multi("bim", "unknown_key") do |key|
+ # "Fallback value for key: #{key}"
+ # end
+ # # => { "bim" => "bam",
+ # # "unknown_key" => "Fallback value for key: unknown_key" }
#
def fetch_multi(*names)
options = names.extract_options!
@@ -563,9 +566,9 @@ module ActiveSupport
def handle_expired_entry(entry, key, options)
if entry && entry.expired?
race_ttl = options[:race_condition_ttl].to_i
- if race_ttl && (Time.now.to_f - entry.expires_at <= race_ttl)
- # When an entry has :race_condition_ttl defined, put the stale entry back into the cache
- # for a brief period while the entry is begin recalculated.
+ if (race_ttl > 0) && (Time.now.to_f - entry.expires_at <= race_ttl)
+ # When an entry has a positive :race_condition_ttl defined, put the stale entry back into the cache
+ # for a brief period while the entry is being recalculated.
entry.expires_at = Time.now + race_ttl
write_entry(key, entry, :expires_in => race_ttl * 2)
else
diff --git a/activesupport/lib/active_support/cache/strategy/local_cache.rb b/activesupport/lib/active_support/cache/strategy/local_cache.rb
index 73c6b3cb88..a913736fc3 100644
--- a/activesupport/lib/active_support/cache/strategy/local_cache.rb
+++ b/activesupport/lib/active_support/cache/strategy/local_cache.rb
@@ -39,7 +39,7 @@ module ActiveSupport
@data = {}
end
- # Don't allow synchronizing since it isn't thread safe,
+ # Don't allow synchronizing since it isn't thread safe.
def synchronize # :nodoc:
yield
end
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index f32bb8a0cc..08520b1077 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -5,6 +5,7 @@ require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/kernel/reporting'
require 'active_support/core_ext/kernel/singleton_class'
require 'active_support/core_ext/string/filters'
+require 'active_support/deprecation'
require 'thread'
module ActiveSupport
@@ -490,17 +491,17 @@ module ActiveSupport
end
def around(&around)
- CallbackSequence.new do |*args|
- around.call(*args) {
- self.call(*args)
+ CallbackSequence.new do |arg|
+ around.call(arg) {
+ self.call(arg)
}
end
end
- def call(*args)
- @before.each { |b| b.call(*args) }
- value = @call.call(*args)
- @after.each { |a| a.call(*args) }
+ def call(arg)
+ @before.each { |b| b.call(arg) }
+ value = @call.call(arg)
+ @after.each { |a| a.call(arg) }
value
end
end
diff --git a/activesupport/lib/active_support/core_ext/array.rb b/activesupport/lib/active_support/core_ext/array.rb
index 7d0c1e4c8d..7551551bd7 100644
--- a/activesupport/lib/active_support/core_ext/array.rb
+++ b/activesupport/lib/active_support/core_ext/array.rb
@@ -4,3 +4,4 @@ require 'active_support/core_ext/array/conversions'
require 'active_support/core_ext/array/extract_options'
require 'active_support/core_ext/array/grouping'
require 'active_support/core_ext/array/prepend_and_append'
+require 'active_support/core_ext/array/inquiry'
diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb
index 080e3b5ef7..d80df21e7d 100644
--- a/activesupport/lib/active_support/core_ext/array/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/array/conversions.rb
@@ -74,7 +74,7 @@ class Array
when 0
''
when 1
- self[0].to_s.dup
+ "#{self[0]}"
when 2
"#{self[0]}#{options[:two_words_connector]}#{self[1]}"
else
diff --git a/activesupport/lib/active_support/core_ext/array/inquiry.rb b/activesupport/lib/active_support/core_ext/array/inquiry.rb
new file mode 100644
index 0000000000..de623c466c
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/array/inquiry.rb
@@ -0,0 +1,15 @@
+class Array
+ # Wraps the array in an +ArrayInquirer+ object, which gives a friendlier way
+ # to check its string-like contents.
+ #
+ # pets = [:cat, :dog].inquiry
+ #
+ # pets.cat? # => true
+ # pets.ferret? # => false
+ #
+ # pets.any?(:cat, :ferret) # => true
+ # pets.any?(:ferret, :alligator) # => false
+ def inquiry
+ ActiveSupport::ArrayInquirer.new(self)
+ end
+end
diff --git a/activesupport/lib/active_support/core_ext/hash/keys.rb b/activesupport/lib/active_support/core_ext/hash/keys.rb
index 9297a59c46..c30044b9ff 100644
--- a/activesupport/lib/active_support/core_ext/hash/keys.rb
+++ b/activesupport/lib/active_support/core_ext/hash/keys.rb
@@ -14,7 +14,7 @@ class Hash
result
end
- # Destructively convert all keys using the block operations.
+ # Destructively converts all keys using the block operations.
# Same as transform_keys but modifies +self+.
def transform_keys!
return enum_for(:transform_keys!) unless block_given?
@@ -34,7 +34,7 @@ class Hash
transform_keys(&:to_s)
end
- # Destructively convert all keys to strings. Same as
+ # Destructively converts all keys to strings. Same as
# +stringify_keys+, but modifies +self+.
def stringify_keys!
transform_keys!(&:to_s)
@@ -52,14 +52,14 @@ class Hash
end
alias_method :to_options, :symbolize_keys
- # Destructively convert all keys to symbols, as long as they respond
+ # Destructively converts all keys to symbols, as long as they respond
# to +to_sym+. Same as +symbolize_keys+, but modifies +self+.
def symbolize_keys!
transform_keys!{ |key| key.to_sym rescue key }
end
alias_method :to_options!, :symbolize_keys!
- # Validate all keys in a hash match <tt>*valid_keys</tt>, raising
+ # Validates all keys in a hash match <tt>*valid_keys</tt>, raising
# ArgumentError on a mismatch.
#
# Note that keys are treated differently than HashWithIndifferentAccess,
@@ -89,7 +89,7 @@ class Hash
_deep_transform_keys_in_object(self, &block)
end
- # Destructively convert all keys by using the block operation.
+ # Destructively converts all keys by using the block operation.
# This includes the keys from the root hash and from all
# nested hashes and arrays.
def deep_transform_keys!(&block)
@@ -108,7 +108,7 @@ class Hash
deep_transform_keys(&:to_s)
end
- # Destructively convert all keys to strings.
+ # Destructively converts all keys to strings.
# This includes the keys from the root hash and from all
# nested hashes and arrays.
def deep_stringify_keys!
@@ -127,7 +127,7 @@ class Hash
deep_transform_keys{ |key| key.to_sym rescue key }
end
- # Destructively convert all keys to symbols, as long as they respond
+ # Destructively converts all keys to symbols, as long as they respond
# to +to_sym+. This includes the keys from the root hash and from all
# nested hashes and arrays.
def deep_symbolize_keys!
diff --git a/activesupport/lib/active_support/core_ext/hash/slice.rb b/activesupport/lib/active_support/core_ext/hash/slice.rb
index 41b2279013..1d5f38231a 100644
--- a/activesupport/lib/active_support/core_ext/hash/slice.rb
+++ b/activesupport/lib/active_support/core_ext/hash/slice.rb
@@ -1,5 +1,5 @@
class Hash
- # Slice a hash to include only the given keys. Returns a hash containing
+ # Slices a hash to include only the given keys. Returns a hash containing
# the given keys.
#
# { a: 1, b: 2, c: 3, d: 4 }.slice(:a, :b)
diff --git a/activesupport/lib/active_support/core_ext/integer/time.rb b/activesupport/lib/active_support/core_ext/integer/time.rb
index 82080ffe51..f0b7382ef3 100644
--- a/activesupport/lib/active_support/core_ext/integer/time.rb
+++ b/activesupport/lib/active_support/core_ext/integer/time.rb
@@ -17,21 +17,6 @@ class Integer
#
# # equivalent to Time.now.advance(months: 4, years: 5)
# (4.months + 5.years).from_now
- #
- # While these methods provide precise calculation when used as in the examples
- # above, care should be taken to note that this is not true if the result of
- # +months+, +years+, etc is converted before use:
- #
- # # equivalent to 30.days.to_i.from_now
- # 1.month.to_i.from_now
- #
- # # equivalent to 365.25.days.to_f.from_now
- # 1.year.to_f.from_now
- #
- # In such cases, Ruby's core
- # Date[http://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and
- # Time[http://ruby-doc.org/stdlib/libdoc/time/rdoc/Time.html] should be used for precision
- # date and time arithmetic.
def months
ActiveSupport::Duration.new(self * 30.days, [[:months, self]])
end
diff --git a/activesupport/lib/active_support/core_ext/marshal.rb b/activesupport/lib/active_support/core_ext/marshal.rb
index 56c79c04bd..20a0856e71 100644
--- a/activesupport/lib/active_support/core_ext/marshal.rb
+++ b/activesupport/lib/active_support/core_ext/marshal.rb
@@ -1,9 +1,7 @@
-require 'active_support/core_ext/module/aliasing'
-
-module Marshal
- class << self
- def load_with_autoloading(source)
- load_without_autoloading(source)
+module ActiveSupport
+ module MarshalWithAutoloading # :nodoc:
+ def load(source)
+ super(source)
rescue ArgumentError, NameError => exc
if exc.message.match(%r|undefined class/module (.+)|)
# try loading the class/module
@@ -15,7 +13,7 @@ module Marshal
raise exc
end
end
-
- alias_method_chain :load, :autoloading
end
end
+
+Marshal.singleton_class.prepend(ActiveSupport::MarshalWithAutoloading)
diff --git a/activesupport/lib/active_support/core_ext/module/aliasing.rb b/activesupport/lib/active_support/core_ext/module/aliasing.rb
index 0a6fadf928..25e138264e 100644
--- a/activesupport/lib/active_support/core_ext/module/aliasing.rb
+++ b/activesupport/lib/active_support/core_ext/module/aliasing.rb
@@ -21,6 +21,8 @@ class Module
#
# so you can safely chain foo, foo?, foo! and/or foo= with the same feature.
def alias_method_chain(target, feature)
+ ActiveSupport::Deprecation.warn("alias_method_chain is deprecated. Please, use Module#prepend instead. From module, you can access the original method using super.")
+
# Strip out punctuation on predicates, bang or writer methods since
# e.g. target?_without_feature is not a valid method name.
aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
diff --git a/activesupport/lib/active_support/core_ext/module/remove_method.rb b/activesupport/lib/active_support/core_ext/module/remove_method.rb
index 8a2569a7d0..52632d2c6b 100644
--- a/activesupport/lib/active_support/core_ext/module/remove_method.rb
+++ b/activesupport/lib/active_support/core_ext/module/remove_method.rb
@@ -1,13 +1,13 @@
class Module
- # Remove the named method, if it exists.
+ # Removes the named method, if it exists.
def remove_possible_method(method)
if method_defined?(method) || private_method_defined?(method)
undef_method(method)
end
end
- # Replace the existing method definition, if there is one, with the contents
- # of the block.
+ # Replaces the existing method definition, if there is one, with the passed
+ # block as its body.
def redefine_method(method, &block)
remove_possible_method(method)
define_method(method, &block)
diff --git a/activesupport/lib/active_support/core_ext/numeric/time.rb b/activesupport/lib/active_support/core_ext/numeric/time.rb
index 98716383f4..6c4a975495 100644
--- a/activesupport/lib/active_support/core_ext/numeric/time.rb
+++ b/activesupport/lib/active_support/core_ext/numeric/time.rb
@@ -18,21 +18,6 @@ class Numeric
#
# # equivalent to Time.current.advance(months: 4, years: 5)
# (4.months + 5.years).from_now
- #
- # While these methods provide precise calculation when used as in the examples above, care
- # should be taken to note that this is not true if the result of `months', `years', etc is
- # converted before use:
- #
- # # equivalent to 30.days.to_i.from_now
- # 1.month.to_i.from_now
- #
- # # equivalent to 365.25.days.to_f.from_now
- # 1.year.to_f.from_now
- #
- # In such cases, Ruby's core
- # Date[http://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and
- # Time[http://ruby-doc.org/stdlib/libdoc/time/rdoc/Time.html] should be used for precision
- # date and time arithmetic.
def seconds
ActiveSupport::Duration.new(self, [[:seconds, self]])
end
diff --git a/activesupport/lib/active_support/core_ext/object/json.rb b/activesupport/lib/active_support/core_ext/object/json.rb
index 698b2d1920..0db787010c 100644
--- a/activesupport/lib/active_support/core_ext/object/json.rb
+++ b/activesupport/lib/active_support/core_ext/object/json.rb
@@ -9,7 +9,6 @@ require 'time'
require 'active_support/core_ext/time/conversions'
require 'active_support/core_ext/date_time/conversions'
require 'active_support/core_ext/date/conversions'
-require 'active_support/core_ext/module/aliasing'
# The JSON gem adds a few modules to Ruby core classes containing :to_json definition, overwriting
# their default behavior. That said, we need to define the basic to_json method in all of them,
@@ -26,22 +25,25 @@ require 'active_support/core_ext/module/aliasing'
# bypassed completely. This means that as_json won't be invoked and the JSON gem will simply
# ignore any options it does not natively understand. This also means that ::JSON.{generate,dump}
# should give exactly the same results with or without active support.
-[Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass, Enumerable].each do |klass|
- klass.class_eval do
- def to_json_with_active_support_encoder(options = nil)
+
+module ActiveSupport
+ module ToJsonWithActiveSupportEncoder # :nodoc:
+ def to_json(options = nil)
if options.is_a?(::JSON::State)
# Called from JSON.{generate,dump}, forward it to JSON gem's to_json
- self.to_json_without_active_support_encoder(options)
+ super(options)
else
# to_json is being invoked directly, use ActiveSupport's encoder
ActiveSupport::JSON.encode(self, options)
end
end
-
- alias_method_chain :to_json, :active_support_encoder
end
end
+[Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass, Enumerable].reverse_each do |klass|
+ klass.prepend(ActiveSupport::ToJsonWithActiveSupportEncoder)
+end
+
class Object
def as_json(options = nil) #:nodoc:
if respond_to?(:to_hash)
diff --git a/activesupport/lib/active_support/core_ext/range/each.rb b/activesupport/lib/active_support/core_ext/range/each.rb
index ecef78f55f..f666480fe6 100644
--- a/activesupport/lib/active_support/core_ext/range/each.rb
+++ b/activesupport/lib/active_support/core_ext/range/each.rb
@@ -1,18 +1,22 @@
-require 'active_support/core_ext/module/aliasing'
-
class Range #:nodoc:
def each_with_time_with_zone(&block)
ensure_iteration_allowed
each_without_time_with_zone(&block)
end
- alias_method_chain :each, :time_with_zone
+ # TODO: change to Module#prepend as soon as the fix is backported to MRI 2.2:
+ # https://bugs.ruby-lang.org/issues/10847
+ alias_method :each_without_time_with_zone, :each
+ alias_method :each, :each_with_time_with_zone
def step_with_time_with_zone(n = 1, &block)
ensure_iteration_allowed
step_without_time_with_zone(n, &block)
end
- alias_method_chain :step, :time_with_zone
+ # TODO: change to Module#prepend as soon as the fix is backported to MRI 2.2:
+ # https://bugs.ruby-lang.org/issues/10847
+ alias_method :step_without_time_with_zone, :step
+ alias_method :step, :step_with_time_with_zone
private
def ensure_iteration_allowed
diff --git a/activesupport/lib/active_support/core_ext/range/include_range.rb b/activesupport/lib/active_support/core_ext/range/include_range.rb
index 3a07401c8a..9d20920dd0 100644
--- a/activesupport/lib/active_support/core_ext/range/include_range.rb
+++ b/activesupport/lib/active_support/core_ext/range/include_range.rb
@@ -1,5 +1,3 @@
-require 'active_support/core_ext/module/aliasing'
-
class Range
# Extends the default Range#include? to support range comparisons.
# (1..5).include?(1..5) # => true
@@ -18,6 +16,8 @@ class Range
include_without_range?(value)
end
end
-
- alias_method_chain :include?, :range
+ # TODO: change to Module#prepend as soon as the fix is backported to MRI 2.2:
+ # https://bugs.ruby-lang.org/issues/10847
+ alias_method :include_without_range?, :include?
+ alias_method :include?, :include_with_range?
end
diff --git a/activesupport/lib/active_support/core_ext/string/behavior.rb b/activesupport/lib/active_support/core_ext/string/behavior.rb
index 4aa960039b..710f1f4670 100644
--- a/activesupport/lib/active_support/core_ext/string/behavior.rb
+++ b/activesupport/lib/active_support/core_ext/string/behavior.rb
@@ -1,5 +1,5 @@
class String
- # Enable more predictable duck-typing on String-like classes. See <tt>Object#acts_like?</tt>.
+ # Enables more predictable duck-typing on String-like classes. See <tt>Object#acts_like?</tt>.
def acts_like_string?
true
end
diff --git a/activesupport/lib/active_support/core_ext/string/inflections.rb b/activesupport/lib/active_support/core_ext/string/inflections.rb
index 38d567c014..97f9720b2b 100644
--- a/activesupport/lib/active_support/core_ext/string/inflections.rb
+++ b/activesupport/lib/active_support/core_ext/string/inflections.rb
@@ -178,7 +178,7 @@ class String
ActiveSupport::Inflector.tableize(self)
end
- # Create a class name from a plural table name like Rails does for table names to models.
+ # Creates a class name from a plural table name like Rails does for table names to models.
# Note that this returns a string and not a class. (To convert to an actual class
# follow +classify+ with +constantize+.)
#
diff --git a/activesupport/lib/active_support/core_ext/string/multibyte.rb b/activesupport/lib/active_support/core_ext/string/multibyte.rb
index 57d7f8d1e7..7055f7f699 100644
--- a/activesupport/lib/active_support/core_ext/string/multibyte.rb
+++ b/activesupport/lib/active_support/core_ext/string/multibyte.rb
@@ -35,7 +35,7 @@ class String
ActiveSupport::Multibyte.proxy_class.new(self)
end
- # Return +true+ if string has utf_8 encoding.
+ # Returns +true+ if string has utf_8 encoding.
#
# utf_8_str = "some string".encode "UTF-8"
# iso_str = "some string".encode "ISO-8859-1"
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 bae4e206e6..c676b26b06 100644
--- a/activesupport/lib/active_support/core_ext/string/output_safety.rb
+++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb
@@ -13,7 +13,7 @@ class ERB
# This method is also aliased as <tt>h</tt>.
#
# In your ERB templates, use this method to escape any unsafe content. For example:
- # <%=h @person.name %>
+ # <%= h @person.name %>
#
# puts html_escape('is a > 0 & a < 10?')
# # => is a &gt; 0 &amp; a &lt; 10?
diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb
index 13610ba19f..6f1b653639 100644
--- a/activesupport/lib/active_support/core_ext/time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -48,7 +48,11 @@ class Time
alias_method :at, :at_with_coercion
end
- # Seconds since midnight: Time.now.seconds_since_midnight
+ # Returns the number of seconds since 00:00:00.
+ #
+ # Time.new(2012, 8, 29, 0, 0, 0).seconds_since_midnight # => 0
+ # Time.new(2012, 8, 29, 12, 34, 56).seconds_since_midnight # => 45296
+ # Time.new(2012, 8, 29, 23, 59, 59).seconds_since_midnight # => 86399
def seconds_since_midnight
to_i - change(:hour => 0).to_i + (usec / 1.0e+6)
end
diff --git a/activesupport/lib/active_support/deprecation/method_wrappers.rb b/activesupport/lib/active_support/deprecation/method_wrappers.rb
index cab8a1b14d..c74e9c40ac 100644
--- a/activesupport/lib/active_support/deprecation/method_wrappers.rb
+++ b/activesupport/lib/active_support/deprecation/method_wrappers.rb
@@ -31,12 +31,14 @@ module ActiveSupport
method_names += options.keys
method_names.each do |method_name|
- target_module.alias_method_chain(method_name, :deprecation) do |target, punctuation|
- target_module.send(:define_method, "#{target}_with_deprecation#{punctuation}") do |*args, &block|
+ mod = Module.new do
+ define_method(method_name) do |*args, &block|
deprecator.deprecation_warning(method_name, options[method_name])
- send(:"#{target}_without_deprecation#{punctuation}", *args, &block)
+ super(*args, &block)
end
end
+
+ target_module.prepend(mod)
end
end
end
diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb
index 5a64fc52cc..4c0d1197fe 100644
--- a/activesupport/lib/active_support/duration.rb
+++ b/activesupport/lib/active_support/duration.rb
@@ -56,6 +56,30 @@ module ActiveSupport
@value.to_s
end
+ # Returns the number of seconds that this Duration represents.
+ #
+ # 1.minute.to_i # => 60
+ # 1.hour.to_i # => 3600
+ # 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:
+ #
+ # # equivalent to 30.days.to_i
+ # 1.month.to_i # => 2592000
+ #
+ # # equivalent to 365.25.days.to_i
+ # 1.year.to_i # => 31557600
+ #
+ # In such cases, Ruby's core
+ # Date[http://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and
+ # Time[http://ruby-doc.org/stdlib/libdoc/time/rdoc/Time.html] should be used for precision
+ # date and time arithmetic.
+ def to_i
+ @value.to_i
+ end
+
# Returns +true+ if +other+ is also a Duration instance, which has the
# same parts as this one.
def eql?(other)
diff --git a/activesupport/lib/active_support/number_helper.rb b/activesupport/lib/active_support/number_helper.rb
index cfca42bc69..258d9b34e1 100644
--- a/activesupport/lib/active_support/number_helper.rb
+++ b/activesupport/lib/active_support/number_helper.rb
@@ -95,8 +95,8 @@ module ActiveSupport
# (defaults to current locale).
# * <tt>:precision</tt> - Sets the precision of the number
# (defaults to 3). Keeps the number's precision if nil.
- # * <tt>:significant</tt> - If +true+, precision will be the #
- # of significant_digits. If +false+, the # of fractional
+ # * <tt>:significant</tt> - If +true+, precision will be the number
+ # of significant_digits. If +false+, the number of fractional
# digits (defaults to +false+).
# * <tt>:separator</tt> - Sets the separator between the
# fractional and integer digits (defaults to ".").
@@ -163,8 +163,8 @@ module ActiveSupport
# (defaults to current locale).
# * <tt>:precision</tt> - Sets the precision of the number
# (defaults to 3). Keeps the number's precision if nil.
- # * <tt>:significant</tt> - If +true+, precision will be the #
- # of significant_digits. If +false+, the # of fractional
+ # * <tt>:significant</tt> - If +true+, precision will be the number
+ # of significant_digits. If +false+, the number of fractional
# digits (defaults to +false+).
# * <tt>:separator</tt> - Sets the separator between the
# fractional and integer digits (defaults to ".").
@@ -210,8 +210,8 @@ module ActiveSupport
# (defaults to current locale).
# * <tt>:precision</tt> - Sets the precision of the number
# (defaults to 3).
- # * <tt>:significant</tt> - If +true+, precision will be the #
- # of significant_digits. If +false+, the # of fractional
+ # * <tt>:significant</tt> - If +true+, precision will be the number
+ # of significant_digits. If +false+, the number of fractional
# digits (defaults to +true+)
# * <tt>:separator</tt> - Sets the separator between the
# fractional and integer digits (defaults to ".").
@@ -260,8 +260,8 @@ module ActiveSupport
# (defaults to current locale).
# * <tt>:precision</tt> - Sets the precision of the number
# (defaults to 3).
- # * <tt>:significant</tt> - If +true+, precision will be the #
- # of significant_digits. If +false+, the # of fractional
+ # * <tt>:significant</tt> - If +true+, precision will be the number
+ # of significant_digits. If +false+, the number of fractional
# digits (defaults to +true+)
# * <tt>:separator</tt> - Sets the separator between the
# fractional and integer digits (defaults to ".").
diff --git a/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb b/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb
index fb5adb574a..ce03700de1 100644
--- a/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb
+++ b/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb
@@ -29,14 +29,14 @@ module ActiveSupport
def options
@options ||= begin
defaults = default_format_options.merge(i18n_opts)
- # Override negative format if format options is given
+ # Override negative format if format options are given
defaults[:negative_format] = "-#{opts[:format]}" if opts[:format]
defaults.merge!(opts)
end
end
def i18n_opts
- # Set International negative format if not exists
+ # Set International negative format if it does not exist
i18n = i18n_format_options
i18n[:negative_format] ||= "-#{i18n[:format]}" if i18n[:format]
i18n
diff --git a/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb b/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb
index df316a08e6..981c562551 100644
--- a/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb
+++ b/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb
@@ -23,7 +23,7 @@ module ActiveSupport
precision = 0 if precision < 0 # don't let it be negative
else
rounded_number = number.round(precision)
- rounded_number = rounded_number.to_i if precision == 0
+ rounded_number = rounded_number.to_i if precision == 0 && rounded_number.finite?
rounded_number = rounded_number.abs if rounded_number.zero? # prevent showing negative zeros
end
diff --git a/activesupport/lib/active_support/railtie.rb b/activesupport/lib/active_support/railtie.rb
index 6eba24b569..ef22433491 100644
--- a/activesupport/lib/active_support/railtie.rb
+++ b/activesupport/lib/active_support/railtie.rb
@@ -23,6 +23,11 @@ module ActiveSupport
# Sets the default value for Time.zone
# If assigned value cannot be matched to a TimeZone, an exception will be raised.
initializer "active_support.initialize_time_zone" do |app|
+ begin
+ TZInfo::DataSource.get
+ rescue TZInfo::DataSourceNotFound => e
+ raise e.exception "tzinfo-data is not present. Please add gem 'tzinfo-data' to your Gemfile and run bundle install"
+ end
require 'active_support/core_ext/time/zones'
zone_default = Time.find_zone!(app.config.time_zone)
diff --git a/activesupport/lib/active_support/string_inquirer.rb b/activesupport/lib/active_support/string_inquirer.rb
index 45271c9163..bc673150d0 100644
--- a/activesupport/lib/active_support/string_inquirer.rb
+++ b/activesupport/lib/active_support/string_inquirer.rb
@@ -1,7 +1,7 @@
module ActiveSupport
# Wrapping a string in this class gives you a prettier way to test
# for equality. The value returned by <tt>Rails.env</tt> is wrapped
- # in a StringInquirer object so instead of calling this:
+ # in a StringInquirer object, so instead of calling this:
#
# Rails.env == 'production'
#
diff --git a/activesupport/lib/active_support/subscriber.rb b/activesupport/lib/active_support/subscriber.rb
index cd40284660..8db423f0e9 100644
--- a/activesupport/lib/active_support/subscriber.rb
+++ b/activesupport/lib/active_support/subscriber.rb
@@ -10,19 +10,14 @@ module ActiveSupport
#
# module ActiveRecord
# class StatsSubscriber < ActiveSupport::Subscriber
+ # attach_to :active_record
+ #
# def sql(event)
# Statsd.timing("sql.#{event.payload[:name]}", event.duration)
# end
# end
# end
#
- # And it's finally registered as:
- #
- # ActiveRecord::StatsSubscriber.attach_to :active_record
- #
- # Since we need to know all instance methods before attaching the log
- # subscriber, the line above should be called after your subscriber definition.
- #
# After configured, whenever a "sql.active_record" notification is published,
# it will properly dispatch the event (ActiveSupport::Notifications::Event) to
# the +sql+ method.
diff --git a/activesupport/lib/active_support/tagged_logging.rb b/activesupport/lib/active_support/tagged_logging.rb
index 9086a959aa..bcd7bf74c0 100644
--- a/activesupport/lib/active_support/tagged_logging.rb
+++ b/activesupport/lib/active_support/tagged_logging.rb
@@ -43,7 +43,7 @@ module ActiveSupport
end
def current_tags
- # We use our object ID here to void conflicting with other instances
+ # We use our object ID here to avoid conflicting with other instances
thread_key = @thread_key ||= "activesupport_tagged_logging_tags:#{object_id}".freeze
Thread.current[thread_key] ||= []
end
diff --git a/activesupport/lib/active_support/test_case.rb b/activesupport/lib/active_support/test_case.rb
index 739823bd56..24b8f4b9f9 100644
--- a/activesupport/lib/active_support/test_case.rb
+++ b/activesupport/lib/active_support/test_case.rb
@@ -45,8 +45,6 @@ module ActiveSupport
test_order
end
-
- alias :my_tests_are_order_dependent! :i_suck_and_my_tests_are_order_dependent!
end
alias_method :method_name, :name
@@ -75,7 +73,7 @@ module ActiveSupport
alias :assert_not_respond_to :refute_respond_to
alias :assert_not_same :refute_same
- # Fails if the block raises an exception.
+ # Reveals the intention that the block should not raise any exception.
#
# assert_nothing_raised do
# ...
diff --git a/activesupport/lib/active_support/testing/time_helpers.rb b/activesupport/lib/active_support/testing/time_helpers.rb
index df5186ddec..3478b09423 100644
--- a/activesupport/lib/active_support/testing/time_helpers.rb
+++ b/activesupport/lib/active_support/testing/time_helpers.rb
@@ -39,15 +39,16 @@ module ActiveSupport
end
end
- # Containing helpers that helps you test passage of time.
+ # Contain helpers that help you test passage of time.
module TimeHelpers
# Changes current time to the time in the future or in the past by a given time difference by
- # stubbing +Time.now+ and +Date.today+.
+ # stubbing +Time.now+, +Date.today+, and +DateTime.now+.
#
- # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
# travel 1.day
- # Time.current # => Sun, 10 Nov 2013 15:34:49 EST -05:00
- # Date.current # => Sun, 10 Nov 2013
+ # Time.current # => Sun, 10 Nov 2013 15:34:49 EST -05:00
+ # Date.current # => Sun, 10 Nov 2013
+ # DateTime.current # => Sun, 10 Nov 2013 15:34:49 -0500
#
# This method also accepts a block, which will return the current time back to its original
# state at the end of the block:
@@ -61,13 +62,14 @@ module ActiveSupport
travel_to Time.now + duration, &block
end
- # Changes current time to the given time by stubbing +Time.now+ and
- # +Date.today+ to return the time or date passed into this method.
+ # Changes current time to the given time by stubbing +Time.now+,
+ # +Date.today+, and +DateTime.now+ to return the time or date passed into this method.
#
- # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
# travel_to Time.new(2004, 11, 24, 01, 04, 44)
- # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
- # Date.current # => Wed, 24 Nov 2004
+ # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
+ # Date.current # => Wed, 24 Nov 2004
+ # DateTime.current # => Wed, 24 Nov 2004 01:04:44 -0500
#
# Dates are taken as their timestamp at the beginning of the day in the
# application time zone. <tt>Time.current</tt> returns said timestamp,
diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb
index 8ddf233b3e..c28de4e21c 100644
--- a/activesupport/lib/active_support/time_with_zone.rb
+++ b/activesupport/lib/active_support/time_with_zone.rb
@@ -252,7 +252,7 @@ module ActiveSupport
utc.hash
end
- # Adds an interval of time to the current object's time and return that
+ # Adds an interval of time to the current object's time and returns that
# value as a new TimeWithZone object.
#
# Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
diff --git a/activesupport/test/abstract_unit.rb b/activesupport/test/abstract_unit.rb
index f65ec962f9..7ffcae6007 100644
--- a/activesupport/test/abstract_unit.rb
+++ b/activesupport/test/abstract_unit.rb
@@ -38,8 +38,3 @@ def jruby_skip(message = '')
end
require 'mocha/setup' # FIXME: stop using mocha
-
-# FIXME: we have tests that depend on run order, we should fix that and
-# remove this method call.
-require 'active_support/test_case'
-ActiveSupport::TestCase.test_order = :sorted
diff --git a/activesupport/test/array_inquirer_test.rb b/activesupport/test/array_inquirer_test.rb
new file mode 100644
index 0000000000..b25e5cca86
--- /dev/null
+++ b/activesupport/test/array_inquirer_test.rb
@@ -0,0 +1,36 @@
+require 'abstract_unit'
+require 'active_support/core_ext/array'
+
+class ArrayInquirerTest < ActiveSupport::TestCase
+ def setup
+ @array_inquirer = ActiveSupport::ArrayInquirer.new([:mobile, :tablet])
+ end
+
+ def test_individual
+ assert @array_inquirer.mobile?
+ assert @array_inquirer.tablet?
+ assert_not @array_inquirer.desktop?
+ end
+
+ def test_any
+ assert @array_inquirer.any?(:mobile, :desktop)
+ assert @array_inquirer.any?(:watch, :tablet)
+ assert_not @array_inquirer.any?(:desktop, :watch)
+ end
+
+ def test_any_with_block
+ assert @array_inquirer.any? { |v| v == :mobile }
+ assert_not @array_inquirer.any? { |v| v == :desktop }
+ end
+
+ def test_respond_to
+ assert_respond_to @array_inquirer, :development?
+ end
+
+ def test_inquiry
+ result = [:mobile, :tablet].inquiry
+
+ assert_instance_of ActiveSupport::ArrayInquirer, result
+ assert_equal @array_inquirer, result
+ end
+end
diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb
index 7f5f8feb0d..4953550c45 100644
--- a/activesupport/test/caching_test.rb
+++ b/activesupport/test/caching_test.rb
@@ -399,15 +399,16 @@ module CacheStoreBehavior
assert_nil @cache.read('foo')
end
- def test_race_condition_protection
- time = Time.now
- @cache.write('foo', 'bar', :expires_in => 60)
- Time.stubs(:now).returns(time + 61)
- result = @cache.fetch('foo', :race_condition_ttl => 10) do
- assert_equal 'bar', @cache.read('foo')
- "baz"
+ def test_race_condition_protection_skipped_if_not_defined
+ @cache.write('foo', 'bar')
+ time = @cache.send(:read_entry, 'foo', {}).expires_at
+ Time.stubs(:now).returns(Time.at(time))
+
+ result = @cache.fetch('foo') do
+ assert_equal nil, @cache.read('foo')
+ 'baz'
end
- assert_equal "baz", result
+ assert_equal 'baz', result
end
def test_race_condition_protection_is_limited
@@ -437,6 +438,17 @@ module CacheStoreBehavior
assert_nil @cache.read('foo')
end
+ def test_race_condition_protection
+ time = Time.now
+ @cache.write('foo', 'bar', :expires_in => 60)
+ Time.stubs(:now).returns(time + 61)
+ result = @cache.fetch('foo', :race_condition_ttl => 10) do
+ assert_equal 'bar', @cache.read('foo')
+ "baz"
+ end
+ assert_equal "baz", result
+ end
+
def test_crazy_key_characters
crazy_key = "#/:*(<+=> )&$%@?;'\"\'`~-"
assert @cache.write(crazy_key, "1", :raw => true)
diff --git a/activesupport/test/core_ext/array/conversions_test.rb b/activesupport/test/core_ext/array/conversions_test.rb
index 577b889410..507e13f968 100644
--- a/activesupport/test/core_ext/array/conversions_test.rb
+++ b/activesupport/test/core_ext/array/conversions_test.rb
@@ -60,6 +60,12 @@ class ToSentenceTest < ActiveSupport::TestCase
assert_equal exception.message, "Unknown key: :passing. Valid keys are: :words_connector, :two_words_connector, :last_word_connector, :locale"
end
+
+ def test_always_returns_string
+ assert_instance_of String, [ActiveSupport::SafeBuffer.new('one')].to_sentence
+ assert_instance_of String, [ActiveSupport::SafeBuffer.new('one'), 'two'].to_sentence
+ assert_instance_of String, [ActiveSupport::SafeBuffer.new('one'), 'two', 'three'].to_sentence
+ end
end
class ToSTest < ActiveSupport::TestCase
diff --git a/activesupport/test/core_ext/marshal_test.rb b/activesupport/test/core_ext/marshal_test.rb
index 8f3f710dfd..e49330128b 100644
--- a/activesupport/test/core_ext/marshal_test.rb
+++ b/activesupport/test/core_ext/marshal_test.rb
@@ -15,7 +15,7 @@ class MarshalTest < ActiveSupport::TestCase
sanity_data = ["test", [1, 2, 3], {a: [1, 2, 3]}, ActiveSupport::TestCase]
sanity_data.each do |obj|
dumped = Marshal.dump(obj)
- assert_equal Marshal.load_without_autoloading(dumped), Marshal.load(dumped)
+ assert_equal Marshal.method(:load).super_method.call(dumped), Marshal.load(dumped)
end
end
@@ -121,4 +121,4 @@ class MarshalTest < ActiveSupport::TestCase
end
end
end
-end \ No newline at end of file
+end
diff --git a/activesupport/test/core_ext/module_test.rb b/activesupport/test/core_ext/module_test.rb
index c9c9b66a6c..bdfbadcf1d 100644
--- a/activesupport/test/core_ext/module_test.rb
+++ b/activesupport/test/core_ext/module_test.rb
@@ -358,148 +358,178 @@ class MethodAliasingTest < ActiveSupport::TestCase
Object.instance_eval { remove_const :FooClassWithBarMethod }
end
- def test_alias_method_chain
- assert @instance.respond_to?(:bar)
- feature_aliases = [:bar_with_baz, :bar_without_baz]
+ def test_alias_method_chain_deprecated
+ assert_deprecated(/alias_method_chain/) do
+ Module.new do
+ def base
+ end
+
+ def base_with_deprecated
+ end
- feature_aliases.each do |method|
- assert !@instance.respond_to?(method)
+ alias_method_chain :base, :deprecated
+ end
end
+ end
- assert_equal 'bar', @instance.bar
+ def test_alias_method_chain
+ assert_deprecated(/alias_method_chain/) do
+ assert @instance.respond_to?(:bar)
+ feature_aliases = [:bar_with_baz, :bar_without_baz]
- FooClassWithBarMethod.class_eval { include BarMethodAliaser }
+ feature_aliases.each do |method|
+ assert !@instance.respond_to?(method)
+ end
- feature_aliases.each do |method|
- assert_respond_to @instance, method
- end
+ assert_equal 'bar', @instance.bar
+
+ FooClassWithBarMethod.class_eval { include BarMethodAliaser }
+
+ feature_aliases.each do |method|
+ assert_respond_to @instance, method
+ end
- assert_equal 'bar_with_baz', @instance.bar
- assert_equal 'bar', @instance.bar_without_baz
+ assert_equal 'bar_with_baz', @instance.bar
+ assert_equal 'bar', @instance.bar_without_baz
+ end
end
def test_alias_method_chain_with_punctuation_method
- FooClassWithBarMethod.class_eval do
- def quux!; 'quux' end
- end
+ assert_deprecated(/alias_method_chain/) do
+ FooClassWithBarMethod.class_eval do
+ def quux!; 'quux' end
+ end
- assert !@instance.respond_to?(:quux_with_baz!)
- FooClassWithBarMethod.class_eval do
- include BarMethodAliaser
- alias_method_chain :quux!, :baz
- end
- assert_respond_to @instance, :quux_with_baz!
+ assert !@instance.respond_to?(:quux_with_baz!)
+ FooClassWithBarMethod.class_eval do
+ include BarMethodAliaser
+ alias_method_chain :quux!, :baz
+ end
+ assert_respond_to @instance, :quux_with_baz!
- assert_equal 'quux_with_baz', @instance.quux!
- assert_equal 'quux', @instance.quux_without_baz!
+ assert_equal 'quux_with_baz', @instance.quux!
+ assert_equal 'quux', @instance.quux_without_baz!
+ end
end
def test_alias_method_chain_with_same_names_between_predicates_and_bang_methods
- FooClassWithBarMethod.class_eval do
- def quux!; 'quux!' end
- def quux?; true end
- def quux=(v); 'quux=' end
- end
+ assert_deprecated(/alias_method_chain/) do
+ FooClassWithBarMethod.class_eval do
+ def quux!; 'quux!' end
+ def quux?; true end
+ def quux=(v); 'quux=' end
+ end
- assert !@instance.respond_to?(:quux_with_baz!)
- assert !@instance.respond_to?(:quux_with_baz?)
- assert !@instance.respond_to?(:quux_with_baz=)
+ assert !@instance.respond_to?(:quux_with_baz!)
+ assert !@instance.respond_to?(:quux_with_baz?)
+ assert !@instance.respond_to?(:quux_with_baz=)
- FooClassWithBarMethod.class_eval { include BarMethodAliaser }
- assert_respond_to @instance, :quux_with_baz!
- assert_respond_to @instance, :quux_with_baz?
- assert_respond_to @instance, :quux_with_baz=
+ FooClassWithBarMethod.class_eval { include BarMethodAliaser }
+ assert_respond_to @instance, :quux_with_baz!
+ assert_respond_to @instance, :quux_with_baz?
+ assert_respond_to @instance, :quux_with_baz=
- FooClassWithBarMethod.alias_method_chain :quux!, :baz
- assert_equal 'quux!_with_baz', @instance.quux!
- assert_equal 'quux!', @instance.quux_without_baz!
+ FooClassWithBarMethod.alias_method_chain :quux!, :baz
+ assert_equal 'quux!_with_baz', @instance.quux!
+ assert_equal 'quux!', @instance.quux_without_baz!
- FooClassWithBarMethod.alias_method_chain :quux?, :baz
- assert_equal false, @instance.quux?
- assert_equal true, @instance.quux_without_baz?
+ FooClassWithBarMethod.alias_method_chain :quux?, :baz
+ assert_equal false, @instance.quux?
+ assert_equal true, @instance.quux_without_baz?
- FooClassWithBarMethod.alias_method_chain :quux=, :baz
- assert_equal 'quux=_with_baz', @instance.send(:quux=, 1234)
- assert_equal 'quux=', @instance.send(:quux_without_baz=, 1234)
+ FooClassWithBarMethod.alias_method_chain :quux=, :baz
+ assert_equal 'quux=_with_baz', @instance.send(:quux=, 1234)
+ assert_equal 'quux=', @instance.send(:quux_without_baz=, 1234)
+ end
end
def test_alias_method_chain_with_feature_punctuation
- FooClassWithBarMethod.class_eval do
- def quux; 'quux' end
- def quux?; 'quux?' end
- include BarMethodAliaser
- alias_method_chain :quux, :baz!
- end
+ assert_deprecated(/alias_method_chain/) do
+ FooClassWithBarMethod.class_eval do
+ def quux; 'quux' end
+ def quux?; 'quux?' end
+ include BarMethodAliaser
+ alias_method_chain :quux, :baz!
+ end
- assert_nothing_raised do
- assert_equal 'quux_with_baz', @instance.quux_with_baz!
- end
+ assert_nothing_raised do
+ assert_equal 'quux_with_baz', @instance.quux_with_baz!
+ end
- assert_raise(NameError) do
- FooClassWithBarMethod.alias_method_chain :quux?, :baz!
+ assert_raise(NameError) do
+ FooClassWithBarMethod.alias_method_chain :quux?, :baz!
+ end
end
end
def test_alias_method_chain_yields_target_and_punctuation
- args = nil
+ assert_deprecated(/alias_method_chain/) do
+ args = nil
- FooClassWithBarMethod.class_eval do
- def quux?; end
- include BarMethods
+ FooClassWithBarMethod.class_eval do
+ def quux?; end
+ include BarMethods
- FooClassWithBarMethod.alias_method_chain :quux?, :baz do |target, punctuation|
- args = [target, punctuation]
+ FooClassWithBarMethod.alias_method_chain :quux?, :baz do |target, punctuation|
+ args = [target, punctuation]
+ end
end
- end
- assert_not_nil args
- assert_equal 'quux', args[0]
- assert_equal '?', args[1]
+ assert_not_nil args
+ assert_equal 'quux', args[0]
+ assert_equal '?', args[1]
+ end
end
def test_alias_method_chain_preserves_private_method_status
- FooClassWithBarMethod.class_eval do
- def duck; 'duck' end
- include BarMethodAliaser
- private :duck
- alias_method_chain :duck, :orange
- end
+ assert_deprecated(/alias_method_chain/) do
+ FooClassWithBarMethod.class_eval do
+ def duck; 'duck' end
+ include BarMethodAliaser
+ private :duck
+ alias_method_chain :duck, :orange
+ end
- assert_raise NoMethodError do
- @instance.duck
- end
+ assert_raise NoMethodError do
+ @instance.duck
+ end
- assert_equal 'duck_with_orange', @instance.instance_eval { duck }
- assert FooClassWithBarMethod.private_method_defined?(:duck)
+ assert_equal 'duck_with_orange', @instance.instance_eval { duck }
+ assert FooClassWithBarMethod.private_method_defined?(:duck)
+ end
end
def test_alias_method_chain_preserves_protected_method_status
- FooClassWithBarMethod.class_eval do
- def duck; 'duck' end
- include BarMethodAliaser
- protected :duck
- alias_method_chain :duck, :orange
- end
+ assert_deprecated(/alias_method_chain/) do
+ FooClassWithBarMethod.class_eval do
+ def duck; 'duck' end
+ include BarMethodAliaser
+ protected :duck
+ alias_method_chain :duck, :orange
+ end
- assert_raise NoMethodError do
- @instance.duck
- end
+ assert_raise NoMethodError do
+ @instance.duck
+ end
- assert_equal 'duck_with_orange', @instance.instance_eval { duck }
- assert FooClassWithBarMethod.protected_method_defined?(:duck)
+ assert_equal 'duck_with_orange', @instance.instance_eval { duck }
+ assert FooClassWithBarMethod.protected_method_defined?(:duck)
+ end
end
def test_alias_method_chain_preserves_public_method_status
- FooClassWithBarMethod.class_eval do
- def duck; 'duck' end
- include BarMethodAliaser
- public :duck
- alias_method_chain :duck, :orange
- end
+ assert_deprecated(/alias_method_chain/) do
+ FooClassWithBarMethod.class_eval do
+ def duck; 'duck' end
+ include BarMethodAliaser
+ public :duck
+ alias_method_chain :duck, :orange
+ end
- assert_equal 'duck_with_orange', @instance.duck
- assert FooClassWithBarMethod.public_method_defined?(:duck)
+ assert_equal 'duck_with_orange', @instance.duck
+ assert FooClassWithBarMethod.public_method_defined?(:duck)
+ end
end
def test_delegate_with_case
diff --git a/activesupport/test/core_ext/securerandom.rb b/activesupport/test/core_ext/secure_random_test.rb
index dfacb7fe9f..dfacb7fe9f 100644
--- a/activesupport/test/core_ext/securerandom.rb
+++ b/activesupport/test/core_ext/secure_random_test.rb
diff --git a/activesupport/test/number_helper_test.rb b/activesupport/test/number_helper_test.rb
index 23996ef381..83efbffdfb 100644
--- a/activesupport/test/number_helper_test.rb
+++ b/activesupport/test/number_helper_test.rb
@@ -83,6 +83,10 @@ module ActiveSupport
assert_equal("98a%", number_helper.number_to_percentage("98a"))
assert_equal("NaN%", number_helper.number_to_percentage(Float::NAN))
assert_equal("Inf%", number_helper.number_to_percentage(Float::INFINITY))
+ assert_equal("NaN%", number_helper.number_to_percentage(Float::NAN, precision: 0))
+ assert_equal("Inf%", number_helper.number_to_percentage(Float::INFINITY, precision: 0))
+ assert_equal("NaN%", number_helper.number_to_percentage(Float::NAN, precision: 1))
+ assert_equal("Inf%", number_helper.number_to_percentage(Float::INFINITY, precision: 1))
assert_equal("1000%", number_helper.number_to_percentage(1000, precision: nil))
assert_equal("1000%", number_helper.number_to_percentage(1000, precision: nil))
assert_equal("1000.1%", number_helper.number_to_percentage(1000.1, precision: nil))
diff --git a/activesupport/test/test_case_test.rb b/activesupport/test/test_case_test.rb
index 151b623171..9e6d1a91d0 100644
--- a/activesupport/test/test_case_test.rb
+++ b/activesupport/test/test_case_test.rb
@@ -205,15 +205,4 @@ class TestOrderTest < ActiveSupport::TestCase
assert_equal :random, self.class.test_order
assert_equal :random, Class.new(ActiveSupport::TestCase).test_order
end
-
- def test_i_suck_and_my_tests_are_order_dependent!
- ActiveSupport::TestCase.test_order = :random
-
- klass = Class.new(ActiveSupport::TestCase) do
- i_suck_and_my_tests_are_order_dependent!
- end
-
- assert_equal :alpha, klass.test_order
- assert_equal :random, ActiveSupport::TestCase.test_order
- end
end
diff --git a/guides/rails_guides.rb b/guides/rails_guides.rb
index 762ab1c0e2..367ed0b12e 100644
--- a/guides/rails_guides.rb
+++ b/guides/rails_guides.rb
@@ -1,13 +1,6 @@
pwd = File.dirname(__FILE__)
$:.unshift pwd
-# This is a predicate useful for the doc:guides task of applications.
-def bundler?
- # Note that rake sets the cwd to the one that contains the Rakefile
- # being executed.
- File.exist?('Gemfile')
-end
-
begin
# Guides generation in the Rails repo.
as_lib = File.join(pwd, "../activesupport/lib")
@@ -20,44 +13,5 @@ rescue LoadError
gem "actionpack", '>= 3.0'
end
-begin
- require 'redcarpet'
-rescue LoadError
- # This can happen if doc:guides is executed in an application.
- $stderr.puts('Generating guides requires Redcarpet 3.2.2+.')
- $stderr.puts(<<ERROR) if bundler?
-Please add
-
- gem 'redcarpet', '~> 3.2.2'
-
-to the Gemfile, run
-
- bundle install
-
-and try again.
-ERROR
- exit 1
-end
-
-begin
- require 'nokogiri'
-rescue LoadError
- # This can happen if doc:guides is executed in an application.
- $stderr.puts('Generating guides requires Nokogiri.')
- $stderr.puts(<<ERROR) if bundler?
-Please add
-
- gem 'nokogiri'
-
-to the Gemfile, run
-
- bundle install
-
-and try again.
-ERROR
- exit 1
-end
-
-require 'rails_guides/markdown'
require "rails_guides/generator"
RailsGuides::Generator.new.generate
diff --git a/guides/rails_guides/generator.rb b/guides/rails_guides/generator.rb
index aa900454c8..43f6f7eecf 100644
--- a/guides/rails_guides/generator.rb
+++ b/guides/rails_guides/generator.rb
@@ -57,6 +57,7 @@ require 'active_support/core_ext/object/blank'
require 'action_controller'
require 'action_view'
+require 'rails_guides/markdown'
require 'rails_guides/indexer'
require 'rails_guides/helpers'
require 'rails_guides/levenshtein'
diff --git a/guides/source/2_3_release_notes.md b/guides/source/2_3_release_notes.md
index 328656f4a4..0a62f34371 100644
--- a/guides/source/2_3_release_notes.md
+++ b/guides/source/2_3_release_notes.md
@@ -187,7 +187,7 @@ MySQL supports a reconnect flag in its connections - if set to true, then the cl
* Lead Contributor: [Dov Murik](http://twitter.com/dubek)
* More information:
- * [Controlling Automatic Reconnection Behavior](http://dev.mysql.com/doc/refman/5.0/en/auto-reconnect.html)
+ * [Controlling Automatic Reconnection Behavior](http://dev.mysql.com/doc/refman/5.6/en/auto-reconnect.html)
* [MySQL auto-reconnect revisited](http://groups.google.com/group/rubyonrails-core/browse_thread/thread/49d2a7e9c96cb9f4)
### Other Active Record Changes
diff --git a/guides/source/3_1_release_notes.md b/guides/source/3_1_release_notes.md
index e187e5f9ab..537aa5a371 100644
--- a/guides/source/3_1_release_notes.md
+++ b/guides/source/3_1_release_notes.md
@@ -174,7 +174,7 @@ Rails Architectural Changes
The major change in Rails 3.1 is the Assets Pipeline. It makes CSS and JavaScript first-class code citizens and enables proper organization, including use in plugins and engines.
-The assets pipeline is powered by [Sprockets](https://github.com/sstephenson/sprockets) and is covered in the [Asset Pipeline](asset_pipeline.html) guide.
+The assets pipeline is powered by [Sprockets](https://github.com/rails/sprockets) and is covered in the [Asset Pipeline](asset_pipeline.html) guide.
### HTTP Streaming
diff --git a/guides/source/4_0_release_notes.md b/guides/source/4_0_release_notes.md
index bd35e2d31a..9feaff098a 100644
--- a/guides/source/4_0_release_notes.md
+++ b/guides/source/4_0_release_notes.md
@@ -59,25 +59,25 @@ Major Features
### Upgrade
- * **Ruby 1.9.3** ([commit](https://github.com/rails/rails/commit/a0380e808d3dbd2462df17f5d3b7fcd8bd812496)) - Ruby 2.0 preferred; 1.9.3+ required
- * **[New deprecation policy](http://www.youtube.com/watch?v=z6YgD6tVPQs)** - Deprecated features are warnings in Rails 4.0 and will be removed in Rails 4.1.
- * **ActionPack page and action caching** ([commit](https://github.com/rails/rails/commit/b0a7068564f0c95e7ef28fc39d0335ed17d93e90)) - Page and action caching are extracted to a separate gem. Page and action caching requires too much manual intervention (manually expiring caches when the underlying model objects are updated). Instead, use Russian doll caching.
- * **ActiveRecord observers** ([commit](https://github.com/rails/rails/commit/ccecab3ba950a288b61a516bf9b6962e384aae0b)) - Observers are extracted to a separate gem. Observers are only needed for page and action caching, and can lead to spaghetti code.
- * **ActiveRecord session store** ([commit](https://github.com/rails/rails/commit/0ffe19056c8e8b2f9ae9d487b896cad2ce9387ad)) - The ActiveRecord session store is extracted to a separate gem. Storing sessions in SQL is costly. Instead, use cookie sessions, memcache sessions, or a custom session store.
- * **ActiveModel mass assignment protection** ([commit](https://github.com/rails/rails/commit/f8c9a4d3e88181cee644f91e1342bfe896ca64c6)) - Rails 3 mass assignment protection is deprecated. Instead, use strong parameters.
- * **ActiveResource** ([commit](https://github.com/rails/rails/commit/f1637bf2bb00490203503fbd943b73406e043d1d)) - ActiveResource is extracted to a separate gem. ActiveResource was not widely used.
- * **vendor/plugins removed** ([commit](https://github.com/rails/rails/commit/853de2bd9ac572735fa6cf59fcf827e485a231c3)) - Use a Gemfile to manage installed gems.
+* **Ruby 1.9.3** ([commit](https://github.com/rails/rails/commit/a0380e808d3dbd2462df17f5d3b7fcd8bd812496)) - Ruby 2.0 preferred; 1.9.3+ required
+* **[New deprecation policy](http://www.youtube.com/watch?v=z6YgD6tVPQs)** - Deprecated features are warnings in Rails 4.0 and will be removed in Rails 4.1.
+* **ActionPack page and action caching** ([commit](https://github.com/rails/rails/commit/b0a7068564f0c95e7ef28fc39d0335ed17d93e90)) - Page and action caching are extracted to a separate gem. Page and action caching requires too much manual intervention (manually expiring caches when the underlying model objects are updated). Instead, use Russian doll caching.
+* **ActiveRecord observers** ([commit](https://github.com/rails/rails/commit/ccecab3ba950a288b61a516bf9b6962e384aae0b)) - Observers are extracted to a separate gem. Observers are only needed for page and action caching, and can lead to spaghetti code.
+* **ActiveRecord session store** ([commit](https://github.com/rails/rails/commit/0ffe19056c8e8b2f9ae9d487b896cad2ce9387ad)) - The ActiveRecord session store is extracted to a separate gem. Storing sessions in SQL is costly. Instead, use cookie sessions, memcache sessions, or a custom session store.
+* **ActiveModel mass assignment protection** ([commit](https://github.com/rails/rails/commit/f8c9a4d3e88181cee644f91e1342bfe896ca64c6)) - Rails 3 mass assignment protection is deprecated. Instead, use strong parameters.
+* **ActiveResource** ([commit](https://github.com/rails/rails/commit/f1637bf2bb00490203503fbd943b73406e043d1d)) - ActiveResource is extracted to a separate gem. ActiveResource was not widely used.
+* **vendor/plugins removed** ([commit](https://github.com/rails/rails/commit/853de2bd9ac572735fa6cf59fcf827e485a231c3)) - Use a Gemfile to manage installed gems.
### ActionPack
- * **Strong parameters** ([commit](https://github.com/rails/rails/commit/a8f6d5c6450a7fe058348a7f10a908352bb6c7fc)) - Only allow whitelisted parameters to update model objects (`params.permit(:title, :text)`).
- * **Routing concerns** ([commit](https://github.com/rails/rails/commit/0dd24728a088fcb4ae616bb5d62734aca5276b1b)) - In the routing DSL, factor out common subroutes (`comments` from `/posts/1/comments` and `/videos/1/comments`).
- * **ActionController::Live** ([commit](https://github.com/rails/rails/commit/af0a9f9eefaee3a8120cfd8d05cbc431af376da3)) - Stream JSON with `response.stream`.
- * **Declarative ETags** ([commit](https://github.com/rails/rails/commit/ed5c938fa36995f06d4917d9543ba78ed506bb8d)) - Add controller-level etag additions that will be part of the action etag computation.
- * **[Russian doll caching](http://37signals.com/svn/posts/3113-how-key-based-cache-expiration-works)** ([commit](https://github.com/rails/rails/commit/4154bf012d2bec2aae79e4a49aa94a70d3e91d49)) - Cache nested fragments of views. Each fragment expires based on a set of dependencies (a cache key). The cache key is usually a template version number and a model object.
- * **Turbolinks** ([commit](https://github.com/rails/rails/commit/e35d8b18d0649c0ecc58f6b73df6b3c8d0c6bb74)) - Serve only one initial HTML page. When the user navigates to another page, use pushState to update the URL and use AJAX to update the title and body.
- * **Decouple ActionView from ActionController** ([commit](https://github.com/rails/rails/commit/78b0934dd1bb84e8f093fb8ef95ca99b297b51cd)) - ActionView was decoupled from ActionPack and will be moved to a separated gem in Rails 4.1.
- * **Do not depend on ActiveModel** ([commit](https://github.com/rails/rails/commit/166dbaa7526a96fdf046f093f25b0a134b277a68)) - ActionPack no longer depends on ActiveModel.
+* **Strong parameters** ([commit](https://github.com/rails/rails/commit/a8f6d5c6450a7fe058348a7f10a908352bb6c7fc)) - Only allow whitelisted parameters to update model objects (`params.permit(:title, :text)`).
+* **Routing concerns** ([commit](https://github.com/rails/rails/commit/0dd24728a088fcb4ae616bb5d62734aca5276b1b)) - In the routing DSL, factor out common subroutes (`comments` from `/posts/1/comments` and `/videos/1/comments`).
+* **ActionController::Live** ([commit](https://github.com/rails/rails/commit/af0a9f9eefaee3a8120cfd8d05cbc431af376da3)) - Stream JSON with `response.stream`.
+* **Declarative ETags** ([commit](https://github.com/rails/rails/commit/ed5c938fa36995f06d4917d9543ba78ed506bb8d)) - Add controller-level etag additions that will be part of the action etag computation.
+* **[Russian doll caching](http://37signals.com/svn/posts/3113-how-key-based-cache-expiration-works)** ([commit](https://github.com/rails/rails/commit/4154bf012d2bec2aae79e4a49aa94a70d3e91d49)) - Cache nested fragments of views. Each fragment expires based on a set of dependencies (a cache key). The cache key is usually a template version number and a model object.
+* **Turbolinks** ([commit](https://github.com/rails/rails/commit/e35d8b18d0649c0ecc58f6b73df6b3c8d0c6bb74)) - Serve only one initial HTML page. When the user navigates to another page, use pushState to update the URL and use AJAX to update the title and body.
+* **Decouple ActionView from ActionController** ([commit](https://github.com/rails/rails/commit/78b0934dd1bb84e8f093fb8ef95ca99b297b51cd)) - ActionView was decoupled from ActionPack and will be moved to a separated gem in Rails 4.1.
+* **Do not depend on ActiveModel** ([commit](https://github.com/rails/rails/commit/166dbaa7526a96fdf046f093f25b0a134b277a68)) - ActionPack no longer depends on ActiveModel.
### General
@@ -87,14 +87,17 @@ Major Features
* **Support for specifying transaction isolation level** ([commit](https://github.com/rails/rails/commit/392eeecc11a291e406db927a18b75f41b2658253)) - Choose whether repeatable reads or improved performance (less locking) is more important.
* **Dalli** ([commit](https://github.com/rails/rails/commit/82663306f428a5bbc90c511458432afb26d2f238)) - Use Dalli memcache client for the memcache store.
* **Notifications start &amp; finish** ([commit](https://github.com/rails/rails/commit/f08f8750a512f741acb004d0cebe210c5f949f28)) - Active Support instrumentation reports start and finish notifications to subscribers.
- * **Thread safe by default** ([commit](https://github.com/rails/rails/commit/5d416b907864d99af55ebaa400fff217e17570cd)) - Rails can run in threaded app servers without additional configuration. Note: Check that the gems you are using are threadsafe.
+ * **Thread safe by default** ([commit](https://github.com/rails/rails/commit/5d416b907864d99af55ebaa400fff217e17570cd)) - Rails can run in threaded app servers without additional configuration.
+
+NOTE: Check that the gems you are using are threadsafe.
+
* **PATCH verb** ([commit](https://github.com/rails/rails/commit/eed9f2539e3ab5a68e798802f464b8e4e95e619e)) - In Rails, PATCH replaces PUT. PATCH is used for partial updates of resources.
### Security
- * **match do not catch all** ([commit](https://github.com/rails/rails/commit/90d2802b71a6e89aedfe40564a37bd35f777e541)) - In the routing DSL, match requires the HTTP verb or verbs to be specified.
- * **html entities escaped by default** ([commit](https://github.com/rails/rails/commit/5f189f41258b83d49012ec5a0678d827327e7543)) - Strings rendered in erb are escaped unless wrapped with `raw` or `html_safe` is called.
- * **New security headers** ([commit](https://github.com/rails/rails/commit/6794e92b204572d75a07bd6413bdae6ae22d5a82)) - Rails sends the following headers with every HTTP request: `X-Frame-Options` (prevents clickjacking by forbidding the browser from embedding the page in a frame), `X-XSS-Protection` (asks the browser to halt script injection) and `X-Content-Type-Options` (prevents the browser from opening a jpeg as an exe).
+* **match do not catch all** ([commit](https://github.com/rails/rails/commit/90d2802b71a6e89aedfe40564a37bd35f777e541)) - In the routing DSL, match requires the HTTP verb or verbs to be specified.
+* **html entities escaped by default** ([commit](https://github.com/rails/rails/commit/5f189f41258b83d49012ec5a0678d827327e7543)) - Strings rendered in erb are escaped unless wrapped with `raw` or `html_safe` is called.
+* **New security headers** ([commit](https://github.com/rails/rails/commit/6794e92b204572d75a07bd6413bdae6ae22d5a82)) - Rails sends the following headers with every HTTP request: `X-Frame-Options` (prevents clickjacking by forbidding the browser from embedding the page in a frame), `X-XSS-Protection` (asks the browser to halt script injection) and `X-Content-Type-Options` (prevents the browser from opening a jpeg as an exe).
Extraction of features to gems
---------------------------
diff --git a/guides/source/4_2_release_notes.md b/guides/source/4_2_release_notes.md
index 366d9d26b4..684bd286bc 100644
--- a/guides/source/4_2_release_notes.md
+++ b/guides/source/4_2_release_notes.md
@@ -257,7 +257,7 @@ application is using any of these spellings, you will need to update them:
* Values in attribute selectors may need to be quoted if they contain
non-alphanumeric characters.
- ```
+ ```ruby
# before
a[href=/]
a[href$=/]
@@ -272,7 +272,7 @@ application is using any of these spellings, you will need to update them:
For example:
- ``` ruby
+ ```ruby
# content: <div><i><p></i></div>
# before:
@@ -290,7 +290,7 @@ application is using any of these spellings, you will need to update them:
used to be raw (e.g. `AT&amp;T`), and now is evaluated
(e.g. `AT&T`).
- ``` ruby
+ ```ruby
# content: <p>AT&amp;T</p>
# before:
@@ -302,6 +302,30 @@ application is using any of these spellings, you will need to update them:
assert_select('p', 'AT&amp;T') # => false
```
+Furthermore substitutions have changed syntax.
+
+Now you have to use a `:match` CSS-like selector:
+
+```ruby
+assert_select ":match('id', ?)", 'comment_1'
+```
+
+Additionally Regexp substitutions look different when the assertion fails.
+Notice how `/hello/` here:
+
+```ruby
+assert_select(":match('id', ?)", /hello/)
+```
+
+becomes `"(?-mix:hello)"`:
+
+```
+Expected at least 1 element matching "div:match('id', "(?-mix:hello)")", found 0..
+Expected 0 to be >= 1.
+```
+
+See the [Rails Dom Testing](https://github.com/rails/rails-dom-testing/tree/8798b9349fb9540ad8cb9a0ce6cb88d1384a210b) documentation for more on `assert_select`.
+
Railties
--------
diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md
index f68179841e..8c1551f4a1 100644
--- a/guides/source/action_controller_overview.md
+++ b/guides/source/action_controller_overview.md
@@ -9,7 +9,7 @@ After reading this guide, you will know:
* How to follow the flow of a request through a controller.
* How to restrict parameters passed to your controller.
-* Why and how to store data in the session or cookies.
+* How and why to store data in the session or cookies.
* How to work with filters to execute code during request processing.
* How to use Action Controller's built-in HTTP authentication.
* How to stream data directly to the user's browser.
@@ -21,11 +21,11 @@ After reading this guide, you will know:
What Does a Controller Do?
--------------------------
-Action Controller is the C in MVC. After routing has determined which controller to use for a request, your controller is responsible for making sense of the request and producing the appropriate output. Luckily, Action Controller does most of the groundwork for you and uses smart conventions to make this as straightforward as possible.
+Action Controller is the C in MVC. After routing has determined which controller to use for a request, the controller is responsible for making sense of the request and producing the appropriate output. Luckily, Action Controller does most of the groundwork for you and uses smart conventions to make this as straightforward as possible.
For most conventional [RESTful](http://en.wikipedia.org/wiki/Representational_state_transfer) applications, the controller will receive the request (this is invisible to you as the developer), fetch or save data from a model and use a view to create HTML output. If your controller needs to do things a little differently, that's not a problem, this is just the most common way for a controller to work.
-A controller can thus be thought of as a middle man between models and views. It makes the model data available to the view so it can display that data to the user, and it saves or updates data from the user to the model.
+A controller can thus be thought of as a middleman between models and views. It makes the model data available to the view so it can display that data to the user, and it saves or updates user data to the model.
NOTE: For more details on the routing process, see [Rails Routing from the Outside In](routing.html).
@@ -34,7 +34,7 @@ Controller Naming Convention
The naming convention of controllers in Rails favors pluralization of the last word in the controller's name, although it is not strictly required (e.g. `ApplicationController`). For example, `ClientsController` is preferable to `ClientController`, `SiteAdminsController` is preferable to `SiteAdminController` or `SitesAdminsController`, and so on.
-Following this convention will allow you to use the default route generators (e.g. `resources`, etc) without needing to qualify each `:path` or `:controller`, and keeps URL and path helpers' usage consistent throughout your application. See [Layouts & Rendering Guide](layouts_and_rendering.html) for more details.
+Following this convention will allow you to use the default route generators (e.g. `resources`, etc) without needing to qualify each `:path` or `:controller`, and will keep URL and path helpers' usage consistent throughout your application. See [Layouts & Rendering Guide](layouts_and_rendering.html) for more details.
NOTE: The controller naming convention differs from the naming convention of models, which are expected to be named in singular form.
@@ -51,7 +51,7 @@ class ClientsController < ApplicationController
end
```
-As an example, if a user goes to `/clients/new` in your application to add a new client, Rails will create an instance of `ClientsController` and run the `new` method. Note that the empty method from the example above would work just fine because Rails will by default render the `new.html.erb` view unless the action says otherwise. The `new` method could make available to the view a `@client` instance variable by creating a new `Client`:
+As an example, if a user goes to `/clients/new` in your application to add a new client, Rails will create an instance of `ClientsController` and call its `new` method. Note that the empty method from the example above would work just fine because Rails will by default render the `new.html.erb` view unless the action says otherwise. The `new` method could make available to the view a `@client` instance variable by creating a new `Client`:
```ruby
def new
@@ -63,7 +63,7 @@ The [Layouts & Rendering Guide](layouts_and_rendering.html) explains this in mor
`ApplicationController` inherits from `ActionController::Base`, which defines a number of helpful methods. This guide will cover some of these, but if you're curious to see what's in there, you can see all of them in the API documentation or in the source itself.
-Only public methods are callable as actions. It is a best practice to lower the visibility of methods which are not intended to be actions, like auxiliary methods or filters.
+Only public methods are callable as actions. It is a best practice to lower the visibility of methods (with `private` or `protected`) which are not intended to be actions, like auxiliary methods or filters.
Parameters
----------
@@ -104,13 +104,13 @@ end
### Hash and Array Parameters
-The `params` hash is not limited to one-dimensional keys and values. It can contain arrays and (nested) hashes. To send an array of values, append an empty pair of square brackets "[]" to the key name:
+The `params` hash is not limited to one-dimensional keys and values. It can contain nested arrays and hashes. To send an array of values, append an empty pair of square brackets "[]" to the key name:
```
GET /clients?ids[]=1&ids[]=2&ids[]=3
```
-NOTE: The actual URL in this example will be encoded as "/clients?ids%5b%5d=1&ids%5b%5d=2&ids%5b%5d=3" as "[" and "]" are not allowed in URLs. Most of the time you don't have to worry about this because the browser will take care of it for you, and Rails will decode it back when it receives it, but if you ever find yourself having to send those requests to the server manually you have to keep this in mind.
+NOTE: The actual URL in this example will be encoded as "/clients?ids%5b%5d=1&ids%5b%5d=2&ids%5b%5d=3" as the "[" and "]" characters are not allowed in URLs. Most of the time you don't have to worry about this because the browser will encode it for you, and Rails will decode it automatically, but if you ever find yourself having to send those requests to the server manually you should keep this in mind.
The value of `params[:ids]` will now be `["1", "2", "3"]`. Note that parameter values are always strings; Rails makes no attempt to guess or cast the type.
@@ -118,7 +118,7 @@ NOTE: Values such as `[nil]` or `[nil, nil, ...]` in `params` are replaced
with `[]` for security reasons by default. See [Security Guide](security.html#unsafe-query-generation)
for more information.
-To send a hash you include the key name inside the brackets:
+To send a hash, you include the key name inside the brackets:
```html
<form accept-charset="UTF-8" action="/clients" method="post">
@@ -131,11 +131,11 @@ To send a hash you include the key name inside the brackets:
When this form is submitted, the value of `params[:client]` will be `{ "name" => "Acme", "phone" => "12345", "address" => { "postcode" => "12345", "city" => "Carrot City" } }`. Note the nested hash in `params[:client][:address]`.
-Note that the `params` hash is actually an instance of `ActiveSupport::HashWithIndifferentAccess`, which acts like a hash but lets you use symbols and strings interchangeably as keys.
+The `params` object acts like a Hash, but lets you use symbols and strings interchangeably as keys.
### JSON parameters
-If you're writing a web service application, you might find yourself more comfortable accepting parameters in JSON format. If the "Content-Type" header of your request is set to "application/json", Rails will automatically convert your parameters into the `params` hash, which you can access as you would normally.
+If you're writing a web service application, you might find yourself more comfortable accepting parameters in JSON format. If the "Content-Type" header of your request is set to "application/json", Rails will automatically load your parameters into the `params` hash, which you can access as you would normally.
So for example, if you are sending this JSON content:
@@ -143,15 +143,15 @@ So for example, if you are sending this JSON content:
{ "company": { "name": "acme", "address": "123 Carrot Street" } }
```
-You'll get `params[:company]` as `{ "name" => "acme", "address" => "123 Carrot Street" }`.
+Your controller will receive `params[:company]` as `{ "name" => "acme", "address" => "123 Carrot Street" }`.
-Also, if you've turned on `config.wrap_parameters` in your initializer or calling `wrap_parameters` in your controller, you can safely omit the root element in the JSON parameter. The parameters will be cloned and wrapped in the key according to your controller's name by default. So the above parameter can be written as:
+Also, if you've turned on `config.wrap_parameters` in your initializer or called `wrap_parameters` in your controller, you can safely omit the root element in the JSON parameter. In this case, the parameters will be cloned and wrapped with a key chosen based on your controller's name. So the above JSON POST can be written as:
```json
{ "name": "acme", "address": "123 Carrot Street" }
```
-And assume that you're sending the data to `CompaniesController`, it would then be wrapped in `:company` key like this:
+And, assuming that you're sending the data to `CompaniesController`, it would then be wrapped within the `:company` key like this:
```ruby
{ name: "acme", address: "123 Carrot Street", company: { name: "acme", address: "123 Carrot Street" } }
@@ -159,17 +159,17 @@ And assume that you're sending the data to `CompaniesController`, it would then
You can customize the name of the key or specific parameters you want to wrap by consulting the [API documentation](http://api.rubyonrails.org/classes/ActionController/ParamsWrapper.html)
-NOTE: Support for parsing XML parameters has been extracted into a gem named `actionpack-xml_parser`
+NOTE: Support for parsing XML parameters has been extracted into a gem named `actionpack-xml_parser`.
### Routing Parameters
-The `params` hash will always contain the `:controller` and `:action` keys, but you should use the methods `controller_name` and `action_name` instead to access these values. Any other parameters defined by the routing, such as `:id` will also be available. As an example, consider a listing of clients where the list can show either active or inactive clients. We can add a route which captures the `:status` parameter in a "pretty" URL:
+The `params` hash will always contain the `:controller` and `:action` keys, but you should use the methods `controller_name` and `action_name` instead to access these values. Any other parameters defined by the routing, such as `:id`, will also be available. As an example, consider a listing of clients where the list can show either active or inactive clients. We can add a route which captures the `:status` parameter in a "pretty" URL:
```ruby
get '/clients/:status' => 'clients#index', foo: 'bar'
```
-In this case, when a user opens the URL `/clients/active`, `params[:status]` will be set to "active". When this route is used, `params[:foo]` will also be set to "bar" just like it was passed in the query string. In the same way `params[:action]` will contain "index".
+In this case, when a user opens the URL `/clients/active`, `params[:status]` will be set to "active". When this route is used, `params[:foo]` will also be set to "bar", as if it were passed in the query string. Your controller will also receive `params[:action]` as "index" and `params[:controller]` as "clients".
### `default_url_options`
@@ -183,21 +183,21 @@ class ApplicationController < ActionController::Base
end
```
-These options will be used as a starting point when generating URLs, so it's possible they'll be overridden by the options passed in `url_for` calls.
+These options will be used as a starting point when generating URLs, so it's possible they'll be overridden by the options passed to `url_for` calls.
-If you define `default_url_options` in `ApplicationController`, as in the example above, it would be used for all URL generation. The method can also be defined in one specific controller, in which case it only affects URLs generated there.
+If you define `default_url_options` in `ApplicationController`, as in the example above, it will be used for all URL generation. The method can also be defined in a specific controller, in which case it only affects URLs generated there.
### Strong Parameters
With strong parameters, Action Controller parameters are forbidden to
be used in Active Model mass assignments until they have been
-whitelisted. This means you'll have to make a conscious choice about
-which attributes to allow for mass updating and thus prevent
-accidentally exposing that which shouldn't be exposed.
+whitelisted. This means that you'll have to make a conscious decision about
+which attributes to allow for mass update. This is a better security
+practice to help prevent accidentally allowing users to update sensitive
+model attributes.
-In addition, parameters can be marked as required and flow through a
-predefined raise/rescue flow to end up as a 400 Bad Request with no
-effort.
+In addition, parameters can be marked as required and will flow through a
+predefined raise/rescue flow to end up as a 400 Bad Request.
```ruby
class PeopleController < ActionController::Base
@@ -239,17 +239,17 @@ params.permit(:id)
```
the key `:id` will pass the whitelisting if it appears in `params` and
-it has a permitted scalar value associated. Otherwise the key is going
+it has a permitted scalar value associated. Otherwise, the key is going
to be filtered out, so arrays, hashes, or any other objects cannot be
injected.
The permitted scalar types are `String`, `Symbol`, `NilClass`,
`Numeric`, `TrueClass`, `FalseClass`, `Date`, `Time`, `DateTime`,
-`StringIO`, `IO`, `ActionDispatch::Http::UploadedFile` and
+`StringIO`, `IO`, `ActionDispatch::Http::UploadedFile`, and
`Rack::Test::UploadedFile`.
To declare that the value in `params` must be an array of permitted
-scalar values map the key to an empty array:
+scalar values, map the key to an empty array:
```ruby
params.permit(id: [])
@@ -262,14 +262,13 @@ used:
params.require(:log_entry).permit!
```
-This will mark the `:log_entry` parameters hash and any sub-hash of it
-permitted. Extreme care should be taken when using `permit!` as it
-will allow all current and future model attributes to be
-mass-assigned.
+This will mark the `:log_entry` parameters hash and any sub-hash of it as
+permitted. Extreme care should be taken when using `permit!`, as it
+will allow all current and future model attributes to be mass-assigned.
#### Nested Parameters
-You can also use permit on nested parameters, like:
+You can also use `permit` on nested parameters, like:
```ruby
params.permit(:name, { emails: [] },
@@ -277,19 +276,19 @@ params.permit(:name, { emails: [] },
{ family: [ :name ], hobbies: [] }])
```
-This declaration whitelists the `name`, `emails` and `friends`
+This declaration whitelists the `name`, `emails`, and `friends`
attributes. It is expected that `emails` will be an array of permitted
-scalar values and that `friends` will be an array of resources with
-specific attributes : they should have a `name` attribute (any
+scalar values, and that `friends` will be an array of resources with
+specific attributes: they should have a `name` attribute (any
permitted scalar values allowed), a `hobbies` attribute as an array of
permitted scalar values, and a `family` attribute which is restricted
-to having a `name` (any permitted scalar values allowed, too).
+to having a `name` (any permitted scalar values allowed here, too).
#### More Examples
-You want to also use the permitted attributes in the `new`
+You may want to also use the permitted attributes in your `new`
action. This raises the problem that you can't use `require` on the
-root key because normally it does not exist when calling `new`:
+root key because, normally, it does not exist when calling `new`:
```ruby
# using `fetch` you can supply a default and use
@@ -297,8 +296,8 @@ root key because normally it does not exist when calling `new`:
params.fetch(:blog, {}).permit(:title, :author)
```
-`accepts_nested_attributes_for` allows you to update and destroy
-associated records. This is based on the `id` and `_destroy`
+The model class method `accepts_nested_attributes_for` allows you to
+update and destroy associated records. This is based on the `id` and `_destroy`
parameters:
```ruby
@@ -306,7 +305,7 @@ parameters:
params.require(:author).permit(:name, books_attributes: [:title, :id, :_destroy])
```
-Hashes with integer keys are treated differently and you can declare
+Hashes with integer keys are treated differently, and you can declare
the attributes as if they were direct children. You get these kinds of
parameters when you use `accepts_nested_attributes_for` in combination
with a `has_many` association:
@@ -323,13 +322,13 @@ params.require(:book).permit(:title, chapters_attributes: [:title])
#### Outside the Scope of Strong Parameters
The strong parameter API was designed with the most common use cases
-in mind. It is not meant as a silver bullet to handle all your
-whitelisting problems. However you can easily mix the API with your
+in mind. It is not meant as a silver bullet to handle all of your
+whitelisting problems. However, you can easily mix the API with your
own code to adapt to your situation.
Imagine a scenario where you have parameters representing a product
name and a hash of arbitrary data associated with that product, and
-you want to whitelist the product name attribute but also the whole
+you want to whitelist the product name attribute and also the whole
data hash. The strong parameters API doesn't let you directly
whitelist the whole of a nested hash with any keys, but you can use
the keys of your nested hash to declare what to whitelist:
diff --git a/guides/source/action_view_overview.md b/guides/source/action_view_overview.md
index 8f6676dc65..71f3f8882c 100644
--- a/guides/source/action_view_overview.md
+++ b/guides/source/action_view_overview.md
@@ -182,7 +182,7 @@ One way to use partials is to treat them as the equivalent of subroutines; a way
<p>Here are a few of our fine products:</p>
<% @products.each do |product| %>
- <%= render partial: "product", locals: {product: product} %>
+ <%= render partial: "product", locals: { product: product } %>
<% end %>
<%= render "shared/footer" %>
@@ -197,7 +197,7 @@ these are the only options you want to pass, you can skip using these options.
For example, instead of:
```erb
-<%= render partial: "product", locals: {product: @product} %>
+<%= render partial: "product", locals: { product: @product } %>
```
You can also do:
@@ -217,7 +217,7 @@ By default `ActionView::Partials::PartialRenderer` has its object in a local var
within product we'll get `@product` in the local variable `product`, as if we had written:
```erb
-<%= render partial: "product", locals: {product: @product} %>
+<%= render partial: "product", locals: { product: @product } %>
```
With the `as` option we can specify a different name for the local variable. For example, if we wanted it to be `item` instead of `product` we would do:
@@ -231,7 +231,7 @@ The `object` option can be used to directly specify which object is rendered int
For example, instead of:
```erb
-<%= render partial: "product", locals: {product: @item} %>
+<%= render partial: "product", locals: { product: @item } %>
```
we would do:
@@ -304,7 +304,7 @@ In the `show` template, we'll render the `_article` partial wrapped in the `box`
**articles/show.html.erb**
```erb
-<%= render partial: 'article', layout: 'box', locals: {article: @article} %>
+<%= render partial: 'article', layout: 'box', locals: { article: @article } %>
```
The `box` layout simply wraps the `_article` partial in a `div`:
@@ -344,7 +344,7 @@ You can also render a block of code within a partial layout instead of calling `
**articles/show.html.erb**
```html+erb
-<% render(layout: 'box', locals: {article: @article}) do %>
+<% render(layout: 'box', locals: { article: @article }) do %>
<%= div_for(article) do %>
<p><%= article.body %></p>
<% end %>
@@ -407,7 +407,7 @@ stylesheet_link_tag :monkey # =>
Returns a link tag that browsers and feed readers can use to auto-detect an RSS or Atom feed.
```ruby
-auto_discovery_link_tag(:rss, "http://www.example.com/feed.rss", {title: "RSS Feed"}) # =>
+auto_discovery_link_tag(:rss, "http://www.example.com/feed.rss", { title: "RSS Feed" }) # =>
<link rel="alternate" type="application/rss+xml" title="RSS Feed" href="http://www.example.com/feed" />
```
@@ -789,7 +789,7 @@ time_select("order", "submitted")
Returns a `pre` tag that has object dumped by YAML. This creates a very readable way to inspect an object.
```ruby
-my_hash = {'first' => 1, 'second' => 'two', 'third' => [1,2,3]}
+my_hash = { 'first' => 1, 'second' => 'two', 'third' => [1,2,3] }
debug(my_hash)
```
@@ -814,7 +814,7 @@ The core method of this helper, form_for, gives you the ability to create a form
```html+erb
# Note: a @person variable will have been created in the controller (e.g. @person = Person.new)
-<%= form_for @person, url: {action: "create"} do |f| %>
+<%= form_for @person, url: { action: "create" } do |f| %>
<%= f.text_field :first_name %>
<%= f.text_field :last_name %>
<%= submit_tag 'Create' %>
@@ -834,7 +834,7 @@ The HTML generated for this would be:
The params object created when this form is submitted would look like:
```ruby
-{"action" => "create", "controller" => "people", "person" => {"first_name" => "William", "last_name" => "Smith"}}
+{ "action" => "create", "controller" => "people", "person" => { "first_name" => "William", "last_name" => "Smith" } }
```
The params hash has a nested person value, which can therefore be accessed with params[:person] in the controller.
@@ -855,7 +855,7 @@ check_box("article", "validated")
Creates a scope around a specific model object like form_for, but doesn't create the form tags themselves. This makes fields_for suitable for specifying additional model objects in the same form:
```html+erb
-<%= form_for @person, url: {action: "update"} do |person_form| %>
+<%= form_for @person, url: { action: "update" } do |person_form| %>
First name: <%= person_form.text_field :first_name %>
Last name : <%= person_form.text_field :last_name %>
@@ -990,7 +990,7 @@ end
Sample usage (selecting the associated Author for an instance of Article, `@article`):
```ruby
-collection_select(:article, :author_id, Author.all, :id, :name_with_initial, {prompt: true})
+collection_select(:article, :author_id, Author.all, :id, :name_with_initial, { prompt: true })
```
If `@article.author_id` is 1, this would return:
@@ -1162,7 +1162,7 @@ Create a select tag and a series of contained option tags for the provided objec
Example:
```ruby
-select("article", "person_id", Person.all.collect {|p| [ p.name, p.id ] }, {include_blank: true})
+select("article", "person_id", Person.all.collect { |p| [ p.name, p.id ] }, { include_blank: true })
```
If `@article.person_id` is 1, this would become:
@@ -1225,7 +1225,7 @@ Creates a field set for grouping HTML form elements.
Creates a file upload field.
```html+erb
-<%= form_tag({action:"post"}, multipart: true) do %>
+<%= form_tag({ action: "post" }, multipart: true) do %>
<label for="file">File to Upload</label> <%= file_field_tag "file" %>
<%= submit_tag %>
<% end %>
diff --git a/guides/source/active_record_basics.md b/guides/source/active_record_basics.md
index bd8cdf62f2..6551ba0389 100644
--- a/guides/source/active_record_basics.md
+++ b/guides/source/active_record_basics.md
@@ -20,7 +20,7 @@ After reading this guide, you will know:
What is Active Record?
----------------------
-Active Record is the M in [MVC](getting_started.html#the-mvc-architecture) - the
+Active Record is the M in [MVC](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) - the
model - which is the layer of the system responsible for representing business
data and logic. Active Record facilitates the creation and use of business
objects whose data requires persistent storage to a database. It is an
@@ -122,7 +122,7 @@ to Active Record instances:
* `(association_name)_type` - Stores the type for
[polymorphic associations](association_basics.html#polymorphic-associations).
* `(table_name)_count` - Used to cache the number of belonging objects on
- associations. For example, a `comments_count` column in a `Articles` class that
+ associations. For example, a `comments_count` column in an `Article` class that
has many instances of `Comment` will cache the number of existent comments
for each article.
@@ -173,18 +173,18 @@ name that should be used:
```ruby
class Product < ActiveRecord::Base
- self.table_name = "PRODUCT"
+ self.table_name = "my_products"
end
```
If you do so, you will have to define manually the class name that is hosting
-the fixtures (class_name.yml) using the `set_fixture_class` method in your test
+the fixtures (my_products.yml) using the `set_fixture_class` method in your test
definition:
```ruby
-class FunnyJoke < ActiveSupport::TestCase
- set_fixture_class funny_jokes: Joke
- fixtures :funny_jokes
+class ProductTest < ActiveSupport::TestCase
+ set_fixture_class my_products: Product
+ fixtures :my_products
...
end
```
diff --git a/guides/source/active_record_callbacks.md b/guides/source/active_record_callbacks.md
index e65ab802c0..13989a3b33 100644
--- a/guides/source/active_record_callbacks.md
+++ b/guides/source/active_record_callbacks.md
@@ -68,7 +68,7 @@ class User < ActiveRecord::Base
protected
def normalize_name
- self.name = self.name.downcase.titleize
+ self.name = name.downcase.titleize
end
def set_location
diff --git a/guides/source/active_record_migrations.md b/guides/source/active_record_migrations.md
index b8db21a989..de8bbc4174 100644
--- a/guides/source/active_record_migrations.md
+++ b/guides/source/active_record_migrations.md
@@ -241,7 +241,7 @@ generates
```ruby
class AddUserRefToProducts < ActiveRecord::Migration
def change
- add_reference :products, :user, index: true
+ add_reference :products, :user, index: true, foreign_key: true
end
end
```
@@ -357,7 +357,7 @@ will append `ENGINE=BLACKHOLE` to the SQL statement used to create the table
### Creating a Join Table
-Migration method `create_join_table` creates a HABTM join table. A typical use
+Migration method `create_join_table` creates an HABTM join table. A typical use
would be:
```ruby
@@ -425,7 +425,7 @@ change_column :products, :part_number, :text
This changes the column `part_number` on products table to be a `:text` field.
Besides `change_column`, the `change_column_null` and `change_column_default`
-methods are used specifically to change the null and default values of a
+methods are used specifically to change a not null constraint and default values of a
column.
```ruby
@@ -539,6 +539,14 @@ definitions:
`change_table` is also reversible, as long as the block does not call `change`,
`change_default` or `remove`.
+`remove_column` is reversible if you supply the column type as the third
+argument. Provide the original column options too, otherwise Rails can't
+recreate the column exactly when rolling back:
+
+```ruby
+remove_column :posts, :slug, :string, null: false, default: '', index: true
+```
+
If you're going to need to use any other methods, you should use `reversible`
or write the `up` and `down` methods instead of using the `change` method.
diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md
index e5a962b739..d6f3506aa5 100644
--- a/guides/source/active_record_querying.md
+++ b/guides/source/active_record_querying.md
@@ -348,7 +348,7 @@ Another example would be if you wanted multiple workers handling the same proces
Similar to the `:begin_at` option, `:end_at` allows you to configure the last ID of the sequence whenever the highest ID is not the one you need.
This would be useful, for example, if you wanted to run a batch process, using a subset of records based on `:begin_at` and `:end_at`
-For example, to send newsletters only to users with the primary key starting from 2000 upto 10000 and to retrieve them in batches of 1000:
+For example, to send newsletters only to users with the primary key starting from 2000 up to 10000 and to retrieve them in batches of 1000:
```ruby
User.find_each(begin_at: 2000, end_at: 10000, batch_size: 5000) do |user|
@@ -1343,7 +1343,7 @@ Client.unscoped {
Dynamic Finders
---------------
-For every field (also known as an attribute) you define in your table, Active Record provides a finder method. If you have a field called `first_name` on your `Client` model for example, you get `find_by_first_name` for free from Active Record. If you have a `locked` field on the `Client` model, you also get `find_by_locked` and methods.
+For every field (also known as an attribute) you define in your table, Active Record provides a finder method. If you have a field called `first_name` on your `Client` model for example, you get `find_by_first_name` for free from Active Record. If you have a `locked` field on the `Client` model, you also get `find_by_locked` method.
You can specify an exclamation point (`!`) on the end of the dynamic finders to get them to raise an `ActiveRecord::RecordNotFound` error if they do not return any records, like `Client.find_by_name!("Ryan")`
diff --git a/guides/source/active_record_validations.md b/guides/source/active_record_validations.md
index f19934fe89..d251c5c0b1 100644
--- a/guides/source/active_record_validations.md
+++ b/guides/source/active_record_validations.md
@@ -1055,7 +1055,9 @@ person.errors[:name]
### `errors.add`
-The `add` method lets you manually add messages that are related to particular attributes. You can use the `errors.full_messages` or `errors.to_a` methods to view the messages in the form they might be displayed to a user. Those particular messages get the attribute name prepended (and capitalized). `add` receives the name of the attribute you want to add the message to, and the message itself.
+The `add` method lets you add an error message related to a particular attribute. It takes as arguments the attribute and the error message.
+
+The `errors.full_messages` method (or its equivalent, `errors.to_a`) returns the error messages in a user-friendly format, with the capitalized attribute name prepended to each message, as shown in the examples below.
```ruby
class Person < ActiveRecord::Base
@@ -1073,12 +1075,12 @@ person.errors.full_messages
# => ["Name cannot contain the characters !@#%*()_-+="]
```
-Another way to do this is using `[]=` setter
+An equivalent to `errors#add` is to use `<<` to append a message to the `errors.messages` array for an attribute:
```ruby
class Person < ActiveRecord::Base
def a_method_used_for_validation_purposes
- errors.add(:name, "cannot contain the characters !@#%*()_-+=")
+ errors.messages[:name] << "cannot contain the characters !@#%*()_-+="
end
end
diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md
index 66626f41d1..f3d8e05089 100644
--- a/guides/source/active_support_core_extensions.md
+++ b/guides/source/active_support_core_extensions.md
@@ -506,6 +506,8 @@ Extensions to `Module`
### `alias_method_chain`
+**This method is deprecated in favour of using Module#prepend.**
+
Using plain Ruby you can wrap methods with other methods, that's called _alias chaining_.
For example, let's say you'd like params to be strings in functional tests, as they are in real requests, but still want the convenience of assigning integers and other kind of values. To accomplish that you could wrap `ActionController::TestCase#process` this way in `test/test_helper.rb`:
@@ -550,8 +552,6 @@ ActionController::TestCase.class_eval do
end
```
-Rails uses `alias_method_chain` all over the code base. For example validations are added to `ActiveRecord::Base#save` by wrapping the method that way in a separate module specialized in validations.
-
NOTE: Defined in `active_support/core_ext/module/aliasing.rb`.
### Attributes
diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md
index 6f8b4f4d15..9da0ef1eb3 100644
--- a/guides/source/asset_pipeline.md
+++ b/guides/source/asset_pipeline.md
@@ -149,7 +149,7 @@ clients to fetch them again, even when the content of those assets has not chang
Fingerprinting fixes these problems by avoiding query strings, and by ensuring
that filenames are consistent based on their content.
-Fingerprinting is enabled by default for both the development and production
+Fingerprinting is enabled by default for both the development and production
environments. You can enable or disable it in your configuration through the
`config.assets.digest` option.
@@ -209,7 +209,7 @@ precompiling works.
NOTE: You must have an ExecJS supported runtime in order to use CoffeeScript.
If you are using Mac OS X or Windows, you have a JavaScript runtime installed in
-your operating system. Check [ExecJS](https://github.com/sstephenson/execjs#readme) documentation to know all supported JavaScript runtimes.
+your operating system. Check [ExecJS](https://github.com/rails/execjs#readme) documentation to know all supported JavaScript runtimes.
You can also disable generation of controller specific asset files by adding the
following to your `config/application.rb` configuration:
@@ -667,8 +667,7 @@ anymore, delete these options from the `javascript_include_tag` and
`stylesheet_link_tag`.
The fingerprinting behavior is controlled by the `config.assets.digest`
-initialization option (which defaults to `true` for production and `false` for
-everything else).
+initialization option (which defaults to `true` for production and development).
NOTE: Under normal circumstances the default `config.assets.digest` option
should not be changed. If there are no digests in the filenames, and far-future
@@ -921,7 +920,7 @@ focus on serving application code as fast as possible.
#### Set up a CDN to Serve Static Assets
To set up your CDN you have to have your application running in production on
-the internet at a publically available URL, for example `example.com`. Next
+the internet at a publicly available URL, for example `example.com`. Next
you'll need to sign up for a CDN service from a cloud hosting provider. When you
do this you need to configure the "origin" of the CDN to point back at your
website `example.com`, check your provider for documentation on configuring the
@@ -974,7 +973,7 @@ http://mycdnsubdomain.fictional-cdn.com/assets/smile.png
If the CDN has a copy of `smile.png` it will serve it to the browser and your
server doesn't even know it was requested. If the CDN does not have a copy it
-will try to find it a the "origin" `example.com/assets/smile.png` and then store
+will try to find it at the "origin" `example.com/assets/smile.png` and then store
it for future use.
If you want to serve only some assets from your CDN, you can use custom `:host`
@@ -1137,7 +1136,7 @@ The following line invokes `uglifier` for JavaScript compression.
config.assets.js_compressor = :uglifier
```
-NOTE: You will need an [ExecJS](https://github.com/sstephenson/execjs#readme)
+NOTE: You will need an [ExecJS](https://github.com/rails/execjs#readme)
supported runtime in order to use `uglifier`. If you are using Mac OS X or
Windows you have a JavaScript runtime installed in your operating system.
diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md
index 280c3008e9..ec6017ff73 100644
--- a/guides/source/association_basics.md
+++ b/guides/source/association_basics.md
@@ -933,7 +933,7 @@ Passing `true` to the `:polymorphic` option indicates that this is a polymorphic
##### `:touch`
-If you set the `:touch` option to `:true`, then the `updated_at` or `updated_on` timestamp on the associated object will be set to the current time whenever this object is saved or destroyed:
+If you set the `:touch` option to `true`, then the `updated_at` or `updated_on` timestamp on the associated object will be set to the current time whenever this object is saved or destroyed:
```ruby
class Order < ActiveRecord::Base
@@ -1496,7 +1496,7 @@ While Rails uses intelligent defaults that will work well in most situations, th
```ruby
class Customer < ActiveRecord::Base
- has_many :orders, dependent: :delete_all, validate: :false
+ has_many :orders, dependent: :delete_all, validate: false
end
```
diff --git a/guides/source/autoloading_and_reloading_constants.md b/guides/source/autoloading_and_reloading_constants.md
index 9e78eebf82..c6149abcba 100644
--- a/guides/source/autoloading_and_reloading_constants.md
+++ b/guides/source/autoloading_and_reloading_constants.md
@@ -465,7 +465,10 @@ by adding this to `config/application.rb`:
```ruby
config.autoload_paths << "#{Rails.root}/lib"
```
-`config.autoload_paths` is accessible from environment-specific configuration files, but any changes made to it outside `config/application.rb` don't have an effect.
+
+`config.autoload_paths` is accessible from environment-specific configuration
+files, but any changes made to it outside `config/application.rb` don't have any
+effect.
The value of `autoload_paths` can be inspected. In a just generated application
it is (edited):
diff --git a/guides/source/command_line.md b/guides/source/command_line.md
index 6f5a6b7957..b409f20122 100644
--- a/guides/source/command_line.md
+++ b/guides/source/command_line.md
@@ -402,7 +402,7 @@ INFO: You can also use `rake -T` to get the list of tasks.
$ bin/rake about
About your application's environment
Rails version 5.0.0
-Ruby version 2.2.0 (x86_64-linux)
+Ruby version 2.2.1 (x86_64-linux)
RubyGems version 2.4.5
Rack version 1.6
JavaScript Runtime Node.js (V8)
@@ -526,8 +526,8 @@ end
To pass arguments to your custom rake task:
```ruby
-task :task_name, [:arg_1] => [:pre_1, :pre_2] do |t, args|
- # You can use args from here
+task :task_name, [:arg_1] => [:prerequisite_1, :prerequisite_2] do |task, args|
+ argument_1 = args.arg_1
end
```
diff --git a/guides/source/configuring.md b/guides/source/configuring.md
index 4fc1301e06..6f32e6484f 100644
--- a/guides/source/configuring.md
+++ b/guides/source/configuring.md
@@ -110,7 +110,9 @@ numbers. New applications filter out passwords by adding the following `config.f
* `config.log_formatter` defines the formatter of the Rails logger. This option defaults to an instance of `ActiveSupport::Logger::SimpleFormatter` for all modes except production, where it defaults to `Logger::Formatter`.
-* `config.log_level` defines the verbosity of the Rails logger. This option defaults to `:debug` for all environments. The available log levels are: :debug, :info, :warn, :error, :fatal, and :unknown.
+* `config.log_level` defines the verbosity of the Rails logger. This option
+defaults to `:debug` for all environments. The available log levels are: `:debug`,
+`:info`, `:warn`, `:error`, `:fatal`, and `:unknown`.
* `config.log_tags` accepts a list of methods that the `request` object responds to. This makes it easy to tag log lines with debug information like subdomain and request id - both very helpful in debugging multi-user production applications.
@@ -286,7 +288,7 @@ All these configuration options are delegated to the `I18n` library.
* `config.active_record.lock_optimistically` controls whether Active Record will use optimistic locking and is true by default.
-* `config.active_record.cache_timestamp_format` controls the format of the timestamp value in the cache key. Default is `:number`.
+* `config.active_record.cache_timestamp_format` controls the format of the timestamp value in the cache key. Default is `:nsec`.
* `config.active_record.record_timestamps` is a boolean value which controls whether or not timestamping of `create` and `update` operations on a model occur. The default value is `true`.
@@ -300,8 +302,18 @@ All these configuration options are delegated to the `I18n` library.
`config/environments/production.rb` which is generated by Rails. The
default value is true if this configuration is not set.
+* `config.active_record.dump_schemas` controls which database schemas will be dumped when calling db:structure:dump.
+ The options are `:schema_search_path` (the default) which dumps any schemas listed in schema_search_path,
+ `:all` which always dumps all schemas regardless of the schema_search_path,
+ or a string of comma separated schemas.
+
* `config.active_record.belongs_to_required_by_default` is a boolean value and controls whether `belongs_to` association is required by default.
+* `config.active_record.warn_on_records_fetched_greater_than` allows setting a
+ warning threshold for query result size. If the number of records returned
+ by a query exceeds the threshold, a warning is logged. This can be used to
+ identify queries which might be causing memory bloat.
+
The MySQL adapter adds one additional configuration option:
* `ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans` controls whether Active Record will consider all `tinyint(1)` columns in a MySQL database to be booleans and is true by default.
@@ -975,8 +987,6 @@ Below is a comprehensive list of all the initializers found in Rails in the orde
* `load_environment_config` Loads the `config/environments` file for the current environment.
-* `append_asset_paths` Finds asset paths for the application and all attached railties and keeps a track of the available directories in `config.static_asset_paths`.
-
* `prepend_helpers_path` Adds the directory `app/helpers` from the application, railties and engines to the lookup path for helpers for the application.
* `load_config_initializers` Loads all Ruby files from `config/initializers` in the application, railties and engines. The files in this directory can be used to hold configuration settings that should be made after all of the frameworks are loaded.
diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md
index 32d1e2c6e7..018100c316 100644
--- a/guides/source/contributing_to_ruby_on_rails.md
+++ b/guides/source/contributing_to_ruby_on_rails.md
@@ -244,11 +244,11 @@ This will generate a report with the following information:
```
Calculating -------------------------------------
- addition 69114 i/100ms
- addition with send 64062 i/100ms
+ addition 132.013k i/100ms
+ addition with send 125.413k i/100ms
-------------------------------------------------
- addition 5307644.4 (±3.5%) i/s - 26539776 in 5.007219s
- addition with send 3702897.9 (±3.5%) i/s - 18513918 in 5.006723s
+ addition 9.677M (± 1.7%) i/s - 48.449M
+ addition with send 6.794M (± 1.1%) i/s - 33.987M
```
Please see the benchmark/ips [README](https://github.com/evanphx/benchmark-ips/blob/master/README.md) for more information.
@@ -378,7 +378,7 @@ Your name can be added directly after the last word if you don't provide any cod
### Updating the Gemfile.lock
-Some changes requires the dependencies to be upgraded. In these cases make sure you run `bundle update` to get the right version of the dependency and commit the `Gemfile.lock` file within your changes.
+Some changes require the dependencies to be upgraded. In these cases make sure you run `bundle update` to get the right version of the dependency and commit the `Gemfile.lock` file within your changes.
### Sanity Check
diff --git a/guides/source/debugging_rails_applications.md b/guides/source/debugging_rails_applications.md
index 9cb2efb9a2..a9715fb837 100644
--- a/guides/source/debugging_rails_applications.md
+++ b/guides/source/debugging_rails_applications.md
@@ -815,7 +815,7 @@ calling the `console` method.
For example, in a controller:
```ruby
-class PostController < ApplicationController
+class PostsController < ApplicationController
def new
console
@post = Post.new
diff --git a/guides/source/form_helpers.md b/guides/source/form_helpers.md
index c21a2ba613..853227e2a1 100644
--- a/guides/source/form_helpers.md
+++ b/guides/source/form_helpers.md
@@ -241,7 +241,7 @@ Upon form submission the value entered by the user will be stored in `params[:pe
WARNING: You must pass the name of an instance variable, i.e. `:person` or `"person"`, not an actual instance of your model object.
-Rails provides helpers for displaying the validation errors associated with a model object. These are covered in detail by the [Active Record Validations](./active_record_validations.html#displaying-validation-errors-in-views) guide.
+Rails provides helpers for displaying the validation errors associated with a model object. These are covered in detail by the [Active Record Validations](active_record_validations.html#displaying-validation-errors-in-views) guide.
### Binding a Form to an Object
@@ -282,7 +282,7 @@ The resulting HTML is:
</form>
```
-The name passed to `form_for` controls the key used in `params` to access the form's values. Here the name is `article` and so all the inputs have names of the form `article[attribute_name]`. Accordingly, in the `create` action `params[:article]` will be a hash with keys `:title` and `:body`. You can read more about the significance of input names in the parameter_names section.
+The name passed to `form_for` controls the key used in `params` to access the form's values. Here the name is `article` and so all the inputs have names of the form `article[attribute_name]`. Accordingly, in the `create` action `params[:article]` will be a hash with keys `:title` and `:body`. You can read more about the significance of input names in the [parameter_names section](#understanding-parameter-naming-conventions).
The helper methods called on the form builder are identical to the model object helpers except that it is not necessary to specify which object is being edited since this is already managed by the form builder.
diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md
index 66cfb72aaf..db4e81e32e 100644
--- a/guides/source/getting_started.md
+++ b/guides/source/getting_started.md
@@ -204,7 +204,7 @@ Rails adds the `therubyracer` gem to the generated `Gemfile` in a
commented line for new apps and you can uncomment if you need it.
`therubyrhino` is the recommended runtime for JRuby users and is added by
default to the `Gemfile` in apps generated under JRuby. You can investigate
-all the supported runtimes at [ExecJS](https://github.com/sstephenson/execjs#readme).
+all the supported runtimes at [ExecJS](https://github.com/rails/execjs#readme).
This will fire up WEBrick, a web server distributed with Ruby by default. To see
your application in action, open a browser window and navigate to
@@ -321,9 +321,9 @@ root 'welcome#index'
application to the welcome controller's index action and `get 'welcome/index'`
tells Rails to map requests to <http://localhost:3000/welcome/index> to the
welcome controller's index action. This was created earlier when you ran the
-controller generator (`rails generate controller welcome index`).
+controller generator (`bin/rails generate controller welcome index`).
-Launch the web server again if you stopped it to generate the controller (`rails
+Launch the web server again if you stopped it to generate the controller (`bin/rails
server`) and navigate to <http://localhost:3000> in your browser. You'll see the
"Hello, Rails!" message you put into `app/views/welcome/index.html.erb`,
indicating that this new route is indeed going to `WelcomeController`'s `index`
@@ -356,7 +356,7 @@ Rails.application.routes.draw do
end
```
-If you run `rake routes`, you'll see that it has defined routes for all the
+If you run `bin/rake routes`, you'll see that it has defined routes for all the
standard RESTful actions. The meaning of the prefix column (and other columns)
will be seen later, but for now notice that Rails has inferred the
singular form `article` and makes meaningful use of the distinction.
@@ -556,7 +556,7 @@ this:
In this example, the `articles_path` helper is passed to the `:url` option.
To see what Rails will do with this, we look back at the output of
-`rake routes`:
+`bin/rake routes`:
```bash
$ bin/rake routes
@@ -666,7 +666,7 @@ models, as that will be done automatically by Active Record.
### Running a Migration
-As we've just seen, `rails generate model` created a _database migration_ file
+As we've just seen, `bin/rails generate model` created a _database migration_ file
inside the `db/migrate` directory. Migrations are Ruby classes that are
designed to make it simple to create and modify database tables. Rails uses
rake commands to run migrations, and it's possible to undo a migration after
@@ -719,7 +719,7 @@ NOTE. Because you're working in the development environment by default, this
command will apply to the database defined in the `development` section of your
`config/database.yml` file. If you would like to execute migrations in another
environment, for instance in production, you must explicitly pass it when
-invoking the command: `rake db:migrate RAILS_ENV=production`.
+invoking the command: `bin/rake db:migrate RAILS_ENV=production`.
### Saving data in the controller
@@ -806,7 +806,7 @@ If you submit the form again now, Rails will complain about not finding the
`show` action. That's not very useful though, so let's add the `show` action
before proceeding.
-As we have seen in the output of `rake routes`, the route for `show` action is
+As we have seen in the output of `bin/rake routes`, the route for `show` action is
as follows:
```
@@ -868,7 +868,7 @@ Visit <http://localhost:3000/articles/new> and give it a try!
### Listing all articles
We still need a way to list all our articles, so let's do that.
-The route for this as per output of `rake routes` is:
+The route for this as per output of `bin/rake routes` is:
```
articles GET /articles(.:format) articles#index
@@ -1363,7 +1363,7 @@ Then do the same for the `app/views/articles/edit.html.erb` view:
We're now ready to cover the "D" part of CRUD, deleting articles from the
database. Following the REST convention, the route for
-deleting articles as per output of `rake routes` is:
+deleting articles as per output of `bin/rake routes` is:
```ruby
DELETE /articles/:id(.:format) articles#destroy
@@ -1482,9 +1482,9 @@ Here we're using `link_to` in a different way. We pass the named route as the
second argument, and then the options as another argument. The `method: :delete`
and `data: { confirm: 'Are you sure?' }` options are used as HTML5 attributes so
that when the link is clicked, Rails will first show a confirm dialog to the
-user, and then submit the link with method `delete`. This is done via the
+user, and then submit the link with method `delete`. This is done via the
JavaScript file `jquery_ujs` which is automatically included in your
-application's layout (`app/views/layouts/application.html.erb`) when you
+application's layout (`app/views/layouts/application.html.erb`) when you
generated the application. Without this file, the confirmation dialog box won't
appear.
@@ -1510,7 +1510,7 @@ comments on articles.
We're going to see the same generator that we used before when creating
the `Article` model. This time we'll create a `Comment` model to hold
-reference of article comments. Run this command in your terminal:
+reference to an article. Run this command in your terminal:
```bash
$ bin/rails generate model Comment commenter:string body:text article:references
@@ -1522,7 +1522,7 @@ This command will generate four files:
| -------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| db/migrate/20140120201010_create_comments.rb | Migration to create the comments table in your database (your name will include a different timestamp) |
| app/models/comment.rb | The Comment model |
-| test/models/comment_test.rb | Testing harness for the comments model |
+| test/models/comment_test.rb | Testing harness for the comment model |
| test/fixtures/comments.yml | Sample comments for use in testing |
First, take a look at `app/models/comment.rb`:
diff --git a/guides/source/i18n.md b/guides/source/i18n.md
index 1e34261272..e8d0a83dd0 100644
--- a/guides/source/i18n.md
+++ b/guides/source/i18n.md
@@ -707,7 +707,7 @@ you can safely pass the username as set by the user:
```erb
<%# This is safe, it is going to be escaped if needed. %>
-<%= t('welcome_html', username: @current_user.username %>
+<%= t('welcome_html', username: @current_user.username) %>
```
Safe strings on the other hand are interpolated verbatim.
diff --git a/guides/source/layouts_and_rendering.md b/guides/source/layouts_and_rendering.md
index 5c7fad09ed..c57fa358d6 100644
--- a/guides/source/layouts_and_rendering.md
+++ b/guides/source/layouts_and_rendering.md
@@ -428,12 +428,13 @@ Rails understands both numeric status codes and the corresponding symbols shown
| | 510 | :not_extended |
| | 511 | :network_authentication_required |
-NOTE: If you try to render content along with a non-content status code
+NOTE: If you try to render content along with a non-content status code
(100-199, 204, 205 or 304), it will be dropped from the response.
##### The `:formats` Option
-Rails uses the format specified in request (or `:html` by default). You can change this adding the `:formats` option with a symbol or an array:
+Rails uses the format specified in the request (or `:html` by default). You can
+change this passing the `:formats` option with a symbol or an array:
```ruby
render formats: :xml
@@ -589,7 +590,7 @@ The lookup order for a `admin/products#index` action will be:
* `app/views/admin/`
* `app/views/application/`
-This makes `app/views/application/` a great place for your shared partials, which can then be rendered in your ERb as such:
+This makes `app/views/application/` a great place for your shared partials, which can then be rendered in your ERB as such:
```erb
<%# app/views/admin/products/index.html.erb %>
diff --git a/guides/source/plugins.md b/guides/source/plugins.md
index 10738320ef..4e630a39f3 100644
--- a/guides/source/plugins.md
+++ b/guides/source/plugins.md
@@ -265,7 +265,7 @@ module Yaffle
end
end
-ActiveRecord::Base.send :include, Yaffle::ActsAsYaffle
+ActiveRecord::Base.include(Yaffle::ActsAsYaffle)
```
You can then return to the root directory (`cd ../..`) of your plugin and rerun the tests using `rake`.
@@ -308,7 +308,7 @@ module Yaffle
end
end
-ActiveRecord::Base.send :include, Yaffle::ActsAsYaffle
+ActiveRecord::Base.include(Yaffle::ActsAsYaffle)
```
When you run `rake`, you should see the tests all pass:
@@ -382,7 +382,7 @@ module Yaffle
end
end
-ActiveRecord::Base.send :include, Yaffle::ActsAsYaffle
+ActiveRecord::Base.include(Yaffle::ActsAsYaffle)
```
Run `rake` one final time and you should see:
diff --git a/guides/source/routing.md b/guides/source/routing.md
index b5defc9d20..7d0a3efbe7 100644
--- a/guides/source/routing.md
+++ b/guides/source/routing.md
@@ -909,7 +909,7 @@ The `:as` option lets you override the normal naming for the named route helpers
resources :photos, as: 'images'
```
-will recognize incoming paths beginning with `/photos` and route the requests to `PhotosController`, but use the value of the :as option to name the helpers.
+will recognize incoming paths beginning with `/photos` and route the requests to `PhotosController`, but use the value of the `:as` option to name the helpers.
| HTTP Verb | Path | Controller#Action | Named Helper |
| --------- | ---------------- | ----------------- | -------------------- |
@@ -1006,7 +1006,7 @@ TIP: If your application has many RESTful routes, using `:only` and `:except` to
### Translated Paths
-Using `scope`, we can alter path names generated by resources:
+Using `scope`, we can alter path names generated by `resources`:
```ruby
scope(path_names: { new: 'neu', edit: 'bearbeiten' }) do
diff --git a/guides/source/security.md b/guides/source/security.md
index e486edde31..184af98d65 100644
--- a/guides/source/security.md
+++ b/guides/source/security.md
@@ -710,7 +710,7 @@ The log files on www.attacker.com will read like this:
GET http://www.attacker.com/_app_session=836c1c25278e5b321d6bea4f19cb57e2
```
-You can mitigate these attacks (in the obvious way) by adding the [httpOnly](http://dev.rubyonrails.org/ticket/8895) flag to cookies, so that document.cookie may not be read by JavaScript. Http only cookies can be used from IE v6.SP1, Firefox v2.0.0.5 and Opera 9.5. Safari is still considering, it ignores the option. But other, older browsers (such as WebTV and IE 5.5 on Mac) can actually cause the page to fail to load. Be warned that cookies [will still be visible using Ajax](http://ha.ckers.org/blog/20070719/firefox-implements-httponly-and-is-vulnerable-to-xmlhttprequest/), though.
+You can mitigate these attacks (in the obvious way) by adding the **httpOnly** flag to cookies, so that document.cookie may not be read by JavaScript. Http only cookies can be used from IE v6.SP1, Firefox v2.0.0.5 and Opera 9.5. Safari is still considering, it ignores the option. But other, older browsers (such as WebTV and IE 5.5 on Mac) can actually cause the page to fail to load. Be warned that cookies [will still be visible using Ajax](http://ha.ckers.org/blog/20070719/firefox-implements-httponly-and-is-vulnerable-to-xmlhttprequest/), though.
##### Defacement
diff --git a/guides/source/testing.md b/guides/source/testing.md
index cb3bd68fbe..752ef48b16 100644
--- a/guides/source/testing.md
+++ b/guides/source/testing.md
@@ -59,9 +59,9 @@ You can find comprehensive documentation in the [Fixtures API documentation](htt
#### What Are Fixtures?
-_Fixtures_ is a fancy word for sample data. Fixtures allow you to populate your testing database with predefined data before your tests run. Fixtures are database independent written in YAML. There is one file per model.
+_Fixtures_ is a fancy word for sample data. Fixtures allow you to populate your testing database with predefined data before your tests run. Fixtures are database independent and written in YAML. There is one file per model.
-You'll find fixtures under your `test/fixtures` directory. When you run `rails generate model` to create a new model fixture stubs will be automatically created and placed in this directory.
+You'll find fixtures under your `test/fixtures` directory. When you run `rails generate model` to create a new model, Rails automatically creates fixture stubs in this directory.
#### YAML
@@ -82,7 +82,7 @@ steve:
profession: guy with keyboard
```
-Each fixture is given a name followed by an indented list of colon-separated key/value pairs. Records are typically separated by a blank space. You can place comments in a fixture file by using the # character in the first column.
+Each fixture is given a name followed by an indented list of colon-separated key/value pairs. Records are typically separated by a blank line. You can place comments in a fixture file by using the # character in the first column.
If you are working with [associations](/association_basics.html), you can simply
define a reference node between two different fixtures. Here's an example with
@@ -138,7 +138,7 @@ users(:david)
users(:david).id
# one can also access methods available on the User class
-email(david.girlfriend.email, david.location_tonight)
+email(david.partner.email, david.location_tonight)
```
### Rake Tasks for Running your Tests
@@ -162,7 +162,7 @@ project is created.
We will cover each of types Rails tests listed above in this guide.
-Unit Testing your Models
+Model Testing
------------------------
In Rails, unit tests are what you write to test your models.
@@ -632,7 +632,7 @@ WARNING: You must include the "layouts" directory name even if you save your lay
If your view renders any partial, when asserting for the layout, you can to assert for the partial at the same time.
Otherwise, assertion will fail.
-Remember, we added the "_form" partial to our creating Articles view? Let's write an assertion for that in the `:new` action now:
+Remember, we added the "_form" partial to our new Article view? Let's write an assertion for that in the `:new` action now:
```ruby
test "new should render correct layout" do
@@ -929,7 +929,7 @@ assert_select_email do
end
```
-Testing helpers
+Testing Helpers
---------------
In order to test helpers, all you need to do is check that the output of the
@@ -1083,7 +1083,7 @@ Testing mailer classes requires some specific tools to do a thorough job.
### Keeping the Postman in Check
-Your mailer classes - like every other part of your Rails application - should be tested to ensure that it is working as expected.
+Your mailer classes - like every other part of your Rails application - should be tested to ensure that they are working as expected.
The goals of testing your mailer classes are to ensure that:
diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md
index 20b90bdba0..5a6f267360 100644
--- a/guides/source/upgrading_ruby_on_rails.md
+++ b/guides/source/upgrading_ruby_on_rails.md
@@ -20,7 +20,7 @@ The best way to be sure that your application still works after upgrading is to
Rails generally stays close to the latest released Ruby version when it's released:
-* Rails 5 requires Ruby 2.2 or newer.
+* Rails 5 requires Ruby 2.2.1 or newer.
* Rails 4 prefers Ruby 2.0 and requires 1.9.3 or newer.
* Rails 3.2.x is the last branch to support Ruby 1.8.7.
* Rails 3 and above require Ruby 1.8.7 or higher. Support for all of the previous Ruby versions has been dropped officially. You should upgrade as early as possible.
@@ -75,6 +75,21 @@ warning by adding the following configuration to your `config/application.rb`:
See [#17227](https://github.com/rails/rails/pull/17227) for more details.
+### ActiveJob jobs now inherent from ApplicationJob by default
+
+In Rails 4.2 an ActiveJob inherents from `ActiveJob::Base`. In Rails 5.0 this
+behaviour has changed to now inherent from `ApplicationJob`.
+
+When upgrading from Rails 4.2 to Rails 5.0 you need to create a file
+`application_job.rb` in `app/jobs/` and add the following content:
+
+```
+class ApplicationJob < ActiveJob::Base
+end
+```
+
+See [#19034](https://github.com/rails/rails/pull/19034) for more details
+
Upgrading from Rails 4.1 to Rails 4.2
-------------------------------------
diff --git a/rails.gemspec b/rails.gemspec
index 1398169922..23404da9be 100644
--- a/rails.gemspec
+++ b/rails.gemspec
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
s.summary = 'Full-stack web application framework.'
s.description = 'Ruby on Rails is a full-stack web framework optimized for programmer happiness and sustainable productivity. It encourages beautiful code by favoring convention over configuration.'
- s.required_ruby_version = '>= 2.2.0'
+ s.required_ruby_version = '>= 2.2.1'
s.required_rubygems_version = '>= 1.8.11'
s.license = 'MIT'
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 8b10144413..a181823576 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,22 +1,36 @@
-* Created rake restart task. Restarts your Rails app by touching the
- `tmp/restart.txt`.
+* Respect `pluralize_table_names` when generating fixture file.
- Fixes #18876.
+ Fixes #19519.
- *Hyonjee Joo*
+ *Yuji Yaginuma*
+
+* Add a new-line to the end of route method generated code.
+
+ We need to add a `\n`, because we cannot have two routes
+ in the same line.
+
+ *arthurnn*
-* Set Rails console to use log formatter and log level as specified for the
- given environment.
+* Add `rake initializers`
- Fixes #15470.
+ This task prints out all defined initializers in the order they are invoked
+ by Rails. This is helpful for debugging issues related to the initialization
+ process.
- *Jacob Evelyn*
+ *Naoto Kaneko*
+
+* Created rake restart task. Restarts your Rails app by touching the
+ `tmp/restart.txt`.
+
+ Fixes #18876.
+
+ *Hyonjee Joo*
* Add `config/initializers/active_record_belongs_to_required_by_default.rb`
Newly generated Rails apps have a new initializer called
`active_record_belongs_to_required_by_default.rb` which sets the value of
- the configuration option `config.active_record.belongs_to_requred_by_default`
+ the configuration option `config.active_record.belongs_to_required_by_default`
to `true` when ActiveRecord is not skipped.
As a result, new Rails apps require `belongs_to` association on model
diff --git a/railties/lib/rails/app_rails_loader.rb b/railties/lib/rails/app_rails_loader.rb
index 39d8007333..9a7c6c5f2d 100644
--- a/railties/lib/rails/app_rails_loader.rb
+++ b/railties/lib/rails/app_rails_loader.rb
@@ -1,4 +1,5 @@
require 'pathname'
+require 'rails/version'
module Rails
module AppRailsLoader
@@ -9,7 +10,7 @@ module Rails
BUNDLER_WARNING = <<EOS
Looks like your app's ./bin/rails is a stub that was generated by Bundler.
-In Rails 4, your app's bin/ directory contains executables that are versioned
+In Rails #{Rails::VERSION::MAJOR}, your app's bin/ directory contains executables that are versioned
like any other source code, rather than stubs that are generated on demand.
Here's how to upgrade:
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index b11815e013..e9683d4a95 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -159,8 +159,9 @@ module Rails
# Implements call according to the Rack API. It simply
# dispatches the request to the underlying middleware stack.
def call(env)
- env["ORIGINAL_FULLPATH"] = build_original_fullpath(env)
- env["ORIGINAL_SCRIPT_NAME"] = env["SCRIPT_NAME"]
+ req = ActionDispatch::Request.new env
+ env["ORIGINAL_FULLPATH"] = req.fullpath
+ env["ORIGINAL_SCRIPT_NAME"] = req.script_name
super(env)
end
@@ -427,9 +428,9 @@ module Rails
# Return an array of railties respecting the order they're loaded
# and the order specified by the +railties_order+ config.
#
- # While when running initializers we need engines in reverse
- # order here when copying migrations from railties we need them in the same
- # order as given by +railties_order+.
+ # While running initializers we need engines in reverse order here when
+ # copying migrations from railties ; we need them in the order given by
+ # +railties_order+.
def migration_railties # :nodoc:
ordered_railties.flatten - [self]
end
@@ -504,18 +505,6 @@ module Rails
default_stack.build_stack
end
- def build_original_fullpath(env) #:nodoc:
- path_info = env["PATH_INFO"]
- query_string = env["QUERY_STRING"]
- script_name = env["SCRIPT_NAME"]
-
- if query_string.present?
- "#{script_name}#{path_info}?#{query_string}"
- else
- "#{script_name}#{path_info}"
- end
- end
-
def validate_secret_key_config! #:nodoc:
if secrets.secret_key_base.blank?
ActiveSupport::Deprecation.warn "You didn't set `secret_key_base`. " +
diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb
index f32bf772a5..12bd73db24 100644
--- a/railties/lib/rails/commands.rb
+++ b/railties/lib/rails/commands.rb
@@ -6,7 +6,8 @@ aliases = {
"c" => "console",
"s" => "server",
"db" => "dbconsole",
- "r" => "runner"
+ "r" => "runner",
+ "t" => "test",
}
command = ARGV.shift
diff --git a/railties/lib/rails/commands/commands_tasks.rb b/railties/lib/rails/commands/commands_tasks.rb
index 8bae08e44e..d8d4080c3e 100644
--- a/railties/lib/rails/commands/commands_tasks.rb
+++ b/railties/lib/rails/commands/commands_tasks.rb
@@ -14,6 +14,7 @@ The most common rails commands are:
generate Generate new code (short-cut alias: "g")
console Start the Rails console (short-cut alias: "c")
server Start the Rails server (short-cut alias: "s")
+ test Run tests (short-cut alias: "t")
dbconsole Start a console for the database specified in config/database.yml
(short-cut alias: "db")
new Create a new Rails application. "rails new my_app" creates a
@@ -27,7 +28,7 @@ In addition to those, there are:
All commands can be run with -h (or --help) for more information.
EOT
- COMMAND_WHITELIST = %w(plugin generate destroy console server dbconsole runner new version help)
+ COMMAND_WHITELIST = %w(plugin generate destroy console server dbconsole runner new version help test)
def initialize(argv)
@argv = argv
@@ -81,6 +82,10 @@ EOT
end
end
+ def test
+ require_command!("test")
+ end
+
def dbconsole
require_command!("dbconsole")
Rails::DBConsole.start
diff --git a/railties/lib/rails/commands/test.rb b/railties/lib/rails/commands/test.rb
new file mode 100644
index 0000000000..598e224a6f
--- /dev/null
+++ b/railties/lib/rails/commands/test.rb
@@ -0,0 +1,5 @@
+require "rails/test_unit/runner"
+
+$: << File.expand_path("../../test", APP_PATH)
+
+Rails::TestRunner.run(ARGV)
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index fd37fd0457..83cee28fa3 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -528,7 +528,7 @@ module Rails
# Defines the routes for this engine. If a block is given to
# routes, it is appended to the engine.
def routes
- @routes ||= ActionDispatch::Routing::RouteSet.new
+ @routes ||= ActionDispatch::Routing::RouteSet.new_with_config(config)
@routes.append(&Proc.new) if block_given?
@routes
end
diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb
index c1bc646c65..70a20801a0 100644
--- a/railties/lib/rails/generators/actions.rb
+++ b/railties/lib/rails/generators/actions.rb
@@ -221,7 +221,7 @@ module Rails
sentinel = /\.routes\.draw do\s*\n/m
in_root do
- inject_into_file 'config/routes.rb', " #{routing_code}", { after: sentinel, verbose: false, force: true }
+ inject_into_file 'config/routes.rb', " #{routing_code}\n", { after: sentinel, verbose: false, force: true }
end
end
diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index 253272c7dd..813f8b21fd 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -291,7 +291,7 @@ module Rails
end
def javascript_runtime_gemfile_entry
- comment = 'See https://github.com/sstephenson/execjs#readme for more supported runtimes'
+ comment = 'See https://github.com/rails/execjs#readme for more supported runtimes'
if defined?(JRUBY_VERSION)
GemfileEntry.version 'therubyrhino', nil, comment
else
diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb
index 36456e64f5..01a8e2e9b4 100644
--- a/railties/lib/rails/generators/named_base.rb
+++ b/railties/lib/rails/generators/named_base.rb
@@ -141,6 +141,10 @@ module Rails
@plural_file_name ||= file_name.pluralize
end
+ def fixture_file_name
+ @fixture_file_name ||= (pluralize_table_names? ? plural_file_name : file_name)
+ end
+
def route_url
@route_url ||= class_path.collect {|dname| "/" + dname }.join + "/" + plural_file_name
end
diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile
index 82a0315379..c11bb58bfa 100644
--- a/railties/lib/rails/generators/rails/app/templates/Gemfile
+++ b/railties/lib/rails/generators/rails/app/templates/Gemfile
@@ -36,10 +36,6 @@ group :development, :test do
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring'
<% end -%>
-
- # Adds `Method#source` and `Method#comment` to get the source code of a
- # method from the console
- gem 'method_source'
<% end -%>
end
<% if RUBY_PLATFORM.match(/bccwin|cygwin|emx|mingw|mswin|wince|java/) -%>
diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt
index c1a77944e8..cb86978d4c 100644
--- a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt
+++ b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt
@@ -7,7 +7,7 @@
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
-// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
+// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
<% unless options[:skip_javascript] -%>
diff --git a/railties/lib/rails/generators/rails/app/templates/app/jobs/application_job.rb b/railties/lib/rails/generators/rails/app/templates/app/jobs/application_job.rb
new file mode 100644
index 0000000000..bddb5bcd0d
--- /dev/null
+++ b/railties/lib/rails/generators/rails/app/templates/app/jobs/application_job.rb
@@ -0,0 +1,3 @@
+class ApplicationJob < ActiveJob::Base
+
+end
diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml
index acb93939e1..f5b62e8fb3 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml
+++ b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml
@@ -7,7 +7,7 @@
# gem 'activerecord-jdbcmysql-adapter'
#
# And be sure to use new-style password hashing:
-# http://dev.mysql.com/doc/refman/5.0/en/old-client.html
+# http://dev.mysql.com/doc/refman/5.6/en/old-client.html
#
default: &default
adapter: mysql
diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml
index 596c916573..b0767bd93a 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml
+++ b/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml
@@ -7,7 +7,7 @@
# gem 'mysql2'
#
# And be sure to use new-style password hashing:
-# http://dev.mysql.com/doc/refman/5.0/en/old-client.html
+# http://dev.mysql.com/doc/refman/5.6/en/old-client.html
#
default: &default
adapter: mysql2
diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js b/railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js
index c28e5badc6..8913b40f69 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js
+++ b/railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js
@@ -7,7 +7,7 @@
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
-// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
+// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require_tree .
diff --git a/railties/lib/rails/generators/rails/resource_route/resource_route_generator.rb b/railties/lib/rails/generators/rails/resource_route/resource_route_generator.rb
index e4a2bc2b0f..c986f95e67 100644
--- a/railties/lib/rails/generators/rails/resource_route/resource_route_generator.rb
+++ b/railties/lib/rails/generators/rails/resource_route/resource_route_generator.rb
@@ -29,8 +29,10 @@ module Rails
write("end", route_length - index)
end
- # route prepends two spaces onto the front of the string that is passed, this corrects that
- route route_string[2..-1]
+ # route prepends two spaces onto the front of the string that is passed, this corrects that.
+ # Also it adds a \n to the end of each line, as route already adds that
+ # we need to correct that too.
+ route route_string[2..-2]
end
private
diff --git a/railties/lib/rails/generators/test_unit/mailer/templates/preview.rb b/railties/lib/rails/generators/test_unit/mailer/templates/preview.rb
index 6b85764a66..b063cbc47b 100644
--- a/railties/lib/rails/generators/test_unit/mailer/templates/preview.rb
+++ b/railties/lib/rails/generators/test_unit/mailer/templates/preview.rb
@@ -1,9 +1,9 @@
<% module_namespacing do -%>
-# Preview all emails at http://localhost:3000/rails/mailers/<%= file_path %>
+# Preview all emails at http://localhost:3000/rails/mailers/<%= file_path %>_mailer
class <%= class_name %>MailerPreview < ActionMailer::Preview
<% actions.each do |action| -%>
- # Preview this email at http://localhost:3000/rails/mailers/<%= file_path %>/<%= action %>
+ # Preview this email at http://localhost:3000/rails/mailers/<%= file_path %>_mailer/<%= action %>
def <%= action %>
<%= class_name %>Mailer.<%= action %>
end
diff --git a/railties/lib/rails/generators/test_unit/model/model_generator.rb b/railties/lib/rails/generators/test_unit/model/model_generator.rb
index 2826a3ffa1..086588750e 100644
--- a/railties/lib/rails/generators/test_unit/model/model_generator.rb
+++ b/railties/lib/rails/generators/test_unit/model/model_generator.rb
@@ -19,7 +19,7 @@ module TestUnit # :nodoc:
def create_fixture_file
if options[:fixture] && options[:fixture_replacement].nil?
- template 'fixtures.yml', File.join('test/fixtures', class_path, "#{plural_file_name}.yml")
+ template 'fixtures.yml', File.join('test/fixtures', class_path, "#{fixture_file_name}.yml")
end
end
diff --git a/railties/lib/rails/ruby_version_check.rb b/railties/lib/rails/ruby_version_check.rb
index e2a199ec4d..9131c51e91 100644
--- a/railties/lib/rails/ruby_version_check.rb
+++ b/railties/lib/rails/ruby_version_check.rb
@@ -1,13 +1,13 @@
-if RUBY_VERSION < '2.2.0' && RUBY_ENGINE == 'ruby'
+if RUBY_VERSION < '2.2.1' && RUBY_ENGINE == 'ruby'
desc = defined?(RUBY_DESCRIPTION) ? RUBY_DESCRIPTION : "ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE})"
abort <<-end_message
- Rails 5 requires to run on Ruby 2.2.0 or newer.
+ Rails 5 requires to run on Ruby 2.2.1 or newer.
You're running
#{desc}
- Please upgrade to Ruby 2.2.0 or newer to continue.
+ Please upgrade to Ruby 2.2.1 or newer to continue.
end_message
end
diff --git a/railties/lib/rails/tasks.rb b/railties/lib/rails/tasks.rb
index a5e4d2935e..2c3d278eca 100644
--- a/railties/lib/rails/tasks.rb
+++ b/railties/lib/rails/tasks.rb
@@ -4,6 +4,7 @@ require 'rake'
%w(
annotations
framework
+ initializers
log
middleware
misc
diff --git a/railties/lib/rails/tasks/initializers.rake b/railties/lib/rails/tasks/initializers.rake
new file mode 100644
index 0000000000..2968b5cb53
--- /dev/null
+++ b/railties/lib/rails/tasks/initializers.rake
@@ -0,0 +1,6 @@
+desc "Print out all defined initializers in the order they are invoked by Rails."
+task initializers: :environment do
+ Rails.application.initializers.tsort_each do |initializer|
+ puts initializer.name
+ end
+end
diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb
index 40a1915b54..5cf44e6331 100644
--- a/railties/lib/rails/test_help.rb
+++ b/railties/lib/rails/test_help.rb
@@ -2,6 +2,7 @@
# so fixtures aren't loaded into that environment
abort("Abort testing: Your Rails environment is running in production mode!") if Rails.env.production?
+require "rails/test_unit/minitest_plugin"
require 'active_support/testing/autorun'
require 'active_support/test_case'
require 'action_controller'
@@ -9,12 +10,6 @@ require 'action_controller/test_case'
require 'action_dispatch/testing/integration'
require 'rails/generators/test_case'
-# Config Rails backtrace in tests.
-require 'rails/backtrace_cleaner'
-if ENV["BACKTRACE"].nil?
- Minitest.backtrace_filter = Rails.backtrace_cleaner
-end
-
if defined?(ActiveRecord::Base)
ActiveRecord::Migration.maintain_test_schema!
diff --git a/railties/lib/rails/test_unit/minitest_plugin.rb b/railties/lib/rails/test_unit/minitest_plugin.rb
new file mode 100644
index 0000000000..70ce9d3360
--- /dev/null
+++ b/railties/lib/rails/test_unit/minitest_plugin.rb
@@ -0,0 +1,14 @@
+require "minitest"
+require "rails/test_unit/reporter"
+
+def Minitest.plugin_rails_init(options)
+ self.reporter << Rails::TestUnitReporter.new(options[:io], options)
+ if $rails_test_runner && (method = $rails_test_runner.find_method)
+ options[:filter] = method
+ end
+
+ if !($rails_test_runner && $rails_test_runner.show_backtrace?)
+ Minitest.backtrace_filter = Rails.backtrace_cleaner
+ end
+end
+Minitest.extensions << 'rails'
diff --git a/railties/lib/rails/test_unit/reporter.rb b/railties/lib/rails/test_unit/reporter.rb
new file mode 100644
index 0000000000..64e99626eb
--- /dev/null
+++ b/railties/lib/rails/test_unit/reporter.rb
@@ -0,0 +1,22 @@
+require "minitest"
+
+module Rails
+ class TestUnitReporter < Minitest::StatisticsReporter
+ def report
+ return if results.empty?
+ io.puts
+ io.puts "Failed tests:"
+ io.puts
+ io.puts aggregated_results
+ end
+
+ def aggregated_results # :nodoc:
+ filtered_results = results.dup
+ filtered_results.reject!(&:skipped?) unless options[:verbose]
+ filtered_results.map do |result|
+ location, line = result.method(result.name).source_location
+ "bin/rails test #{location}:#{line}"
+ end.join "\n"
+ end
+ end
+end
diff --git a/railties/lib/rails/test_unit/runner.rb b/railties/lib/rails/test_unit/runner.rb
new file mode 100644
index 0000000000..5573fa6904
--- /dev/null
+++ b/railties/lib/rails/test_unit/runner.rb
@@ -0,0 +1,137 @@
+require "optparse"
+require "rake/file_list"
+require "method_source"
+
+module Rails
+ class TestRunner
+ class Options
+ def self.parse(args)
+ options = { backtrace: !ENV["BACKTRACE"].nil?, name: nil, environment: "test" }
+
+ opt_parser = ::OptionParser.new do |opts|
+ opts.banner = "Usage: bin/rails test [options] [file or directory]"
+
+ opts.separator ""
+ opts.on("-e", "--environment [ENV]",
+ "Run tests in the ENV environment") do |env|
+ options[:environment] = env.strip
+ end
+ opts.separator ""
+ opts.separator "Filter options:"
+ opts.separator ""
+ opts.separator <<-DESC
+ You can run a single test by appending the line number to filename:
+
+ bin/rails test test/models/user_test.rb:27
+
+ DESC
+
+ opts.on("-n", "--name [NAME]",
+ "Only run tests matching NAME") do |name|
+ options[:name] = name
+ end
+ opts.on("-p", "--pattern [PATTERN]",
+ "Only run tests matching PATTERN") do |pattern|
+ options[:name] = "/#{pattern}/"
+ end
+
+ opts.separator ""
+ opts.separator "Output options:"
+
+ opts.on("-b", "--backtrace",
+ "Show the complete backtrace") do
+ options[:backtrace] = true
+ end
+
+ opts.separator ""
+ opts.separator "Common options:"
+
+ opts.on_tail("-h", "--help", "Show this message") do
+ puts opts
+ exit
+ end
+ end
+
+ opt_parser.order!(args)
+
+ options[:patterns] = []
+ while arg = args.shift
+ if (file_and_line = arg.split(':')).size > 1
+ options[:filename], options[:line] = file_and_line
+ options[:filename] = File.expand_path options[:filename]
+ options[:line] &&= options[:line].to_i
+ else
+ arg = arg.gsub(':', '')
+ if Dir.exist?("#{arg}")
+ options[:patterns] << File.expand_path("#{arg}/**/*_test.rb")
+ elsif File.file?(arg)
+ options[:patterns] << File.expand_path(arg)
+ end
+ end
+ end
+ options
+ end
+ end
+
+ def initialize(options = {})
+ @options = options
+ end
+
+ def self.run(arguments)
+ options = Rails::TestRunner::Options.parse(arguments)
+ Rails::TestRunner.new(options).run
+ end
+
+ def run
+ $rails_test_runner = self
+ ENV["RAILS_ENV"] = @options[:environment]
+ run_tests
+ end
+
+ def find_method
+ return @options[:name] if @options[:name]
+ return unless @options[:line]
+ method = test_methods.find do |location, test_method, start_line, end_line|
+ location == @options[:filename] &&
+ (start_line..end_line).include?(@options[:line].to_i)
+ end
+ method[1] if method
+ end
+
+ def show_backtrace?
+ @options[:backtrace]
+ end
+
+ def test_files
+ return [@options[:filename]] if @options[:filename]
+ if @options[:patterns] && @options[:patterns].count > 0
+ pattern = @options[:patterns]
+ else
+ pattern = "test/**/*_test.rb"
+ end
+ Rake::FileList[pattern]
+ end
+
+ private
+ def run_tests
+ test_files.to_a.each do |file|
+ require File.expand_path file
+ end
+ end
+
+ def test_methods
+ methods_map = []
+ suites = Minitest::Runnable.runnables.shuffle
+ suites.each do |suite_class|
+ suite_class.runnable_methods.each do |test_method|
+ method = suite_class.instance_method(test_method)
+ location = method.source_location
+ start_line = location.last
+ end_line = method.source.split("\n").size + start_line - 1
+ methods_map << [File.expand_path(location.first), test_method, start_line, end_line]
+ end
+ end
+ methods_map
+ end
+ end
+end
diff --git a/railties/lib/rails/test_unit/testing.rake b/railties/lib/rails/test_unit/testing.rake
index d836c0d6d6..0f26621b59 100644
--- a/railties/lib/rails/test_unit/testing.rake
+++ b/railties/lib/rails/test_unit/testing.rake
@@ -1,11 +1,12 @@
-require 'rake/testtask'
-require 'rails/test_unit/sub_test_task'
+require "rails/test_unit/runner"
task default: :test
desc "Runs all tests in test folder"
task :test do
- Rails::TestTask.test_creator(Rake.application.top_level_tasks).invoke_rake_task
+ $: << "test"
+ args = ARGV[0] == "test" ? ARGV[1..-1] : []
+ Rails::TestRunner.run(args)
end
namespace :test do
@@ -14,30 +15,30 @@ namespace :test do
# If used with Active Record, this task runs before the database schema is synchronized.
end
- Rails::TestTask.new(:run) do |t|
- t.pattern = "test/**/*_test.rb"
- end
+ task :run => %w[test]
desc "Run tests quickly, but also reset db"
task :db => %w[db:test:prepare test]
- Rails::TestTask.new(single: "test:prepare")
-
["models", "helpers", "controllers", "mailers", "integration", "jobs"].each do |name|
- Rails::TestTask.new(name => "test:prepare") do |t|
- t.pattern = "test/#{name}/**/*_test.rb"
+ task name => "test:prepare" do
+ $: << "test"
+ Rails::TestRunner.run(["test/#{name}"])
end
end
- Rails::TestTask.new(generators: "test:prepare") do |t|
- t.pattern = "test/lib/generators/**/*_test.rb"
+ task :generators => "test:prepare" do
+ $: << "test"
+ Rails::TestRunner.run(["test/lib/generators"])
end
- Rails::TestTask.new(units: "test:prepare") do |t|
- t.pattern = 'test/{models,helpers,unit}/**/*_test.rb'
+ task :units => "test:prepare" do
+ $: << "test"
+ Rails::TestRunner.run(["test/models", "test/helpers", "test/unit"])
end
- Rails::TestTask.new(functionals: "test:prepare") do |t|
- t.pattern = 'test/{controllers,mailers,functional}/**/*_test.rb'
+ task :functionals => "test:prepare" do
+ $: << "test"
+ Rails::TestRunner.run(["test/controllers", "test/mailers", "test/functional"])
end
end
diff --git a/railties/railties.gemspec b/railties/railties.gemspec
index 7a1c897e3d..001882fdc6 100644
--- a/railties/railties.gemspec
+++ b/railties/railties.gemspec
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
s.summary = 'Tools for creating, working with, and running Rails applications.'
s.description = 'Rails internals: application bootup, plugins, generators, and rake tasks.'
- s.required_ruby_version = '>= 2.2.0'
+ s.required_ruby_version = '>= 2.2.1'
s.license = 'MIT'
@@ -28,6 +28,7 @@ Gem::Specification.new do |s|
s.add_dependency 'rake', '>= 0.8.7'
s.add_dependency 'thor', '>= 0.18.1', '< 2.0'
+ s.add_dependency 'method_source'
s.add_development_dependency 'actionview', version
end
diff --git a/railties/test/abstract_unit.rb b/railties/test/abstract_unit.rb
index ab8883e135..794d180e5d 100644
--- a/railties/test/abstract_unit.rb
+++ b/railties/test/abstract_unit.rb
@@ -30,9 +30,4 @@ end
class ActiveSupport::TestCase
include ActiveSupport::Testing::Stream
-
- # FIXME: we have tests that depend on run order, we should fix that and
- # remove this method call.
- self.test_order = :sorted
-
end
diff --git a/railties/test/application/asset_debugging_test.rb b/railties/test/application/asset_debugging_test.rb
index 9a571fac3a..acd387256c 100644
--- a/railties/test/application/asset_debugging_test.rb
+++ b/railties/test/application/asset_debugging_test.rb
@@ -57,8 +57,8 @@ module ApplicationTests
class ::PostsController < ActionController::Base ; end
get '/posts?debug_assets=true'
- assert_match(/<script src="\/assets\/application-([0-z]+)\.js\?body=1"><\/script>/, last_response.body)
- assert_match(/<script src="\/assets\/xmlhr-([0-z]+)\.js\?body=1"><\/script>/, last_response.body)
+ assert_match(/<script src="\/assets\/application(\.self)?-([0-z]+)\.js\?body=1"><\/script>/, last_response.body)
+ assert_match(/<script src="\/assets\/xmlhr(\.self)?-([0-z]+)\.js\?body=1"><\/script>/, last_response.body)
end
end
end
diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb
index 0a2f283cce..f6b7d4c855 100644
--- a/railties/test/application/assets_test.rb
+++ b/railties/test/application/assets_test.rb
@@ -204,7 +204,7 @@ module ApplicationTests
app_file "app/assets/javascripts/application.js", "alert();"
precompile!
- manifest = Dir["#{app_path}/public/assets/manifest-*.json"].first
+ manifest = Dir["#{app_path}/public/assets/.sprockets-manifest-*.json"].first
assets = ActiveSupport::JSON.decode(File.read(manifest))
assert_match(/application-([0-z]+)\.js/, assets["assets"]["application.js"])
@@ -217,7 +217,7 @@ module ApplicationTests
precompile!
- manifest = Dir["#{app_path}/public/x/manifest-*.json"].first
+ manifest = Dir["#{app_path}/public/x/.sprockets-manifest-*.json"].first
assets = ActiveSupport::JSON.decode(File.read(manifest))
assert_match(/application-([0-z]+)\.js/, assets["assets"]["application.js"])
end
@@ -229,7 +229,7 @@ module ApplicationTests
ENV["RAILS_ENV"] = "production"
precompile!
- manifest = Dir["#{app_path}/public/assets/manifest-*.json"].first
+ manifest = Dir["#{app_path}/public/assets/.sprockets-manifest-*.json"].first
assets = ActiveSupport::JSON.decode(File.read(manifest))
asset_path = assets["assets"]["application.js"]
@@ -261,7 +261,7 @@ module ApplicationTests
ENV["RAILS_ENV"] = "production"
precompile!
- manifest = Dir["#{app_path}/public/assets/manifest-*.json"].first
+ manifest = Dir["#{app_path}/public/assets/.sprockets-manifest-*.json"].first
assets = ActiveSupport::JSON.decode(File.read(manifest))
asset_path = assets["assets"]["application.css"]
@@ -291,7 +291,7 @@ module ApplicationTests
precompile!
- manifest = Dir["#{app_path}/public/assets/manifest-*.json"].first
+ manifest = Dir["#{app_path}/public/assets/.sprockets-manifest-*.json"].first
assets = ActiveSupport::JSON.decode(File.read(manifest))
assert asset_path = assets["assets"].find { |(k, _)| k && k =~ /.png/ }[1]
@@ -437,9 +437,9 @@ module ApplicationTests
class ::PostsController < ActionController::Base; end
get '/posts', {}, {'HTTPS'=>'off'}
- assert_match('src="http://example.com/assets/application.js', last_response.body)
+ assert_match('src="http://example.com/assets/application.self.js', last_response.body)
get '/posts', {}, {'HTTPS'=>'on'}
- assert_match('src="https://example.com/assets/application.js', last_response.body)
+ assert_match('src="https://example.com/assets/application.self.js', last_response.body)
end
test "asset urls should be protocol-relative if no request is in scope" do
diff --git a/railties/test/application/build_original_fullpath_test.rb b/railties/test/application/build_original_fullpath_test.rb
deleted file mode 100644
index 647ffb097a..0000000000
--- a/railties/test/application/build_original_fullpath_test.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-require "abstract_unit"
-
-module ApplicationTests
- class BuildOriginalPathTest < ActiveSupport::TestCase
- def test_include_original_PATH_info_in_ORIGINAL_FULLPATH
- env = { 'PATH_INFO' => '/foo/' }
- assert_equal "/foo/", Rails.application.send(:build_original_fullpath, env)
- end
-
- def test_include_SCRIPT_NAME
- env = {
- 'SCRIPT_NAME' => '/foo',
- 'PATH_INFO' => '/bar'
- }
-
- assert_equal "/foo/bar", Rails.application.send(:build_original_fullpath, env)
- end
-
- def test_include_QUERY_STRING
- env = {
- 'PATH_INFO' => '/foo',
- 'QUERY_STRING' => 'bar',
- }
- assert_equal "/foo?bar", Rails.application.send(:build_original_fullpath, env)
- end
- end
-end
diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb
index 2bff21dae5..0648b11813 100644
--- a/railties/test/application/rake_test.rb
+++ b/railties/test/application/rake_test.rb
@@ -99,7 +99,7 @@ module ApplicationTests
end
def test_code_statistics_sanity
- assert_match "Code LOC: 5 Test LOC: 0 Code to Test Ratio: 1:0.0",
+ assert_match "Code LOC: 7 Test LOC: 0 Code to Test Ratio: 1:0.0",
Dir.chdir(app_path){ `rake stats` }
end
diff --git a/railties/test/application/test_runner_test.rb b/railties/test/application/test_runner_test.rb
index a12f3cfc24..c122b315c0 100644
--- a/railties/test/application/test_runner_test.rb
+++ b/railties/test/application/test_runner_test.rb
@@ -7,7 +7,6 @@ module ApplicationTests
def setup
build_app
- ENV['RAILS_ENV'] = nil
create_schema
end
@@ -55,7 +54,7 @@ module ApplicationTests
create_test_file :models, 'foo'
create_test_file :models, 'bar'
create_test_file :controllers, 'foobar_controller'
- run_test_models_command.tap do |output|
+ run_test_command("test/models").tap do |output|
assert_match "FooTest", output
assert_match "BarTest", output
assert_match "2 runs, 2 assertions, 0 failures", output
@@ -66,7 +65,7 @@ module ApplicationTests
create_test_file :helpers, 'foo_helper'
create_test_file :helpers, 'bar_helper'
create_test_file :controllers, 'foobar_controller'
- run_test_helpers_command.tap do |output|
+ run_test_command("test/helpers").tap do |output|
assert_match "FooHelperTest", output
assert_match "BarHelperTest", output
assert_match "2 runs, 2 assertions, 0 failures", output
@@ -74,6 +73,7 @@ module ApplicationTests
end
def test_run_units
+ skip "we no longer have the concept of unit tests. Just different directories..."
create_test_file :models, 'foo'
create_test_file :helpers, 'bar_helper'
create_test_file :unit, 'baz_unit'
@@ -90,7 +90,7 @@ module ApplicationTests
create_test_file :controllers, 'foo_controller'
create_test_file :controllers, 'bar_controller'
create_test_file :models, 'foo'
- run_test_controllers_command.tap do |output|
+ run_test_command("test/controllers").tap do |output|
assert_match "FooControllerTest", output
assert_match "BarControllerTest", output
assert_match "2 runs, 2 assertions, 0 failures", output
@@ -101,7 +101,7 @@ module ApplicationTests
create_test_file :mailers, 'foo_mailer'
create_test_file :mailers, 'bar_mailer'
create_test_file :models, 'foo'
- run_test_mailers_command.tap do |output|
+ run_test_command("test/mailers").tap do |output|
assert_match "FooMailerTest", output
assert_match "BarMailerTest", output
assert_match "2 runs, 2 assertions, 0 failures", output
@@ -112,7 +112,7 @@ module ApplicationTests
create_test_file :jobs, 'foo_job'
create_test_file :jobs, 'bar_job'
create_test_file :models, 'foo'
- run_test_jobs_command.tap do |output|
+ run_test_command("test/jobs").tap do |output|
assert_match "FooJobTest", output
assert_match "BarJobTest", output
assert_match "2 runs, 2 assertions, 0 failures", output
@@ -120,6 +120,7 @@ module ApplicationTests
end
def test_run_functionals
+ skip "we no longer have the concept of functional tests. Just different directories..."
create_test_file :mailers, 'foo_mailer'
create_test_file :controllers, 'bar_controller'
create_test_file :functional, 'baz_functional'
@@ -135,7 +136,7 @@ module ApplicationTests
def test_run_integration
create_test_file :integration, 'foo_integration'
create_test_file :models, 'foo'
- run_test_integration_command.tap do |output|
+ run_test_command("test/integration").tap do |output|
assert_match "FooIntegration", output
assert_match "1 runs, 1 assertions, 0 failures", output
end
@@ -165,7 +166,7 @@ module ApplicationTests
end
RUBY
- run_test_command('test/unit/chu_2_koi_test.rb test_rikka').tap do |output|
+ run_test_command('-n test_rikka test/unit/chu_2_koi_test.rb').tap do |output|
assert_match "Rikka", output
assert_no_match "Sanae", output
end
@@ -186,7 +187,7 @@ module ApplicationTests
end
RUBY
- run_test_command('test/unit/chu_2_koi_test.rb /rikka/').tap do |output|
+ run_test_command('-p rikka test/unit/chu_2_koi_test.rb').tap do |output|
assert_match "Rikka", output
assert_no_match "Sanae", output
end
@@ -194,18 +195,18 @@ module ApplicationTests
def test_load_fixtures_when_running_test_suites
create_model_with_fixture
- suites = [:models, :helpers, [:units, :unit], :controllers, :mailers,
- [:functionals, :functional], :integration]
+ suites = [:models, :helpers, :controllers, :mailers, :integration]
suites.each do |suite, directory|
directory ||= suite
create_fixture_test directory
- assert_match "3 users", run_task(["test:#{suite}"])
+ assert_match "3 users", run_test_command("test/#{suite}")
Dir.chdir(app_path) { FileUtils.rm_f "test/#{directory}" }
end
end
def test_run_with_model
+ skip "These feel a bit odd. Not sure we should keep supporting them."
create_model_with_fixture
create_fixture_test 'models', 'user'
assert_match "3 users", run_task(["test models/user"])
@@ -213,6 +214,7 @@ module ApplicationTests
end
def test_run_different_environment_using_env_var
+ skip "no longer possible. Running tests in a different environment should be explicit"
app_file 'test/unit/env_test.rb', <<-RUBY
require 'test_helper'
@@ -227,7 +229,7 @@ module ApplicationTests
assert_match "development", run_test_command('test/unit/env_test.rb')
end
- def test_run_different_environment_using_e_tag
+ def test_run_different_environment
env = "development"
app_file 'test/unit/env_test.rb', <<-RUBY
require 'test_helper'
@@ -239,7 +241,7 @@ module ApplicationTests
end
RUBY
- assert_match env, run_test_command("test/unit/env_test.rb RAILS_ENV=#{env}")
+ assert_match env, run_test_command("-e #{env} test/unit/env_test.rb")
end
def test_generated_scaffold_works_with_rails_test
@@ -248,17 +250,8 @@ module ApplicationTests
end
private
- def run_task(tasks)
- Dir.chdir(app_path) { `bundle exec rake #{tasks.join ' '}` }
- end
-
def run_test_command(arguments = 'test/unit/test_test.rb')
- run_task ['test', arguments]
- end
- %w{ mailers models helpers units controllers functionals integration jobs }.each do |type|
- define_method("run_test_#{type}_command") do
- run_task ["test:#{type}"]
- end
+ Dir.chdir(app_path) { `bin/rails t #{arguments}` }
end
def create_model_with_fixture
diff --git a/railties/test/application/test_test.rb b/railties/test/application/test_test.rb
index c7132837b1..61652e5052 100644
--- a/railties/test/application/test_test.rb
+++ b/railties/test/application/test_test.rb
@@ -65,6 +65,7 @@ module ApplicationTests
output = run_test_file('unit/failing_test.rb', env: { "BACKTRACE" => "1" })
assert_match %r{/app/test/unit/failing_test\.rb}, output
+ assert_match %r{/app/test/unit/failing_test\.rb:4}, output
end
test "ruby schema migrations" do
@@ -300,23 +301,7 @@ Expected: ["id", "name"]
end
def run_test_file(name, options = {})
- ruby '-Itest', "#{app_path}/test/#{name}", options.deep_merge(env: {"RAILS_ENV" => "test"})
- end
-
- def ruby(*args)
- options = args.extract_options!
- env = options.fetch(:env, {})
- env["RUBYLIB"] = $:.join(':')
-
- Dir.chdir(app_path) do
- `#{env_string(env)} #{Gem.ruby} #{args.join(' ')} 2>&1`
- end
- end
-
- def env_string(variables)
- variables.map do |key, value|
- "#{key}='#{value}'"
- end.join " "
+ Dir.chdir(app_path) { `bin/rails test "#{app_path}/test/#{name}" 2>&1` }
end
end
end
diff --git a/railties/test/application/url_generation_test.rb b/railties/test/application/url_generation_test.rb
index ef16ab56ed..894e18cb39 100644
--- a/railties/test/application/url_generation_test.rb
+++ b/railties/test/application/url_generation_test.rb
@@ -42,5 +42,18 @@ module ApplicationTests
get "/"
assert_equal "/", last_response.body
end
+
+ def test_routes_know_the_relative_root
+ boot_rails
+ require "rails"
+ require "action_controller/railtie"
+ require "action_view/railtie"
+
+ relative_url = '/hello'
+ ENV["RAILS_RELATIVE_URL_ROOT"] = relative_url
+ app = Class.new(Rails::Application)
+ assert_equal relative_url, app.routes.relative_url_root
+ ENV["RAILS_RELATIVE_URL_ROOT"] = nil
+ end
end
end
diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb
index c6de2c1fb9..c0b88089b3 100644
--- a/railties/test/generators/actions_test.rb
+++ b/railties/test/generators/actions_test.rb
@@ -219,6 +219,30 @@ class ActionsTest < Rails::Generators::TestCase
assert_file 'config/routes.rb', /#{Regexp.escape(route_command)}/
end
+ def test_route_should_add_data_with_an_new_line
+ run_generator
+ action :route, "root 'welcome#index'"
+ route_path = File.expand_path("config/routes.rb", destination_root)
+ content = File.read(route_path)
+
+ # Remove all of the comments and blank lines from the routes file
+ content.gsub!(/^ \#.*\n/, '')
+ content.gsub!(/^\n/, '')
+
+ File.open(route_path, "wb") { |file| file.write(content) }
+ assert_file "config/routes.rb", /\.routes\.draw do\n root 'welcome#index'\nend\n\z/
+
+ action :route, "resources :product_lines"
+
+ routes = <<-F
+Rails.application.routes.draw do
+ resources :product_lines
+ root 'welcome#index'
+end
+F
+ assert_file "config/routes.rb", routes
+ end
+
def test_readme
run_generator
Rails::Generators::AppGenerator.expects(:source_root).times(2).returns(destination_root)
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index 4c5dd70a88..282e8cc4f9 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -18,6 +18,7 @@ DEFAULT_APP_FILES = %w(
app/mailers
app/models
app/models/concerns
+ app/jobs
app/views/layouts
bin/bundle
bin/rails
@@ -67,6 +68,11 @@ class AppGeneratorTest < Rails::Generators::TestCase
assert_file("app/assets/javascripts/application.js")
end
+ def test_application_job_file_present
+ run_generator
+ assert_file("app/jobs/application_job.rb")
+ end
+
def test_invalid_application_name_raises_an_error
content = capture(:stderr){ run_generator [File.join(destination_root, "43-things")] }
assert_equal "Invalid application name 43-things. Please give a name which does not start with numbers.\n", content
@@ -443,13 +449,6 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
end
- def test_inclusion_of_method_source
- run_generator
- assert_file "Gemfile" do |content|
- assert_gem 'method_source'
- end
- end
-
def test_template_from_dir_pwd
FileUtils.cd(Rails.root)
assert_match(/It works from file!/, run_generator([destination_root, "-m", "lib/template.rb"]))
diff --git a/railties/test/generators/job_generator_test.rb b/railties/test/generators/job_generator_test.rb
index a9e0cea94f..7fd8f2062f 100644
--- a/railties/test/generators/job_generator_test.rb
+++ b/railties/test/generators/job_generator_test.rb
@@ -7,14 +7,14 @@ class JobGeneratorTest < Rails::Generators::TestCase
def test_job_skeleton_is_created
run_generator ["refresh_counters"]
assert_file "app/jobs/refresh_counters_job.rb" do |job|
- assert_match(/class RefreshCountersJob < ActiveJob::Base/, job)
+ assert_match(/class RefreshCountersJob < ApplicationJob/, job)
end
end
def test_job_queue_param
run_generator ["refresh_counters", "--queue", "important"]
assert_file "app/jobs/refresh_counters_job.rb" do |job|
- assert_match(/class RefreshCountersJob < ActiveJob::Base/, job)
+ assert_match(/class RefreshCountersJob < ApplicationJob/, job)
assert_match(/queue_as :important/, job)
end
end
@@ -22,7 +22,7 @@ class JobGeneratorTest < Rails::Generators::TestCase
def test_job_namespace
run_generator ["admin/refresh_counters", "--queue", "admin"]
assert_file "app/jobs/admin/refresh_counters_job.rb" do |job|
- assert_match(/class Admin::RefreshCountersJob < ActiveJob::Base/, job)
+ assert_match(/class Admin::RefreshCountersJob < ApplicationJob/, job)
assert_match(/queue_as :admin/, job)
end
end
diff --git a/railties/test/generators/mailer_generator_test.rb b/railties/test/generators/mailer_generator_test.rb
index 584e7a82aa..f01e8cd2d9 100644
--- a/railties/test/generators/mailer_generator_test.rb
+++ b/railties/test/generators/mailer_generator_test.rb
@@ -47,13 +47,13 @@ class MailerGeneratorTest < Rails::Generators::TestCase
assert_match(/test "bar"/, test)
end
assert_file "test/mailers/previews/notifier_mailer_preview.rb" do |preview|
- assert_match(/\# Preview all emails at http:\/\/localhost\:3000\/rails\/mailers\/notifier/, preview)
+ assert_match(/\# Preview all emails at http:\/\/localhost\:3000\/rails\/mailers\/notifier_mailer/, preview)
assert_match(/class NotifierMailerPreview < ActionMailer::Preview/, preview)
- assert_match(/\# Preview this email at http:\/\/localhost\:3000\/rails\/mailers\/notifier\/foo/, preview)
+ assert_match(/\# Preview this email at http:\/\/localhost\:3000\/rails\/mailers\/notifier_mailer\/foo/, preview)
assert_instance_method :foo, preview do |foo|
assert_match(/NotifierMailer.foo/, foo)
end
- assert_match(/\# Preview this email at http:\/\/localhost\:3000\/rails\/mailers\/notifier\/bar/, preview)
+ assert_match(/\# Preview this email at http:\/\/localhost\:3000\/rails\/mailers\/notifier_mailer\/bar/, preview)
assert_instance_method :bar, preview do |bar|
assert_match(/NotifierMailer.bar/, bar)
end
@@ -129,9 +129,9 @@ class MailerGeneratorTest < Rails::Generators::TestCase
assert_match(/en\.farm\.animal_mailer\.moos\.subject/, mailer)
end
assert_file "test/mailers/previews/farm/animal_mailer_preview.rb" do |preview|
- assert_match(/\# Preview all emails at http:\/\/localhost\:3000\/rails\/mailers\/farm\/animal/, preview)
+ assert_match(/\# Preview all emails at http:\/\/localhost\:3000\/rails\/mailers\/farm\/animal_mailer/, preview)
assert_match(/class Farm::AnimalMailerPreview < ActionMailer::Preview/, preview)
- assert_match(/\# Preview this email at http:\/\/localhost\:3000\/rails\/mailers\/farm\/animal\/moos/, preview)
+ assert_match(/\# Preview this email at http:\/\/localhost\:3000\/rails\/mailers\/farm\/animal_mailer\/moos/, preview)
end
assert_file "app/views/farm/animal_mailer/moos.text.erb"
assert_file "app/views/farm/animal_mailer/moos.html.erb"
diff --git a/railties/test/generators/model_generator_test.rb b/railties/test/generators/model_generator_test.rb
index 17a13fbf1f..abd3ff50a4 100644
--- a/railties/test/generators/model_generator_test.rb
+++ b/railties/test/generators/model_generator_test.rb
@@ -319,6 +319,16 @@ class ModelGeneratorTest < Rails::Generators::TestCase
assert_no_file "test/fixtures/accounts.yml"
end
+ def test_fixture_without_pluralization
+ original_pluralize_table_name = ActiveRecord::Base.pluralize_table_names
+ ActiveRecord::Base.pluralize_table_names = false
+ run_generator
+ assert_generated_fixture("test/fixtures/account.yml",
+ {"one"=>{"name"=>"MyString", "age"=>1}, "two"=>{"name"=>"MyString", "age"=>1}})
+ ensure
+ ActiveRecord::Base.pluralize_table_names = original_pluralize_table_name
+ end
+
def test_check_class_collision
content = capture(:stderr){ run_generator ["object"] }
assert_match(/The name 'Object' is either already used in your application or reserved/, content)
diff --git a/railties/test/rails_info_controller_test.rb b/railties/test/rails_info_controller_test.rb
index d87b51d852..c51503c2b7 100644
--- a/railties/test/rails_info_controller_test.rb
+++ b/railties/test/rails_info_controller_test.rb
@@ -56,26 +56,26 @@ class InfoControllerTest < ActionController::TestCase
test "info controller returns exact matches" do
exact_count = -> { JSON(response.body)['exact'].size }
- get :routes, path: 'rails/info/route'
+ get :routes, params: { path: 'rails/info/route' }
assert exact_count.call == 0, 'should not match incomplete routes'
- get :routes, path: 'rails/info/routes'
+ get :routes, params: { path: 'rails/info/routes' }
assert exact_count.call == 1, 'should match complete routes'
-
- get :routes, path: 'rails/info/routes.html'
+
+ get :routes, params: { path: 'rails/info/routes.html' }
assert exact_count.call == 1, 'should match complete routes with optional parts'
end
test "info controller returns fuzzy matches" do
fuzzy_count = -> { JSON(response.body)['fuzzy'].size }
- get :routes, path: 'rails/info'
+ get :routes, params: { path: 'rails/info' }
assert fuzzy_count.call == 2, 'should match incomplete routes'
- get :routes, path: 'rails/info/routes'
+ get :routes, params: { path: 'rails/info/routes' }
assert fuzzy_count.call == 1, 'should match complete routes'
-
- get :routes, path: 'rails/info/routes.html'
+
+ get :routes, params: { path: 'rails/info/routes.html' }
assert fuzzy_count.call == 0, 'should match optional parts of route literally'
end
end
diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb
index 6185742cc1..79bd7a8241 100644
--- a/railties/test/railties/engine_test.rb
+++ b/railties/test/railties/engine_test.rb
@@ -1155,10 +1155,10 @@ YAML
assert_equal "App's bar partial", last_response.body.strip
get("/assets/foo.js")
- assert_equal "// Bukkit's foo js\n;", last_response.body.strip
+ assert_equal "// Bukkit's foo js", last_response.body.strip
get("/assets/bar.js")
- assert_equal "// App's bar js\n;", last_response.body.strip
+ assert_equal "// App's bar js", last_response.body.strip
# ensure that railties are not added twice
railties = Rails.application.send(:ordered_railties).map(&:class)
diff --git a/railties/test/test_unit/reporter_test.rb b/railties/test/test_unit/reporter_test.rb
new file mode 100644
index 0000000000..77883612f5
--- /dev/null
+++ b/railties/test/test_unit/reporter_test.rb
@@ -0,0 +1,74 @@
+require 'abstract_unit'
+require 'rails/test_unit/reporter'
+
+class TestUnitReporterTest < ActiveSupport::TestCase
+ class ExampleTest < Minitest::Test
+ def woot; end
+ end
+
+ setup do
+ @output = StringIO.new
+ @reporter = Rails::TestUnitReporter.new @output
+ end
+
+ test "prints rerun snippet to run a single failed test" do
+ @reporter.record(failed_test)
+ @reporter.report
+
+ assert_match %r{^bin/rails test .*test/test_unit/reporter_test.rb:6$}, @output.string
+ assert_rerun_snippet_count 1
+ end
+
+ test "prints rerun snippet for every failed test" do
+ @reporter.record(failed_test)
+ @reporter.record(failed_test)
+ @reporter.record(failed_test)
+ @reporter.report
+
+ assert_rerun_snippet_count 3
+ end
+
+ test "does not print snippet for successful and skipped tests" do
+ @reporter.record(passing_test)
+ @reporter.record(skipped_test)
+ @reporter.report
+ assert_rerun_snippet_count 0
+ end
+
+ test "prints rerun snippet for skipped tests if run in verbose mode" do
+ verbose = Rails::TestUnitReporter.new @output, verbose: true
+ verbose.record(skipped_test)
+ verbose.report
+
+ assert_rerun_snippet_count 1
+ end
+
+ private
+ def assert_rerun_snippet_count(snippet_count)
+ assert_equal snippet_count, @output.string.scan(%r{^bin/rails test }).size
+ end
+
+ def failed_test
+ ft = ExampleTest.new(:woot)
+ ft.failures << begin
+ raise Minitest::Assertion, "boo"
+ rescue Minitest::Assertion => e
+ e
+ end
+ ft
+ end
+
+ def passing_test
+ ExampleTest.new(:woot)
+ end
+
+ def skipped_test
+ st = ExampleTest.new(:woot)
+ st.failures << begin
+ raise Minitest::Skip
+ rescue Minitest::Assertion => e
+ e
+ end
+ st
+ end
+end
diff --git a/railties/test/test_unit/runner_test.rb b/railties/test/test_unit/runner_test.rb
new file mode 100644
index 0000000000..9ea8b2c114
--- /dev/null
+++ b/railties/test/test_unit/runner_test.rb
@@ -0,0 +1,111 @@
+require 'abstract_unit'
+require 'env_helpers'
+require 'rails/test_unit/runner'
+
+class TestUnitTestRunnerTest < ActiveSupport::TestCase
+ include EnvHelpers
+
+ setup do
+ @options = Rails::TestRunner::Options
+ end
+
+ test "shows the filtered backtrace by default" do
+ options = @options.parse([])
+ assert_not options[:backtrace]
+ end
+
+ test "has --backtrace (-b) option to show the full backtrace" do
+ options = @options.parse(["-b"])
+ assert options[:backtrace]
+
+ options = @options.parse(["--backtrace"])
+ assert options[:backtrace]
+ end
+
+ test "show full backtrace using BACKTRACE environment variable" do
+ switch_env "BACKTRACE", "true" do
+ options = @options.parse([])
+ assert options[:backtrace]
+ end
+ end
+
+ test "tests run in the test environment by default" do
+ options = @options.parse([])
+ assert_equal "test", options[:environment]
+ end
+
+ test "can run in a specific environment" do
+ options = @options.parse(["-e development"])
+ assert_equal "development", options[:environment]
+ end
+
+ test "parse the filename and line" do
+ file = "test/test_unit/runner_test.rb"
+ absolute_file = File.expand_path __FILE__
+ options = @options.parse(["#{file}:20"])
+ assert_equal absolute_file, options[:filename]
+ assert_equal 20, options[:line]
+
+ options = @options.parse(["#{file}:"])
+ assert_equal [absolute_file], options[:patterns]
+ assert_nil options[:line]
+
+ options = @options.parse([file])
+ assert_equal [absolute_file], options[:patterns]
+ assert_nil options[:line]
+ end
+
+ test "find_method on same file" do
+ options = @options.parse(["#{__FILE__}:#{__LINE__}"])
+ runner = Rails::TestRunner.new(options)
+ assert_equal "test_find_method_on_same_file", runner.find_method
+ end
+
+ test "find_method on a different file" do
+ options = @options.parse(["foobar.rb:#{__LINE__}"])
+ runner = Rails::TestRunner.new(options)
+ assert_nil runner.find_method
+ end
+
+ test "run all tests in a directory" do
+ options = @options.parse([__dir__])
+
+ assert_equal ["#{__dir__}/**/*_test.rb"], options[:patterns]
+ assert_nil options[:filename]
+ assert_nil options[:line]
+ end
+
+ test "run multiple folders" do
+ application_dir = File.expand_path("#{__dir__}/../application")
+
+ options = @options.parse([__dir__, application_dir])
+
+ assert_equal ["#{__dir__}/**/*_test.rb", "#{application_dir}/**/*_test.rb"], options[:patterns]
+ assert_nil options[:filename]
+ assert_nil options[:line]
+
+ runner = Rails::TestRunner.new(options)
+ assert runner.test_files.size > 0
+ end
+
+ test "run multiple files and run one file by line" do
+ line = __LINE__
+ absolute_file = File.expand_path(__FILE__)
+ options = @options.parse([__dir__, "#{__FILE__}:#{line}"])
+
+ assert_equal ["#{__dir__}/**/*_test.rb"], options[:patterns]
+ assert_equal absolute_file, options[:filename]
+ assert_equal line, options[:line]
+
+ runner = Rails::TestRunner.new(options)
+ assert_equal [absolute_file], runner.test_files, 'Only returns the file that running by line'
+ end
+
+ test "running multiple files passing line number" do
+ line = __LINE__
+ options = @options.parse(["foobar.rb:8", "#{__FILE__}:#{line}"])
+
+ assert_equal File.expand_path(__FILE__), options[:filename], 'Returns the last file'
+ assert_equal line, options[:line]
+ end
+end
diff --git a/tools/line_statistics b/tools/line_statistics
index bfa921b095..d0b3557d7d 100644
--- a/tools/line_statistics
+++ b/tools/line_statistics
@@ -1,4 +1,4 @@
-# Class used to calculates LOC for a provided file list.
+# Class used to calculate LOC for a provided file list.
#
# Example:
# files = FileList["lib/active_record/**/*.rb"]