aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.codeclimate.yml2
-rw-r--r--.rubocop.yml17
-rw-r--r--Gemfile5
-rw-r--r--Gemfile.lock102
-rw-r--r--RELEASING_RAILS.md2
-rw-r--r--actioncable/lib/action_cable/server/broadcasting.rb2
-rw-r--r--actioncable/lib/action_cable/server/worker.rb1
-rw-r--r--actionmailbox/CHANGELOG.md3
-rw-r--r--actionmailbox/app/controllers/rails/conductor/action_mailbox/inbound_emails_controller.rb3
-rw-r--r--actionmailbox/lib/action_mailbox/router.rb10
-rw-r--r--actionmailbox/lib/action_mailbox/routing.rb4
-rw-r--r--actionmailbox/lib/rails/generators/test_unit/templates/mailbox_test.rb.tt2
-rw-r--r--actionmailbox/test/controllers/rails/action_mailbox/inbound_emails_controller_test.rb5
-rw-r--r--actionmailbox/test/unit/mailbox/routing_test.rb5
-rw-r--r--actionmailbox/test/unit/router_test.rb14
-rw-r--r--actionmailer/lib/action_mailer/base.rb2
-rw-r--r--actionmailer/lib/action_mailer/preview.rb1
-rw-r--r--actionmailer/lib/action_mailer/test_case.rb2
-rw-r--r--actionmailer/lib/action_mailer/test_helper.rb1
-rw-r--r--actionmailer/test/base_test.rb1
-rw-r--r--actionmailer/test/caching_test.rb1
-rw-r--r--actionmailer/test/i18n_with_controller_test.rb1
-rw-r--r--actionmailer/test/legacy_delivery_job_test.rb1
-rw-r--r--actionmailer/test/mail_helper_test.rb1
-rw-r--r--actionmailer/test/mailers/proc_mailer.rb1
-rw-r--r--actionmailer/test/parameterized_test.rb1
-rw-r--r--actionpack/CHANGELOG.md76
-rw-r--r--actionpack/lib/abstract_controller.rb1
-rw-r--r--actionpack/lib/abstract_controller/base.rb1
-rw-r--r--actionpack/lib/abstract_controller/collector.rb1
-rw-r--r--actionpack/lib/abstract_controller/helpers.rb30
-rw-r--r--actionpack/lib/action_controller.rb2
-rw-r--r--actionpack/lib/action_controller/base.rb1
-rw-r--r--actionpack/lib/action_controller/caching.rb1
-rw-r--r--actionpack/lib/action_controller/metal.rb3
-rw-r--r--actionpack/lib/action_controller/metal/content_security_policy.rb1
-rw-r--r--actionpack/lib/action_controller/metal/data_streaming.rb2
-rw-r--r--actionpack/lib/action_controller/metal/feature_policy.rb46
-rw-r--r--actionpack/lib/action_controller/metal/instrumentation.rb1
-rw-r--r--actionpack/lib/action_controller/metal/live.rb4
-rw-r--r--actionpack/lib/action_controller/metal/mime_responds.rb2
-rw-r--r--actionpack/lib/action_controller/metal/params_wrapper.rb1
-rw-r--r--actionpack/lib/action_controller/metal/renderers.rb2
-rw-r--r--actionpack/lib/action_controller/metal/rendering.rb3
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb2
-rw-r--r--actionpack/lib/action_controller/metal/streaming.rb1
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb70
-rw-r--r--actionpack/lib/action_controller/template_assertions.rb2
-rw-r--r--actionpack/lib/action_controller/test_case.rb3
-rw-r--r--actionpack/lib/action_dispatch.rb1
-rw-r--r--actionpack/lib/action_dispatch/http/cache.rb1
-rw-r--r--actionpack/lib/action_dispatch/http/content_security_policy.rb35
-rw-r--r--actionpack/lib/action_dispatch/http/feature_policy.rb168
-rw-r--r--actionpack/lib/action_dispatch/http/filter_parameters.rb1
-rw-r--r--actionpack/lib/action_dispatch/http/filter_redirect.rb1
-rw-r--r--actionpack/lib/action_dispatch/http/headers.rb1
-rw-r--r--actionpack/lib/action_dispatch/http/mime_negotiation.rb1
-rw-r--r--actionpack/lib/action_dispatch/http/mime_type.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/parameters.rb1
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb1
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb21
-rw-r--r--actionpack/lib/action_dispatch/http/url.rb1
-rw-r--r--actionpack/lib/action_dispatch/journey/formatter.rb3
-rw-r--r--actionpack/lib/action_dispatch/journey/gtg/builder.rb1
-rw-r--r--actionpack/lib/action_dispatch/journey/gtg/transition_table.rb1
-rw-r--r--actionpack/lib/action_dispatch/journey/nfa/transition_table.rb1
-rw-r--r--actionpack/lib/action_dispatch/journey/path/pattern.rb1
-rw-r--r--actionpack/lib/action_dispatch/journey/route.rb12
-rw-r--r--actionpack/lib/action_dispatch/journey/router.rb1
-rw-r--r--actionpack/lib/action_dispatch/journey/routes.rb1
-rw-r--r--actionpack/lib/action_dispatch/journey/scanner.rb1
-rw-r--r--actionpack/lib/action_dispatch/journey/visitors.rb3
-rw-r--r--actionpack/lib/action_dispatch/middleware/cookies.rb6
-rw-r--r--actionpack/lib/action_dispatch/middleware/debug_exceptions.rb7
-rw-r--r--actionpack/lib/action_dispatch/middleware/debug_view.rb6
-rw-r--r--actionpack/lib/action_dispatch/middleware/exception_wrapper.rb16
-rw-r--r--actionpack/lib/action_dispatch/middleware/host_authorization.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/public_exceptions.rb1
-rw-r--r--actionpack/lib/action_dispatch/middleware/remote_ip.rb1
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/abstract_store.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/cookie_store.rb1
-rw-r--r--actionpack/lib/action_dispatch/middleware/show_exceptions.rb1
-rw-r--r--actionpack/lib/action_dispatch/middleware/stack.rb16
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb4
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb71
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb11
-rw-r--r--actionpack/lib/action_dispatch/railtie.rb2
-rw-r--r--actionpack/lib/action_dispatch/request/session.rb1
-rw-r--r--actionpack/lib/action_dispatch/routing/inspector.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb41
-rw-r--r--actionpack/lib/action_dispatch/routing/polymorphic_routes.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb3
-rw-r--r--actionpack/lib/action_dispatch/routing/url_for.rb2
-rw-r--r--actionpack/lib/action_dispatch/system_test_case.rb38
-rw-r--r--actionpack/lib/action_dispatch/system_testing/browser.rb23
-rw-r--r--actionpack/lib/action_dispatch/system_testing/driver.rb2
-rw-r--r--actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb12
-rw-r--r--actionpack/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb26
-rw-r--r--actionpack/lib/action_dispatch/testing/assertion_response.rb1
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions.rb2
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb12
-rw-r--r--actionpack/lib/action_dispatch/testing/test_response.rb2
-rw-r--r--actionpack/test/abstract_unit.rb1
-rw-r--r--actionpack/test/controller/api/conditional_get_test.rb1
-rw-r--r--actionpack/test/controller/content_type_test.rb29
-rw-r--r--actionpack/test/controller/filters_test.rb3
-rw-r--r--actionpack/test/controller/flash_test.rb1
-rw-r--r--actionpack/test/controller/helper_test.rb4
-rw-r--r--actionpack/test/controller/http_basic_authentication_test.rb2
-rw-r--r--actionpack/test/controller/http_digest_authentication_test.rb2
-rw-r--r--actionpack/test/controller/http_token_authentication_test.rb2
-rw-r--r--actionpack/test/controller/integration_test.rb21
-rw-r--r--actionpack/test/controller/localized_templates_test.rb2
-rw-r--r--actionpack/test/controller/metal/renderers_test.rb4
-rw-r--r--actionpack/test/controller/mime/accept_format_test.rb1
-rw-r--r--actionpack/test/controller/mime/respond_to_test.rb78
-rw-r--r--actionpack/test/controller/new_base/render_template_test.rb1
-rw-r--r--actionpack/test/controller/new_base/render_test.rb1
-rw-r--r--actionpack/test/controller/parameters/accessors_test.rb33
-rw-r--r--actionpack/test/controller/parameters/log_on_unpermitted_params_test.rb1
-rw-r--r--actionpack/test/controller/parameters/mutators_test.rb27
-rw-r--r--actionpack/test/controller/parameters/nested_parameters_permit_test.rb30
-rw-r--r--actionpack/test/controller/params_parse_test.rb1
-rw-r--r--actionpack/test/controller/params_wrapper_test.rb1
-rw-r--r--actionpack/test/controller/render_js_test.rb3
-rw-r--r--actionpack/test/controller/render_json_test.rb15
-rw-r--r--actionpack/test/controller/render_test.rb25
-rw-r--r--actionpack/test/controller/render_xml_test.rb5
-rw-r--r--actionpack/test/controller/renderers_test.rb4
-rw-r--r--actionpack/test/controller/request_forgery_protection_test.rb1
-rw-r--r--actionpack/test/controller/rescue_test.rb2
-rw-r--r--actionpack/test/controller/resources_test.rb5
-rw-r--r--actionpack/test/controller/show_exceptions_test.rb11
-rw-r--r--actionpack/test/controller/test_case_test.rb1
-rw-r--r--actionpack/test/dispatch/callbacks_test.rb1
-rw-r--r--actionpack/test/dispatch/content_security_policy_test.rb80
-rw-r--r--actionpack/test/dispatch/debug_exceptions_test.rb72
-rw-r--r--actionpack/test/dispatch/feature_policy_test.rb142
-rw-r--r--actionpack/test/dispatch/middleware_stack_test.rb6
-rw-r--r--actionpack/test/dispatch/request_id_test.rb2
-rw-r--r--actionpack/test/dispatch/request_test.rb1
-rw-r--r--actionpack/test/dispatch/response_test.rb65
-rw-r--r--actionpack/test/dispatch/routing_test.rb44
-rw-r--r--actionpack/test/dispatch/session/cookie_store_test.rb1
-rw-r--r--actionpack/test/dispatch/static_test.rb1
-rw-r--r--actionpack/test/dispatch/system_testing/driver_test.rb17
-rw-r--r--actionpack/test/dispatch/system_testing/system_test_case_test.rb45
-rw-r--r--actionpack/test/journey/route/definition/scanner_test.rb1
-rw-r--r--actionpack/test/journey/route_test.rb41
-rw-r--r--actionpack/test/journey/router_test.rb1
-rw-r--r--actiontext/.gitignore1
-rw-r--r--actiontext/CHANGELOG.md18
-rw-r--r--actiontext/Rakefile8
-rw-r--r--actiontext/app/models/action_text/rich_text.rb2
-rw-r--r--actiontext/lib/action_text/engine.rb11
-rw-r--r--actiontext/lib/action_text/system_test_helper.rb48
-rw-r--r--actiontext/test/application_system_test_case.rb9
-rw-r--r--actiontext/test/dummy/.babelrc18
-rw-r--r--actiontext/test/dummy/.browserslistrc1
-rw-r--r--actiontext/test/dummy/app/javascript/packs/application.js1
-rw-r--r--actiontext/test/dummy/app/views/messages/_form.html.erb3
-rw-r--r--actiontext/test/dummy/babel.config.js70
-rwxr-xr-xactiontext/test/dummy/bin/bundle2
-rwxr-xr-xactiontext/test/dummy/bin/webpack19
-rwxr-xr-xactiontext/test/dummy/bin/webpack-dev-server19
-rw-r--r--actiontext/test/dummy/config/webpack/development.js2
-rw-r--r--actiontext/test/dummy/config/webpack/production.js2
-rw-r--r--actiontext/test/dummy/config/webpack/test.js2
-rw-r--r--actiontext/test/dummy/config/webpacker.yml32
-rw-r--r--actiontext/test/dummy/package.json5
-rw-r--r--actiontext/test/dummy/postcss.config.js12
-rw-r--r--actiontext/test/dummy/yarn.lock2741
-rw-r--r--actiontext/test/system/system_test_helper_test.rb39
-rw-r--r--actiontext/test/unit/attachment_test.rb5
-rw-r--r--actiontext/test/unit/model_test.rb9
-rw-r--r--actionview/CHANGELOG.md16
-rw-r--r--actionview/app/assets/javascripts/README.md2
-rw-r--r--actionview/app/assets/javascripts/rails-ujs/features/remote.coffee4
-rw-r--r--actionview/lib/action_view.rb1
-rw-r--r--actionview/lib/action_view/base.rb1
-rw-r--r--actionview/lib/action_view/cache_expiry.rb22
-rw-r--r--actionview/lib/action_view/flows.rb1
-rw-r--r--actionview/lib/action_view/helpers/active_model_helper.rb1
-rw-r--r--actionview/lib/action_view/helpers/asset_tag_helper.rb3
-rw-r--r--actionview/lib/action_view/helpers/asset_url_helper.rb2
-rw-r--r--actionview/lib/action_view/helpers/cache_helper.rb1
-rw-r--r--actionview/lib/action_view/helpers/date_helper.rb1
-rw-r--r--actionview/lib/action_view/helpers/form_tag_helper.rb3
-rw-r--r--actionview/lib/action_view/helpers/number_helper.rb3
-rw-r--r--actionview/lib/action_view/helpers/rendering_helper.rb6
-rw-r--r--actionview/lib/action_view/helpers/tags/base.rb1
-rw-r--r--actionview/lib/action_view/helpers/tags/check_box.rb1
-rw-r--r--actionview/lib/action_view/helpers/tags/collection_check_boxes.rb1
-rw-r--r--actionview/lib/action_view/helpers/tags/collection_helpers.rb1
-rw-r--r--actionview/lib/action_view/helpers/tags/collection_radio_buttons.rb1
-rw-r--r--actionview/lib/action_view/helpers/tags/color_field.rb1
-rw-r--r--actionview/lib/action_view/helpers/tags/date_field.rb1
-rw-r--r--actionview/lib/action_view/helpers/tags/date_select.rb1
-rw-r--r--actionview/lib/action_view/helpers/tags/datetime_field.rb1
-rw-r--r--actionview/lib/action_view/helpers/tags/datetime_local_field.rb1
-rw-r--r--actionview/lib/action_view/helpers/tags/label.rb1
-rw-r--r--actionview/lib/action_view/helpers/tags/month_field.rb1
-rw-r--r--actionview/lib/action_view/helpers/tags/radio_button.rb1
-rw-r--r--actionview/lib/action_view/helpers/tags/select.rb1
-rw-r--r--actionview/lib/action_view/helpers/tags/text_field.rb1
-rw-r--r--actionview/lib/action_view/helpers/tags/time_field.rb1
-rw-r--r--actionview/lib/action_view/helpers/tags/week_field.rb1
-rw-r--r--actionview/lib/action_view/helpers/text_helper.rb1
-rw-r--r--actionview/lib/action_view/helpers/translation_helper.rb2
-rw-r--r--actionview/lib/action_view/helpers/url_helper.rb58
-rw-r--r--actionview/lib/action_view/layouts.rb3
-rw-r--r--actionview/lib/action_view/log_subscriber.rb1
-rw-r--r--actionview/lib/action_view/lookup_context.rb3
-rw-r--r--actionview/lib/action_view/path_set.rb1
-rw-r--r--actionview/lib/action_view/record_identifier.rb1
-rw-r--r--actionview/lib/action_view/renderer/abstract_renderer.rb1
-rw-r--r--actionview/lib/action_view/renderer/partial_renderer.rb7
-rw-r--r--actionview/lib/action_view/renderer/streaming_template_renderer.rb2
-rw-r--r--actionview/lib/action_view/renderer/template_renderer.rb1
-rw-r--r--actionview/lib/action_view/rendering.rb1
-rw-r--r--actionview/lib/action_view/template.rb3
-rw-r--r--actionview/lib/action_view/template/error.rb21
-rw-r--r--actionview/lib/action_view/template/handlers.rb2
-rw-r--r--actionview/lib/action_view/template/handlers/erb.rb1
-rw-r--r--actionview/lib/action_view/template/html.rb2
-rw-r--r--actionview/lib/action_view/template/resolver.rb12
-rw-r--r--actionview/lib/action_view/test_case.rb2
-rw-r--r--actionview/lib/action_view/testing/resolvers.rb39
-rw-r--r--actionview/lib/action_view/unbound_template.rb7
-rw-r--r--actionview/lib/action_view/view_paths.rb1
-rw-r--r--actionview/test/abstract_unit.rb2
-rw-r--r--actionview/test/actionpack/abstract/abstract_controller_test.rb2
-rw-r--r--actionview/test/actionpack/abstract/layouts_test.rb3
-rw-r--r--actionview/test/actionpack/controller/render_test.rb25
-rw-r--r--actionview/test/active_record_unit.rb10
-rw-r--r--actionview/test/activerecord/form_helper_activerecord_test.rb1
-rw-r--r--actionview/test/lib/test_component.rb45
-rw-r--r--actionview/test/template/compiled_templates_test.rb40
-rw-r--r--actionview/test/template/form_helper_test.rb1
-rw-r--r--actionview/test/template/form_options_helper_test.rb1
-rw-r--r--actionview/test/template/form_tag_helper_test.rb8
-rw-r--r--actionview/test/template/render_test.rb36
-rw-r--r--actionview/test/template/template_error_test.rb16
-rw-r--r--actionview/test/template/testing/fixture_resolver_test.rb22
-rw-r--r--actionview/test/template/translation_helper_test.rb5
-rw-r--r--actionview/test/template/url_helper_test.rb62
-rw-r--r--actionview/test/ujs/public/test/data-remote.js14
-rw-r--r--activejob/CHANGELOG.md3
-rw-r--r--activejob/lib/active_job/arguments.rb1
-rw-r--r--activejob/lib/active_job/serializers/date_serializer.rb1
-rw-r--r--activejob/lib/active_job/serializers/date_time_serializer.rb1
-rw-r--r--activejob/lib/active_job/serializers/duration_serializer.rb1
-rw-r--r--activejob/lib/active_job/serializers/object_serializer.rb1
-rw-r--r--activejob/lib/active_job/serializers/symbol_serializer.rb1
-rw-r--r--activejob/lib/active_job/serializers/time_serializer.rb1
-rw-r--r--activejob/lib/active_job/serializers/time_with_zone_serializer.rb1
-rw-r--r--activejob/lib/active_job/test_helper.rb3
-rw-r--r--activejob/test/cases/serializers_test.rb1
-rw-r--r--activejob/test/cases/test_helper_test.rb18
-rw-r--r--activejob/test/jobs/timezone_dependent_job.rb1
-rw-r--r--activejob/test/support/integration/test_case_helpers.rb1
-rw-r--r--activemodel/lib/active_model.rb1
-rw-r--r--activemodel/lib/active_model/attribute_assignment.rb1
-rw-r--r--activemodel/lib/active_model/attribute_methods.rb10
-rw-r--r--activemodel/lib/active_model/attribute_set.rb2
-rw-r--r--activemodel/lib/active_model/attributes.rb2
-rw-r--r--activemodel/lib/active_model/callbacks.rb1
-rw-r--r--activemodel/lib/active_model/dirty.rb2
-rw-r--r--activemodel/lib/active_model/error.rb96
-rw-r--r--activemodel/lib/active_model/errors.rb99
-rw-r--r--activemodel/lib/active_model/naming.rb1
-rw-r--r--activemodel/lib/active_model/railtie.rb2
-rw-r--r--activemodel/lib/active_model/serialization.rb1
-rw-r--r--activemodel/lib/active_model/serializers/json.rb7
-rw-r--r--activemodel/lib/active_model/type/big_integer.rb1
-rw-r--r--activemodel/lib/active_model/type/boolean.rb1
-rw-r--r--activemodel/lib/active_model/type/date.rb1
-rw-r--r--activemodel/lib/active_model/type/date_time.rb1
-rw-r--r--activemodel/lib/active_model/type/decimal.rb1
-rw-r--r--activemodel/lib/active_model/type/float.rb1
-rw-r--r--activemodel/lib/active_model/type/helpers/numeric.rb1
-rw-r--r--activemodel/lib/active_model/type/helpers/time_value.rb22
-rw-r--r--activemodel/lib/active_model/type/immutable_string.rb1
-rw-r--r--activemodel/lib/active_model/type/integer.rb5
-rw-r--r--activemodel/lib/active_model/type/string.rb1
-rw-r--r--activemodel/lib/active_model/type/time.rb1
-rw-r--r--activemodel/lib/active_model/type/value.rb3
-rw-r--r--activemodel/lib/active_model/validations.rb1
-rw-r--r--activemodel/lib/active_model/validations/acceptance.rb1
-rw-r--r--activemodel/lib/active_model/validations/callbacks.rb1
-rw-r--r--activemodel/lib/active_model/validations/clusivity.rb1
-rw-r--r--activemodel/lib/active_model/validations/format.rb1
-rw-r--r--activemodel/lib/active_model/validations/numericality.rb1
-rw-r--r--activemodel/lib/active_model/validations/validates.rb1
-rw-r--r--activemodel/lib/active_model/validator.rb1
-rw-r--r--activemodel/test/cases/attribute_methods_test.rb1
-rw-r--r--activemodel/test/cases/errors_test.rb68
-rw-r--r--activemodel/test/cases/nested_error_test.rb2
-rw-r--r--activemodel/test/cases/railtie_test.rb6
-rw-r--r--activemodel/test/cases/type/date_time_test.rb1
-rw-r--r--activemodel/test/cases/validations/acceptance_validation_test.rb1
-rw-r--r--activemodel/test/cases/validations/i18n_validation_test.rb99
-rw-r--r--activemodel/test/cases/validations/numericality_validation_test.rb1
-rw-r--r--activerecord/CHANGELOG.md57
-rw-r--r--activerecord/lib/active_record/aggregations.rb1
-rw-r--r--activerecord/lib/active_record/association_relation.rb1
-rw-r--r--activerecord/lib/active_record/associations/alias_tracker.rb1
-rw-r--r--activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb2
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb2
-rw-r--r--activerecord/lib/active_record/associations/collection_proxy.rb3
-rw-r--r--activerecord/lib/active_record/associations/has_many_association.rb1
-rw-r--r--activerecord/lib/active_record/associations/join_dependency/join_association.rb13
-rw-r--r--activerecord/lib/active_record/associations/preloader.rb1
-rw-r--r--activerecord/lib/active_record/associations/preloader/association.rb4
-rw-r--r--activerecord/lib/active_record/attribute_assignment.rb1
-rw-r--r--activerecord/lib/active_record/attribute_decorators.rb2
-rw-r--r--activerecord/lib/active_record/attribute_methods.rb57
-rw-r--r--activerecord/lib/active_record/attribute_methods/before_type_cast.rb1
-rw-r--r--activerecord/lib/active_record/attribute_methods/dirty.rb7
-rw-r--r--activerecord/lib/active_record/attribute_methods/primary_key.rb2
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb1
-rw-r--r--activerecord/lib/active_record/attribute_methods/serialization.rb1
-rw-r--r--activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb2
-rw-r--r--activerecord/lib/active_record/attribute_methods/write.rb1
-rw-r--r--activerecord/lib/active_record/attributes.rb1
-rw-r--r--activerecord/lib/active_record/autosave_association.rb6
-rw-r--r--activerecord/lib/active_record/base.rb1
-rw-r--r--activerecord/lib/active_record/callbacks.rb1
-rw-r--r--activerecord/lib/active_record/coders/yaml_column.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb105
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb7
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/quoting.rb63
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/savepoints.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb3
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb41
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/transaction.rb72
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb62
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb33
-rw-r--r--activerecord/lib/active_record/connection_adapters/column.rb14
-rw-r--r--activerecord/lib/active_record/connection_adapters/connection_specification.rb3
-rw-r--r--activerecord/lib/active_record/connection_adapters/deduplicable.rb29
-rw-r--r--activerecord/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb9
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/quoting.rb51
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/schema_creation.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb11
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/column.rb23
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/money.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/uuid.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb41
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb7
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb8
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/utils.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb10
-rw-r--r--activerecord/lib/active_record/connection_adapters/schema_cache.rb55
-rw-r--r--activerecord/lib/active_record/connection_adapters/sql_type_metadata.rb10
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3/database_statements.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb41
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb29
-rw-r--r--activerecord/lib/active_record/connection_adapters/statement_pool.rb1
-rw-r--r--activerecord/lib/active_record/connection_handling.rb9
-rw-r--r--activerecord/lib/active_record/core.rb2
-rw-r--r--activerecord/lib/active_record/database_configurations.rb58
-rw-r--r--activerecord/lib/active_record/database_configurations/url_config.rb1
-rw-r--r--activerecord/lib/active_record/dynamic_matchers.rb1
-rw-r--r--activerecord/lib/active_record/enum.rb9
-rw-r--r--activerecord/lib/active_record/errors.rb16
-rw-r--r--activerecord/lib/active_record/explain.rb1
-rw-r--r--activerecord/lib/active_record/fixture_set/table_row.rb1
-rw-r--r--activerecord/lib/active_record/fixture_set/table_rows.rb1
-rw-r--r--activerecord/lib/active_record/fixtures.rb3
-rw-r--r--activerecord/lib/active_record/inheritance.rb3
-rw-r--r--activerecord/lib/active_record/integration.rb2
-rw-r--r--activerecord/lib/active_record/internal_metadata.rb4
-rw-r--r--activerecord/lib/active_record/locking/optimistic.rb1
-rw-r--r--activerecord/lib/active_record/middleware/database_selector.rb7
-rw-r--r--activerecord/lib/active_record/middleware/database_selector/resolver.rb5
-rw-r--r--activerecord/lib/active_record/migration.rb52
-rw-r--r--activerecord/lib/active_record/migration/command_recorder.rb1
-rw-r--r--activerecord/lib/active_record/migration/join_table.rb1
-rw-r--r--activerecord/lib/active_record/model_schema.rb5
-rw-r--r--activerecord/lib/active_record/nested_attributes.rb3
-rw-r--r--activerecord/lib/active_record/null_relation.rb1
-rw-r--r--activerecord/lib/active_record/persistence.rb3
-rw-r--r--activerecord/lib/active_record/railtie.rb1
-rw-r--r--activerecord/lib/active_record/railties/databases.rake89
-rw-r--r--activerecord/lib/active_record/readonly_attributes.rb4
-rw-r--r--activerecord/lib/active_record/reflection.rb2
-rw-r--r--activerecord/lib/active_record/relation.rb14
-rw-r--r--activerecord/lib/active_record/relation/batches.rb1
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb2
-rw-r--r--activerecord/lib/active_record/relation/delegation.rb2
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb3
-rw-r--r--activerecord/lib/active_record/relation/merger.rb1
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb68
-rw-r--r--activerecord/lib/active_record/relation/spawn_methods.rb1
-rw-r--r--activerecord/lib/active_record/relation/where_clause.rb1
-rw-r--r--activerecord/lib/active_record/result.rb1
-rw-r--r--activerecord/lib/active_record/sanitization.rb32
-rw-r--r--activerecord/lib/active_record/schema.rb2
-rw-r--r--activerecord/lib/active_record/schema_dumper.rb6
-rw-r--r--activerecord/lib/active_record/schema_migration.rb4
-rw-r--r--activerecord/lib/active_record/scoping.rb1
-rw-r--r--activerecord/lib/active_record/scoping/default.rb1
-rw-r--r--activerecord/lib/active_record/scoping/named.rb1
-rw-r--r--activerecord/lib/active_record/table_metadata.rb16
-rw-r--r--activerecord/lib/active_record/tasks/database_tasks.rb51
-rw-r--r--activerecord/lib/active_record/tasks/mysql_database_tasks.rb5
-rw-r--r--activerecord/lib/active_record/tasks/postgresql_database_tasks.rb1
-rw-r--r--activerecord/lib/active_record/tasks/sqlite_database_tasks.rb1
-rw-r--r--activerecord/lib/active_record/test_fixtures.rb1
-rw-r--r--activerecord/lib/active_record/timestamp.rb43
-rw-r--r--activerecord/lib/active_record/touch_later.rb3
-rw-r--r--activerecord/lib/active_record/transactions.rb21
-rw-r--r--activerecord/lib/active_record/type.rb1
-rw-r--r--activerecord/lib/active_record/type/adapter_specific_registry.rb3
-rw-r--r--activerecord/lib/active_record/type/hash_lookup_type_map.rb1
-rw-r--r--activerecord/lib/active_record/type/serialized.rb1
-rw-r--r--activerecord/lib/active_record/type/type_map.rb1
-rw-r--r--activerecord/lib/active_record/type/unsigned_integer.rb1
-rw-r--r--activerecord/lib/active_record/type_caster/connection.rb26
-rw-r--r--activerecord/lib/active_record/validations.rb1
-rw-r--r--activerecord/lib/active_record/validations/associated.rb1
-rw-r--r--activerecord/lib/arel.rb2
-rw-r--r--activerecord/lib/arel/attributes.rb22
-rw-r--r--activerecord/lib/arel/nodes/node.rb8
-rw-r--r--activerecord/lib/arel/predications.rb5
-rw-r--r--activerecord/lib/arel/visitors.rb1
-rw-r--r--activerecord/lib/arel/visitors/depth_first.rb204
-rw-r--r--activerecord/lib/arel/visitors/dot.rb1
-rw-r--r--activerecord/lib/arel/visitors/mssql.rb1
-rw-r--r--activerecord/lib/arel/visitors/oracle.rb1
-rw-r--r--activerecord/lib/arel/visitors/oracle12.rb1
-rw-r--r--activerecord/lib/arel/visitors/postgresql.rb1
-rw-r--r--activerecord/lib/arel/visitors/sqlite.rb1
-rw-r--r--activerecord/lib/arel/visitors/to_sql.rb56
-rw-r--r--activerecord/lib/arel/visitors/visitor.rb15
-rw-r--r--activerecord/lib/arel/visitors/where_sql.rb1
-rw-r--r--activerecord/lib/rails/generators/active_record/application_record/application_record_generator.rb1
-rw-r--r--activerecord/lib/rails/generators/active_record/migration.rb1
-rw-r--r--activerecord/lib/rails/generators/active_record/migration/migration_generator.rb1
-rw-r--r--activerecord/lib/rails/generators/active_record/model/model_generator.rb1
-rw-r--r--activerecord/test/active_record/connection_adapters/fake_adapter.rb3
-rw-r--r--activerecord/test/cases/adapter_test.rb12
-rw-r--r--activerecord/test/cases/adapters/mysql2/annotate_test.rb37
-rw-r--r--activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb10
-rw-r--r--activerecord/test/cases/adapters/mysql2/connection_test.rb1
-rw-r--r--activerecord/test/cases/adapters/mysql2/enum_test.rb14
-rw-r--r--activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb45
-rw-r--r--activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb1
-rw-r--r--activerecord/test/cases/adapters/mysql2/set_test.rb32
-rw-r--r--activerecord/test/cases/adapters/mysql2/table_options_test.rb4
-rw-r--r--activerecord/test/cases/adapters/mysql2/transaction_test.rb6
-rw-r--r--activerecord/test/cases/adapters/postgresql/annotate_test.rb37
-rw-r--r--activerecord/test/cases/adapters/postgresql/connection_test.rb1
-rw-r--r--activerecord/test/cases/adapters/postgresql/extension_migration_test.rb12
-rw-r--r--activerecord/test/cases/adapters/postgresql/geometric_test.rb1
-rw-r--r--activerecord/test/cases/adapters/postgresql/money_test.rb4
-rw-r--r--activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb34
-rw-r--r--activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb5
-rw-r--r--activerecord/test/cases/adapters/postgresql/rename_table_test.rb1
-rw-r--r--activerecord/test/cases/adapters/postgresql/schema_test.rb6
-rw-r--r--activerecord/test/cases/adapters/postgresql/transaction_test.rb1
-rw-r--r--activerecord/test/cases/adapters/postgresql/uuid_test.rb8
-rw-r--r--activerecord/test/cases/adapters/sqlite3/annotate_test.rb37
-rw-r--r--activerecord/test/cases/adapters/sqlite3/collation_test.rb9
-rw-r--r--activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb31
-rw-r--r--activerecord/test/cases/annotate_test.rb46
-rw-r--r--activerecord/test/cases/ar_schema_test.rb27
-rw-r--r--activerecord/test/cases/arel/attributes/attribute_test.rb24
-rw-r--r--activerecord/test/cases/arel/attributes_test.rb41
-rw-r--r--activerecord/test/cases/arel/nodes/node_test.rb19
-rw-r--r--activerecord/test/cases/arel/select_manager_test.rb10
-rw-r--r--activerecord/test/cases/arel/visitors/depth_first_test.rb276
-rw-r--r--activerecord/test/cases/arel/visitors/dispatch_contamination_test.rb8
-rw-r--r--activerecord/test/cases/associations/cascaded_eager_loading_test.rb24
-rw-r--r--activerecord/test/cases/associations/eager_load_nested_include_test.rb1
-rw-r--r--activerecord/test/cases/associations/eager_test.rb36
-rw-r--r--activerecord/test/cases/associations/extension_test.rb1
-rw-r--r--activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb16
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb86
-rw-r--r--activerecord/test/cases/associations/has_many_through_associations_test.rb18
-rw-r--r--activerecord/test/cases/associations/has_one_associations_test.rb5
-rw-r--r--activerecord/test/cases/associations/nested_through_associations_test.rb1
-rw-r--r--activerecord/test/cases/associations/required_test.rb1
-rw-r--r--activerecord/test/cases/attribute_methods_test.rb1
-rw-r--r--activerecord/test/cases/attributes_test.rb6
-rw-r--r--activerecord/test/cases/autosave_association_test.rb79
-rw-r--r--activerecord/test/cases/base_test.rb84
-rw-r--r--activerecord/test/cases/batches_test.rb2
-rw-r--r--activerecord/test/cases/bind_parameter_test.rb2
-rw-r--r--activerecord/test/cases/calculations_test.rb45
-rw-r--r--activerecord/test/cases/comment_test.rb25
-rw-r--r--activerecord/test/cases/connection_adapters/connection_handler_test.rb15
-rw-r--r--activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb90
-rw-r--r--activerecord/test/cases/connection_adapters/mysql_type_lookup_test.rb3
-rw-r--r--activerecord/test/cases/connection_adapters/type_lookup_test.rb1
-rw-r--r--activerecord/test/cases/connection_pool_test.rb23
-rw-r--r--activerecord/test/cases/database_statements_test.rb1
-rw-r--r--activerecord/test/cases/enum_test.rb22
-rw-r--r--activerecord/test/cases/explain_test.rb1
-rw-r--r--activerecord/test/cases/finder_respond_to_test.rb1
-rw-r--r--activerecord/test/cases/finder_test.rb14
-rw-r--r--activerecord/test/cases/fixtures_test.rb2
-rw-r--r--activerecord/test/cases/helper.rb1
-rw-r--r--activerecord/test/cases/hot_compatibility_test.rb1
-rw-r--r--activerecord/test/cases/inheritance_test.rb4
-rw-r--r--activerecord/test/cases/insert_all_test.rb1
-rw-r--r--activerecord/test/cases/json_serialization_test.rb3
-rw-r--r--activerecord/test/cases/locking_test.rb1
-rw-r--r--activerecord/test/cases/migration/compatibility_test.rb29
-rw-r--r--activerecord/test/cases/migration/create_join_table_test.rb1
-rw-r--r--activerecord/test/cases/migration/helper.rb1
-rw-r--r--activerecord/test/cases/migration/logger_test.rb9
-rw-r--r--activerecord/test/cases/migration/references_statements_test.rb1
-rw-r--r--activerecord/test/cases/migration_test.rb39
-rw-r--r--activerecord/test/cases/migrator_test.rb143
-rw-r--r--activerecord/test/cases/multi_db_migrator_test.rb218
-rw-r--r--activerecord/test/cases/nested_attributes_test.rb1
-rw-r--r--activerecord/test/cases/pooled_connections_test.rb1
-rw-r--r--activerecord/test/cases/query_cache_test.rb24
-rw-r--r--activerecord/test/cases/relation/where_clause_test.rb1
-rw-r--r--activerecord/test/cases/relation/where_test.rb7
-rw-r--r--activerecord/test/cases/relation_test.rb8
-rw-r--r--activerecord/test/cases/relations_test.rb32
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb1
-rw-r--r--activerecord/test/cases/schema_loading_test.rb1
-rw-r--r--activerecord/test/cases/tasks/database_tasks_test.rb1
-rw-r--r--activerecord/test/cases/tasks/mysql_rake_test.rb14
-rw-r--r--activerecord/test/cases/tasks/postgresql_rake_test.rb3
-rw-r--r--activerecord/test/cases/test_case.rb12
-rw-r--r--activerecord/test/cases/transaction_callbacks_test.rb57
-rw-r--r--activerecord/test/cases/transactions_test.rb1
-rw-r--r--activerecord/test/cases/unsafe_raw_sql_test.rb87
-rw-r--r--activerecord/test/cases/validations/i18n_validation_test.rb4
-rw-r--r--activerecord/test/cases/yaml_serialization_test.rb1
-rw-r--r--activerecord/test/models/author.rb1
-rw-r--r--activerecord/test/models/book.rb6
-rw-r--r--activerecord/test/models/club.rb1
-rw-r--r--activerecord/test/models/company.rb1
-rw-r--r--activerecord/test/models/company_in_module.rb1
-rw-r--r--activerecord/test/models/contact.rb18
-rw-r--r--activerecord/test/models/face.rb2
-rw-r--r--activerecord/test/models/mouse.rb6
-rw-r--r--activerecord/test/models/person.rb1
-rw-r--r--activerecord/test/models/rating.rb1
-rw-r--r--activerecord/test/models/ship.rb3
-rw-r--r--activerecord/test/models/squeak.rb6
-rw-r--r--activerecord/test/models/topic.rb1
-rw-r--r--activerecord/test/schema/mysql2_specific_schema.rb4
-rw-r--r--activerecord/test/schema/schema.rb11
-rw-r--r--activerecord/test/support/config.rb1
-rw-r--r--activestorage/CHANGELOG.md61
-rw-r--r--activestorage/app/jobs/active_storage/mirror_job.rb13
-rw-r--r--activestorage/app/models/active_storage/attachment.rb6
-rw-r--r--activestorage/app/models/active_storage/blob.rb3
-rw-r--r--activestorage/app/models/active_storage/variant.rb14
-rw-r--r--activestorage/config/routes.rb2
-rw-r--r--activestorage/lib/active_storage.rb19
-rw-r--r--activestorage/lib/active_storage/analyzer/image_analyzer.rb3
-rw-r--r--activestorage/lib/active_storage/attached/model.rb17
-rw-r--r--activestorage/lib/active_storage/attached/one.rb2
-rw-r--r--activestorage/lib/active_storage/engine.rb7
-rw-r--r--activestorage/lib/active_storage/log_subscriber.rb6
-rw-r--r--activestorage/lib/active_storage/service/azure_storage_service.rb4
-rw-r--r--activestorage/lib/active_storage/service/disk_service.rb6
-rw-r--r--activestorage/lib/active_storage/service/mirror_service.rb29
-rw-r--r--activestorage/lib/active_storage/service/s3_service.rb32
-rw-r--r--activestorage/test/analyzer/video_analyzer_test.rb1
-rw-r--r--activestorage/test/controllers/blobs_controller_test.rb25
-rw-r--r--activestorage/test/controllers/representations_controller_test.rb30
-rw-r--r--activestorage/test/models/attached/many_test.rb72
-rw-r--r--activestorage/test/models/attachment_test.rb53
-rw-r--r--activestorage/test/service/azure_storage_service_test.rb14
-rw-r--r--activestorage/test/service/disk_service_test.rb10
-rw-r--r--activestorage/test/service/mirror_service_test.rb14
-rw-r--r--activestorage/test/service/s3_service_test.rb22
-rw-r--r--activestorage/test/test_helper.rb4
-rw-r--r--activesupport/CHANGELOG.md77
-rw-r--r--activesupport/activesupport.gemspec2
-rw-r--r--activesupport/lib/active_support/backtrace_cleaner.rb1
-rw-r--r--activesupport/lib/active_support/cache.rb9
-rw-r--r--activesupport/lib/active_support/cache/file_store.rb1
-rw-r--r--activesupport/lib/active_support/cache/memory_store.rb1
-rw-r--r--activesupport/lib/active_support/cache/strategy/local_cache.rb6
-rw-r--r--activesupport/lib/active_support/callbacks.rb4
-rw-r--r--activesupport/lib/active_support/concurrency/share_lock.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/date_and_time/calculations.rb30
-rw-r--r--activesupport/lib/active_support/core_ext/date_and_time/zones.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/conversions.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/digest.rb3
-rw-r--r--activesupport/lib/active_support/core_ext/enumerable.rb46
-rw-r--r--activesupport/lib/active_support/core_ext/hash/deep_transform_values.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/module/delegation.rb29
-rw-r--r--activesupport/lib/active_support/core_ext/object/duplicable.rb124
-rw-r--r--activesupport/lib/active_support/core_ext/range/each.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/string/output_safety.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/time/calculations.rb30
-rw-r--r--activesupport/lib/active_support/dependencies.rb42
-rw-r--r--activesupport/lib/active_support/dependencies/zeitwerk_integration.rb3
-rw-r--r--activesupport/lib/active_support/deprecation/proxy_wrappers.rb29
-rw-r--r--activesupport/lib/active_support/descendants_tracker.rb7
-rw-r--r--activesupport/lib/active_support/duration.rb2
-rw-r--r--activesupport/lib/active_support/duration/iso8601_parser.rb1
-rw-r--r--activesupport/lib/active_support/duration/iso8601_serializer.rb1
-rw-r--r--activesupport/lib/active_support/evented_file_update_checker.rb20
-rw-r--r--activesupport/lib/active_support/file_update_checker.rb1
-rw-r--r--activesupport/lib/active_support/hash_with_indifferent_access.rb10
-rw-r--r--activesupport/lib/active_support/inflector/inflections.rb2
-rw-r--r--activesupport/lib/active_support/inflector/methods.rb1
-rw-r--r--activesupport/lib/active_support/json/decoding.rb1
-rw-r--r--activesupport/lib/active_support/lazy_load_hooks.rb1
-rw-r--r--activesupport/lib/active_support/log_subscriber.rb4
-rw-r--r--activesupport/lib/active_support/logger_thread_safe_level.rb3
-rw-r--r--activesupport/lib/active_support/message_verifier.rb4
-rw-r--r--activesupport/lib/active_support/messages/rotator.rb9
-rw-r--r--activesupport/lib/active_support/multibyte/chars.rb1
-rw-r--r--activesupport/lib/active_support/multibyte/unicode.rb1
-rw-r--r--activesupport/lib/active_support/notifications.rb35
-rw-r--r--activesupport/lib/active_support/notifications/fanout.rb26
-rw-r--r--activesupport/lib/active_support/notifications/instrumenter.rb4
-rw-r--r--activesupport/lib/active_support/number_helper.rb4
-rw-r--r--activesupport/lib/active_support/number_helper/number_converter.rb1
-rw-r--r--activesupport/lib/active_support/number_helper/number_to_currency_converter.rb1
-rw-r--r--activesupport/lib/active_support/number_helper/number_to_delimited_converter.rb1
-rw-r--r--activesupport/lib/active_support/number_helper/number_to_human_converter.rb1
-rw-r--r--activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb1
-rw-r--r--activesupport/lib/active_support/number_helper/number_to_phone_converter.rb1
-rw-r--r--activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb1
-rw-r--r--activesupport/lib/active_support/parameter_filter.rb8
-rw-r--r--activesupport/lib/active_support/rails.rb3
-rw-r--r--activesupport/lib/active_support/secure_compare_rotator.rb52
-rw-r--r--activesupport/lib/active_support/string_inquirer.rb1
-rw-r--r--activesupport/lib/active_support/testing/parallelization.rb19
-rw-r--r--activesupport/lib/active_support/testing/stream.rb1
-rw-r--r--activesupport/lib/active_support/testing/time_helpers.rb2
-rw-r--r--activesupport/lib/active_support/xml_mini.rb1
-rw-r--r--activesupport/lib/active_support/xml_mini/jdom.rb1
-rw-r--r--activesupport/test/cache/behaviors/cache_store_behavior.rb1
-rw-r--r--activesupport/test/cache/behaviors/local_cache_behavior.rb9
-rw-r--r--activesupport/test/cache/cache_key_test.rb1
-rw-r--r--activesupport/test/cache/stores/mem_cache_store_test.rb1
-rw-r--r--activesupport/test/cache/stores/redis_cache_store_test.rb2
-rw-r--r--activesupport/test/callbacks_test.rb2
-rw-r--r--activesupport/test/core_ext/date_and_time_behavior.rb60
-rw-r--r--activesupport/test/core_ext/date_ext_test.rb16
-rw-r--r--activesupport/test/core_ext/enumerable_test.rb24
-rw-r--r--activesupport/test/core_ext/module_test.rb44
-rw-r--r--activesupport/test/core_ext/object/duplicable_test.rb9
-rw-r--r--activesupport/test/core_ext/time_ext_test.rb60
-rw-r--r--activesupport/test/dependencies_test.rb24
-rw-r--r--activesupport/test/deprecation/method_wrappers_test.rb2
-rw-r--r--activesupport/test/deprecation_test.rb17
-rw-r--r--activesupport/test/descendants_tracker_test_cases.rb1
-rw-r--r--activesupport/test/evented_file_update_checker_test.rb64
-rw-r--r--activesupport/test/json/decoding_test.rb1
-rw-r--r--activesupport/test/json/encoding_test.rb1
-rw-r--r--activesupport/test/lazy_load_hooks_test.rb1
-rw-r--r--activesupport/test/logger_test.rb44
-rw-r--r--activesupport/test/message_encryptor_test.rb28
-rw-r--r--activesupport/test/multibyte_chars_test.rb1
-rw-r--r--activesupport/test/notifications_test.rb109
-rw-r--r--activesupport/test/parameter_filter_test.rb7
-rw-r--r--activesupport/test/secure_compare_rotator_test.rb57
-rw-r--r--activesupport/test/share_lock_test.rb2
-rw-r--r--activesupport/test/subscriber_test.rb1
-rw-r--r--activesupport/test/test_case_test.rb1
-rw-r--r--guides/assets/images/getting_started/unknown_action_create_for_articles.pngbin4808 -> 16331 bytes
-rw-r--r--guides/rails_guides/generator.rb1
-rw-r--r--guides/rails_guides/indexer.rb1
-rw-r--r--guides/rails_guides/markdown.rb1
-rw-r--r--guides/rails_guides/markdown/renderer.rb1
-rw-r--r--guides/source/2_3_release_notes.md2
-rw-r--r--guides/source/5_1_release_notes.md4
-rw-r--r--guides/source/5_2_release_notes.md2
-rw-r--r--guides/source/6_0_release_notes.md44
-rw-r--r--guides/source/action_text_overview.md2
-rw-r--r--guides/source/action_view_overview.md28
-rw-r--r--guides/source/active_record_migrations.md2
-rw-r--r--guides/source/active_record_multiple_databases.md288
-rw-r--r--guides/source/active_record_querying.md15
-rw-r--r--guides/source/active_storage_overview.md34
-rw-r--r--guides/source/active_support_core_extensions.md69
-rw-r--r--guides/source/active_support_instrumentation.md11
-rw-r--r--guides/source/association_basics.md4
-rw-r--r--guides/source/autoloading_and_reloading_constants.md1376
-rw-r--r--guides/source/autoloading_and_reloading_constants_classic_mode.md1351
-rw-r--r--guides/source/command_line.md24
-rw-r--r--guides/source/configuring.md49
-rw-r--r--guides/source/contributing_to_ruby_on_rails.md8
-rw-r--r--guides/source/documents.yaml15
-rw-r--r--guides/source/engines.md59
-rw-r--r--guides/source/getting_started.md6
-rw-r--r--guides/source/initialization.md10
-rw-r--r--guides/source/layouts_and_rendering.md46
-rw-r--r--guides/source/rails_application_templates.md4
-rw-r--r--guides/source/routing.md2
-rw-r--r--guides/source/security.md2
-rw-r--r--guides/source/testing.md4
-rw-r--r--guides/source/upgrading_ruby_on_rails.md321
-rw-r--r--railties/CHANGELOG.md2
-rw-r--r--railties/lib/rails.rb1
-rw-r--r--railties/lib/rails/application.rb7
-rw-r--r--railties/lib/rails/application/bootstrap.rb24
-rw-r--r--railties/lib/rails/application/configuration.rb31
-rw-r--r--railties/lib/rails/application/default_middleware_stack.rb2
-rw-r--r--railties/lib/rails/application/dummy_erb_compiler.rb5
-rw-r--r--railties/lib/rails/application/finisher.rb12
-rw-r--r--railties/lib/rails/application/routes_reloader.rb1
-rw-r--r--railties/lib/rails/application_controller.rb1
-rw-r--r--railties/lib/rails/command.rb1
-rw-r--r--railties/lib/rails/command/spellchecker.rb1
-rw-r--r--railties/lib/rails/commands/server/server_command.rb11
-rw-r--r--railties/lib/rails/engine.rb2
-rw-r--r--railties/lib/rails/engine/configuration.rb11
-rw-r--r--railties/lib/rails/generators.rb3
-rw-r--r--railties/lib/rails/generators/actions.rb27
-rw-r--r--railties/lib/rails/generators/actions/create_migration.rb1
-rw-r--r--railties/lib/rails/generators/app_base.rb5
-rw-r--r--railties/lib/rails/generators/base.rb8
-rw-r--r--railties/lib/rails/generators/erb.rb1
-rw-r--r--railties/lib/rails/generators/erb/mailer/mailer_generator.rb1
-rw-r--r--railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb1
-rw-r--r--railties/lib/rails/generators/erb/scaffold/templates/show.html.erb.tt2
-rw-r--r--railties/lib/rails/generators/generated_attribute.rb1
-rw-r--r--railties/lib/rails/generators/named_base.rb1
-rw-r--r--railties/lib/rails/generators/rails/app/app_generator.rb8
-rw-r--r--railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt3
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/feature_policy.rb.tt11
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_6_0.rb.tt12
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/puma.rb.tt3
-rw-r--r--railties/lib/rails/generators/rails/app/templates/public/robots.txt2
-rw-r--r--railties/lib/rails/generators/rails/controller/controller_generator.rb1
-rw-r--r--railties/lib/rails/generators/rails/generator/generator_generator.rb1
-rw-r--r--railties/lib/rails/generators/rails/plugin/plugin_generator.rb1
-rw-r--r--railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb13
-rw-r--r--railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb.tt2
-rw-r--r--railties/lib/rails/generators/test_unit/generator/generator_generator.rb1
-rw-r--r--railties/lib/rails/generators/test_unit/integration/integration_generator.rb1
-rw-r--r--railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb10
-rw-r--r--railties/lib/rails/generators/testing/behaviour.rb1
-rw-r--r--railties/lib/rails/info_controller.rb1
-rw-r--r--railties/lib/rails/paths.rb12
-rw-r--r--railties/lib/rails/rack/logger.rb1
-rw-r--r--railties/lib/rails/railtie.rb2
-rw-r--r--railties/lib/rails/railtie/configurable.rb1
-rw-r--r--railties/lib/rails/railtie/configuration.rb1
-rw-r--r--railties/lib/rails/source_annotation_extractor.rb10
-rw-r--r--railties/lib/rails/tasks/zeitwerk.rake96
-rw-r--r--railties/lib/rails/test_unit/runner.rb2
-rw-r--r--railties/test/application/assets_test.rb1
-rw-r--r--railties/test/application/bin_setup_test.rb2
-rw-r--r--railties/test/application/configuration_test.rb56
-rw-r--r--railties/test/application/content_security_policy_test.rb33
-rw-r--r--railties/test/application/feature_policy_test.rb191
-rw-r--r--railties/test/application/generators_test.rb10
-rw-r--r--railties/test/application/initializers/frameworks_test.rb3
-rw-r--r--railties/test/application/loading_test.rb10
-rw-r--r--railties/test/application/middleware/exceptions_test.rb16
-rw-r--r--railties/test/application/middleware_test.rb2
-rw-r--r--railties/test/application/rake/dbs_test.rb77
-rw-r--r--railties/test/application/rake/multi_dbs_test.rb46
-rw-r--r--railties/test/application/rake/notes_test.rb1
-rw-r--r--railties/test/application/system_test_case_test.rb45
-rw-r--r--railties/test/application/test_runner_test.rb18
-rw-r--r--railties/test/application/zeitwerk_integration_test.rb9
-rw-r--r--railties/test/commands/console_test.rb1
-rw-r--r--railties/test/commands/dbconsole_test.rb1
-rw-r--r--railties/test/commands/server_test.rb23
-rw-r--r--railties/test/configuration/middleware_stack_proxy_test.rb1
-rw-r--r--railties/test/env_helpers.rb1
-rw-r--r--railties/test/generators/actions_test.rb93
-rw-r--r--railties/test/generators/api_app_generator_test.rb1
-rw-r--r--railties/test/generators/migration_generator_test.rb16
-rw-r--r--railties/test/generators/named_base_test.rb1
-rw-r--r--railties/test/generators/plugin_generator_test.rb1
-rw-r--r--railties/test/generators/scaffold_controller_generator_test.rb9
-rw-r--r--railties/test/generators/scaffold_generator_test.rb30
-rw-r--r--railties/test/isolation/abstract_unit.rb42
-rw-r--r--railties/test/railties/engine_test.rb2
-rwxr-xr-xtools/profile1
803 files changed, 10219 insertions, 6473 deletions
diff --git a/.codeclimate.yml b/.codeclimate.yml
index 7114a98266..952b330d8c 100644
--- a/.codeclimate.yml
+++ b/.codeclimate.yml
@@ -25,6 +25,6 @@ checks:
plugins:
rubocop:
enabled: true
- channel: rubocop-0-67
+ channel: rubocop-0-71
exclude_patterns: []
diff --git a/.rubocop.yml b/.rubocop.yml
index 0cfe5d5d84..e310351bf5 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -1,4 +1,6 @@
-require: rubocop-performance
+require:
+ - rubocop-performance
+ - rubocop-rails
AllCops:
TargetRubyVersion: 2.5
@@ -18,9 +20,6 @@ Performance:
Exclude:
- '**/test/**/*'
-Rails:
- Enabled: true
-
# Prefer assert_not over assert !
Rails/AssertNot:
Include:
@@ -62,6 +61,10 @@ Layout/EndAlignment:
Layout/EmptyLineAfterMagicComment:
Enabled: true
+Layout/EmptyLinesAroundAccessModifier:
+ Enabled: true
+ EnforcedStyle: only_before
+
Layout/EmptyLinesAroundBlockBody:
Enabled: true
@@ -77,13 +80,13 @@ Layout/EmptyLinesAroundMethodBody:
Layout/EmptyLinesAroundModuleBody:
Enabled: true
-Layout/FirstParameterIndentation:
- Enabled: true
-
# Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }.
Style/HashSyntax:
Enabled: true
+Layout/IndentFirstArgument:
+ Enabled: true
+
# Method definitions after `private` or `protected` isolated calls need one
# extra level of indentation.
Layout/IndentationConsistency:
diff --git a/Gemfile b/Gemfile
index 69f277be29..3a7a564a35 100644
--- a/Gemfile
+++ b/Gemfile
@@ -9,8 +9,8 @@ gemspec
# We need a newish Rake since Active Job sets its test tasks' descriptions.
gem "rake", ">= 11.1"
-gem "capybara", ">= 2.15"
-gem "selenium-webdriver", ">= 3.5.0", "< 3.13.0"
+gem "capybara", ">= 3.26"
+gem "selenium-webdriver", ">= 3.141.592"
gem "rack-cache", "~> 1.2"
gem "sass-rails"
@@ -30,6 +30,7 @@ gem "json", ">= 2.0.0"
gem "rubocop", ">= 0.47", require: false
gem "rubocop-performance", require: false
+gem "rubocop-rails", require: false
group :doc do
gem "sdoc", "~> 1.0"
diff --git a/Gemfile.lock b/Gemfile.lock
index 8d34d9a24b..0618bcf7ec 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -71,7 +71,7 @@ PATH
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
- zeitwerk (~> 2.1, >= 2.1.4)
+ zeitwerk (~> 2.1, >= 2.1.8)
rails (6.1.0.alpha)
actioncable (= 6.1.0.alpha)
actionmailbox (= 6.1.0.alpha)
@@ -175,16 +175,16 @@ GEM
bunny (2.13.0)
amq-protocol (~> 2.3, >= 2.3.0)
byebug (10.0.2)
- capybara (3.10.1)
+ capybara (3.26.0)
addressable
mini_mime (>= 0.1.3)
nokogiri (~> 1.8)
rack (>= 1.6.0)
rack-test (>= 0.6.3)
- regexp_parser (~> 1.2)
+ regexp_parser (~> 1.5)
xpath (~> 3.2)
- childprocess (0.9.0)
- ffi (~> 1.0, >= 1.0.11)
+ childprocess (1.0.1)
+ rake (< 13.0)
coffee-script (2.4.1)
coffee-script-source
execjs
@@ -216,7 +216,7 @@ GEM
em-socksify (0.3.2)
eventmachine (>= 1.0.0.beta.4)
erubi (1.8.0)
- et-orbi (1.1.6)
+ et-orbi (1.2.1)
tzinfo
event_emitter (0.2.6)
eventmachine (1.2.7)
@@ -236,12 +236,12 @@ GEM
faye-websocket (0.10.7)
eventmachine (>= 0.12.0)
websocket-driver (>= 0.5.1)
- ffi (1.10.0)
- ffi (1.10.0-java)
- ffi (1.10.0-x64-mingw32)
- ffi (1.10.0-x86-mingw32)
- fugit (1.1.6)
- et-orbi (~> 1.1, >= 1.1.6)
+ ffi (1.11.1)
+ ffi (1.11.1-java)
+ ffi (1.11.1-x64-mingw32)
+ ffi (1.11.1-x86-mingw32)
+ fugit (1.2.1)
+ et-orbi (~> 1.1, >= 1.1.8)
raabro (~> 1.1)
globalid (0.4.2)
activesupport (>= 4.2.0)
@@ -279,7 +279,6 @@ GEM
image_processing (1.7.1)
mini_magick (~> 4.0)
ruby-vips (>= 2.0.13, < 3)
- jar-dependencies (0.4.0)
jaro_winkler (1.5.2)
jaro_winkler (1.5.2-java)
jdbc-mysql (5.1.46)
@@ -338,29 +337,24 @@ GEM
mysql2 (0.5.2)
mysql2 (0.5.2-x64-mingw32)
mysql2 (0.5.2-x86-mingw32)
- net_http_ssl_fix (0.0.10)
nio4r (2.3.1)
nio4r (2.3.1-java)
- nokogiri (1.9.1)
+ nokogiri (1.10.3)
mini_portile2 (~> 2.4.0)
- nokogiri (1.9.1-java)
- nokogiri (1.9.1-x64-mingw32)
+ nokogiri (1.10.3-java)
+ nokogiri (1.10.3-x64-mingw32)
mini_portile2 (~> 2.4.0)
- nokogiri (1.9.1-x86-mingw32)
+ nokogiri (1.10.3-x86-mingw32)
mini_portile2 (~> 2.4.0)
os (1.0.0)
- parallel (1.13.0)
- parser (2.6.2.0)
+ parallel (1.17.0)
+ parser (2.6.3.0)
ast (~> 2.4.0)
path_expander (1.0.3)
pg (1.1.3)
pg (1.1.3-x64-mingw32)
pg (1.1.3-x86-mingw32)
psych (3.1.0)
- psych (3.1.0-java)
- jar-dependencies (>= 0.1.7)
- psych (3.1.0-x64-mingw32)
- psych (3.1.0-x86-mingw32)
public_suffix (3.0.3)
puma (3.12.1)
puma (3.12.1-java)
@@ -370,10 +364,10 @@ GEM
thor
raabro (1.1.6)
racc (1.4.15)
- rack (2.0.6)
+ rack (2.0.7)
rack-cache (1.8.0)
rack (>= 0.4)
- rack-protection (2.0.4)
+ rack-protection (2.0.5)
rack
rack-proxy (0.6.5)
rack
@@ -391,43 +385,45 @@ GEM
ffi (~> 1.0)
rdoc (6.0.4)
redcarpet (3.2.3)
- redis (4.0.3)
+ redis (4.1.1)
redis-namespace (1.6.0)
redis (>= 3.0.4)
- regexp_parser (1.3.0)
+ regexp_parser (1.6.0)
representable (3.0.4)
declarative (< 0.1.0)
declarative-option (< 0.2.0)
uber (< 0.2.0)
- resque (1.27.4)
+ resque (2.0.0)
mono_logger (~> 1.0)
multi_json (~> 1.0)
- redis-namespace (~> 1.3)
+ redis-namespace (~> 1.6)
sinatra (>= 0.9.2)
vegas (~> 0.1.2)
- resque-scheduler (4.3.1)
+ resque-scheduler (4.4.0)
mono_logger (~> 1.0)
- redis (>= 3.3, < 5)
- resque (~> 1.26)
+ redis (>= 3.3)
+ resque (>= 1.26)
rufus-scheduler (~> 3.2)
retriable (3.1.2)
- rubocop (0.67.2)
+ rubocop (0.71.0)
jaro_winkler (~> 1.5.1)
parallel (~> 1.10)
- parser (>= 2.5, != 2.5.1.1)
- psych (>= 3.1.0)
+ parser (>= 2.6)
rainbow (>= 2.2.2, < 4.0)
ruby-progressbar (~> 1.7)
- unicode-display_width (>= 1.4.0, < 1.6)
+ unicode-display_width (>= 1.4.0, < 1.7)
rubocop-performance (1.1.0)
rubocop (>= 0.67.0)
- ruby-progressbar (1.10.0)
+ rubocop-rails (2.0.0)
+ rack (>= 2.0)
+ rubocop (>= 0.70.0)
+ ruby-progressbar (1.10.1)
ruby-vips (2.0.13)
ffi (~> 1.9)
ruby_dep (1.5.0)
- rubyzip (1.2.2)
- rufus-scheduler (3.5.2)
- fugit (~> 1.1, >= 1.1.5)
+ rubyzip (1.2.3)
+ rufus-scheduler (3.6.0)
+ fugit (~> 1.1, >= 1.1.6)
safe_yaml (1.0.4)
sass (3.7.2)
sass-listen (~> 4.0.0)
@@ -442,9 +438,9 @@ GEM
tilt (>= 1.1, < 3)
sdoc (1.0.0)
rdoc (>= 5.0)
- selenium-webdriver (3.12.0)
- childprocess (~> 0.5)
- rubyzip (~> 1.2)
+ selenium-webdriver (3.142.3)
+ childprocess (>= 0.5, < 2.0)
+ rubyzip (~> 1.2, >= 1.2.2)
sequel (5.14.0)
serverengine (2.0.7)
sigdump (~> 0.2.2)
@@ -458,10 +454,10 @@ GEM
faraday (~> 0.9)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
- sinatra (2.0.4)
+ sinatra (2.0.5)
mustermann (~> 1.0)
rack (~> 2.0)
- rack-protection (= 2.0.4)
+ rack-protection (= 2.0.5)
tilt (~> 2.0)
sneakers (2.11.0)
bunny (~> 2.12)
@@ -488,7 +484,7 @@ GEM
thor (0.20.3)
thread_safe (0.3.6)
thread_safe (0.3.6-java)
- tilt (2.0.8)
+ tilt (2.0.9)
turbolinks (5.2.0)
turbolinks-source (~> 5.2)
turbolinks-source (5.2.0)
@@ -499,7 +495,7 @@ GEM
uber (0.1.0)
uglifier (4.1.19)
execjs (>= 0.3.0, < 3)
- unicode-display_width (1.5.0)
+ unicode-display_width (1.6.0)
useragent (0.16.10)
vegas (0.1.11)
rack (>= 1.0.0)
@@ -507,8 +503,7 @@ GEM
json (>= 1.8)
nokogiri (~> 1.6)
wdm (0.1.1)
- webdrivers (3.7.0)
- net_http_ssl_fix
+ webdrivers (4.0.0)
nokogiri (~> 1.6)
rubyzip (~> 1.0)
selenium-webdriver (~> 3.0)
@@ -528,7 +523,7 @@ GEM
websocket-extensions (0.1.3)
xpath (3.2.0)
nokogiri (~> 1.8)
- zeitwerk (2.1.4)
+ zeitwerk (2.1.8)
PLATFORMS
java
@@ -550,7 +545,7 @@ DEPENDENCIES
blade-sauce_labs_plugin
bootsnap (>= 1.4.4)
byebug
- capybara (>= 2.15)
+ capybara (>= 3.26)
connection_pool
dalli
delayed_job
@@ -584,9 +579,10 @@ DEPENDENCIES
resque-scheduler
rubocop (>= 0.47)
rubocop-performance
+ rubocop-rails
sass-rails
sdoc (~> 1.0)
- selenium-webdriver (>= 3.5.0, < 3.13.0)
+ selenium-webdriver (>= 3.141.592)
sequel
sidekiq
sneakers
diff --git a/RELEASING_RAILS.md b/RELEASING_RAILS.md
index d2d7a771bc..bc39e2313d 100644
--- a/RELEASING_RAILS.md
+++ b/RELEASING_RAILS.md
@@ -125,7 +125,7 @@ guide. You can generate keys with the GPG suite from here: https://gpgtools.org.
Run `rake changelog:header` to put a header with the new version in every
CHANGELOG. Don't commit this, the release task handles it.
-Run `rake release`. This will populate the gemspecs and NPM package.json with
+Run `rake release`. This will populate the gemspecs and npm package.json with
the current RAILS_VERSION, commit the changes, tag it, and push the gems to
rubygems.org.
diff --git a/actioncable/lib/action_cable/server/broadcasting.rb b/actioncable/lib/action_cable/server/broadcasting.rb
index bc54d784b3..b73cfa7d1f 100644
--- a/actioncable/lib/action_cable/server/broadcasting.rb
+++ b/actioncable/lib/action_cable/server/broadcasting.rb
@@ -40,7 +40,7 @@ module ActionCable
end
def broadcast(message)
- server.logger.debug "[ActionCable] Broadcasting to #{broadcasting}: #{message.inspect}"
+ server.logger.debug { "[ActionCable] Broadcasting to #{broadcasting}: #{message.inspect}" }
payload = { broadcasting: broadcasting, message: message, coder: coder }
ActiveSupport::Notifications.instrument("broadcast.action_cable", payload) do
diff --git a/actioncable/lib/action_cable/server/worker.rb b/actioncable/lib/action_cable/server/worker.rb
index 187c8f7939..b918d4ae72 100644
--- a/actioncable/lib/action_cable/server/worker.rb
+++ b/actioncable/lib/action_cable/server/worker.rb
@@ -66,7 +66,6 @@ module ActionCable
end
private
-
def logger
ActionCable.server.logger
end
diff --git a/actionmailbox/CHANGELOG.md b/actionmailbox/CHANGELOG.md
index a86adae5a7..bca3d1d9ed 100644
--- a/actionmailbox/CHANGELOG.md
+++ b/actionmailbox/CHANGELOG.md
@@ -1,3 +1,6 @@
+* Add `ApplicationMailbox.mailbox_for` to expose mailbox routing.
+
+ *James Dabbs*
Please check [6-0-stable](https://github.com/rails/rails/blob/6-0-stable/actionmailbox/CHANGELOG.md) for previous changes.
diff --git a/actionmailbox/app/controllers/rails/conductor/action_mailbox/inbound_emails_controller.rb b/actionmailbox/app/controllers/rails/conductor/action_mailbox/inbound_emails_controller.rb
index d051dfe665..cd8b12dcde 100644
--- a/actionmailbox/app/controllers/rails/conductor/action_mailbox/inbound_emails_controller.rb
+++ b/actionmailbox/app/controllers/rails/conductor/action_mailbox/inbound_emails_controller.rb
@@ -21,8 +21,9 @@ module Rails
private
def new_mail
Mail.new(params.require(:mail).permit(:from, :to, :cc, :bcc, :in_reply_to, :subject, :body).to_h).tap do |mail|
+ mail[:bcc]&.include_in_headers = true
params[:mail][:attachments].to_a.each do |attachment|
- mail.add_file(filename: attachment.path, content: attachment.read)
+ mail.add_file(filename: attachment.original_filename, content: attachment.read)
end
end
end
diff --git a/actionmailbox/lib/action_mailbox/router.rb b/actionmailbox/lib/action_mailbox/router.rb
index 71370e409d..54982eae21 100644
--- a/actionmailbox/lib/action_mailbox/router.rb
+++ b/actionmailbox/lib/action_mailbox/router.rb
@@ -21,7 +21,7 @@ module ActionMailbox
end
def route(inbound_email)
- if mailbox = match_to_mailbox(inbound_email)
+ if mailbox = mailbox_for(inbound_email)
mailbox.receive(inbound_email)
else
inbound_email.bounced!
@@ -30,12 +30,12 @@ module ActionMailbox
end
end
+ def mailbox_for(inbound_email)
+ routes.detect { |route| route.match?(inbound_email) }.try(:mailbox_class)
+ end
+
private
attr_reader :routes
-
- def match_to_mailbox(inbound_email)
- routes.detect { |route| route.match?(inbound_email) }.try(:mailbox_class)
- end
end
end
diff --git a/actionmailbox/lib/action_mailbox/routing.rb b/actionmailbox/lib/action_mailbox/routing.rb
index 58462a44c6..8391bf9db0 100644
--- a/actionmailbox/lib/action_mailbox/routing.rb
+++ b/actionmailbox/lib/action_mailbox/routing.rb
@@ -17,6 +17,10 @@ module ActionMailbox
def route(inbound_email)
router.route(inbound_email)
end
+
+ def mailbox_for(inbound_email)
+ router.mailbox_for(inbound_email)
+ end
end
end
end
diff --git a/actionmailbox/lib/rails/generators/test_unit/templates/mailbox_test.rb.tt b/actionmailbox/lib/rails/generators/test_unit/templates/mailbox_test.rb.tt
index 0b51f29fe4..3e215b4d0b 100644
--- a/actionmailbox/lib/rails/generators/test_unit/templates/mailbox_test.rb.tt
+++ b/actionmailbox/lib/rails/generators/test_unit/templates/mailbox_test.rb.tt
@@ -1,5 +1,3 @@
-# frozen_string_literal: true
-
require "test_helper"
class <%= class_name %>MailboxTest < ActionMailbox::TestCase
diff --git a/actionmailbox/test/controllers/rails/action_mailbox/inbound_emails_controller_test.rb b/actionmailbox/test/controllers/rails/action_mailbox/inbound_emails_controller_test.rb
index fcd9ad839f..06f5a9d6db 100644
--- a/actionmailbox/test/controllers/rails/action_mailbox/inbound_emails_controller_test.rb
+++ b/actionmailbox/test/controllers/rails/action_mailbox/inbound_emails_controller_test.rb
@@ -10,6 +10,8 @@ class Rails::Conductor::ActionMailbox::InboundEmailsControllerTest < ActionDispa
mail: {
from: "Jason Fried <jason@37signals.com>",
to: "Replies <replies@example.com>",
+ cc: "CC <cc@example.com>",
+ bcc: "Bcc <bcc@example.com>",
in_reply_to: "<4e6e35f5a38b4_479f13bb90078178@small-app-01.mail>",
subject: "Hey there",
body: "How's it going?"
@@ -20,6 +22,8 @@ class Rails::Conductor::ActionMailbox::InboundEmailsControllerTest < ActionDispa
mail = ActionMailbox::InboundEmail.last.mail
assert_equal %w[ jason@37signals.com ], mail.from
assert_equal %w[ replies@example.com ], mail.to
+ assert_equal %w[ cc@example.com ], mail.cc
+ assert_equal %w[ bcc@example.com ], mail.bcc
assert_equal "4e6e35f5a38b4_479f13bb90078178@small-app-01.mail", mail.in_reply_to
assert_equal "Hey there", mail.subject
assert_equal "How's it going?", mail.body.decoded
@@ -43,6 +47,7 @@ class Rails::Conductor::ActionMailbox::InboundEmailsControllerTest < ActionDispa
mail = ActionMailbox::InboundEmail.last.mail
assert_equal "Let's talk about these images:", mail.text_part.decoded
assert_equal 2, mail.attachments.count
+ assert_equal %w[ avatar1.jpeg avatar2.jpeg ], mail.attachments.collect(&:filename)
end
end
diff --git a/actionmailbox/test/unit/mailbox/routing_test.rb b/actionmailbox/test/unit/mailbox/routing_test.rb
index d4ba702ac5..8302b1d5cc 100644
--- a/actionmailbox/test/unit/mailbox/routing_test.rb
+++ b/actionmailbox/test/unit/mailbox/routing_test.rb
@@ -28,4 +28,9 @@ class ActionMailbox::Base::RoutingTest < ActiveSupport::TestCase
assert_equal "Discussion: Let's debate these attachments", $processed
end
end
+
+ test "mailbox_for" do
+ inbound_email = create_inbound_email_from_fixture "welcome.eml", status: :pending
+ assert_equal RepliesMailbox, ApplicationMailbox.mailbox_for(inbound_email)
+ end
end
diff --git a/actionmailbox/test/unit/router_test.rb b/actionmailbox/test/unit/router_test.rb
index c5dce60856..4dd3730604 100644
--- a/actionmailbox/test/unit/router_test.rb
+++ b/actionmailbox/test/unit/router_test.rb
@@ -135,5 +135,19 @@ module ActionMailbox
@router.add_route Array.new, to: :first
end
end
+
+ test "single string mailbox_for" do
+ @router.add_routes("first@example.com" => :first)
+
+ inbound_email = create_inbound_email_from_mail(to: "first@example.com", subject: "This is a reply")
+ assert_equal FirstMailbox, @router.mailbox_for(inbound_email)
+ end
+
+ test "mailbox_for with no matches" do
+ @router.add_routes("first@example.com" => :first)
+
+ inbound_email = create_inbound_email_from_mail(to: "second@example.com", subject: "This is a reply")
+ assert_nil @router.mailbox_for(inbound_email)
+ end
end
end
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index c1ac9c2ad1..ba914c4813 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -591,7 +591,6 @@ module ActionMailer
end
private
-
def set_payload_for_mail(payload, mail)
payload[:mail] = mail.encoded
payload[:mailer] = name
@@ -873,7 +872,6 @@ module ActionMailer
end
private
-
# Used by #mail to set the content type of the message.
#
# It will use the given +user_content_type+, or multipart if the mail
diff --git a/actionmailer/lib/action_mailer/preview.rb b/actionmailer/lib/action_mailer/preview.rb
index 500b3bede0..a763b9776c 100644
--- a/actionmailer/lib/action_mailer/preview.rb
+++ b/actionmailer/lib/action_mailer/preview.rb
@@ -55,7 +55,6 @@ module ActionMailer
end
private
-
def interceptor_class_for(interceptor)
case interceptor
when String, Symbol
diff --git a/actionmailer/lib/action_mailer/test_case.rb b/actionmailer/lib/action_mailer/test_case.rb
index ee5a864847..97afd87840 100644
--- a/actionmailer/lib/action_mailer/test_case.rb
+++ b/actionmailer/lib/action_mailer/test_case.rb
@@ -22,7 +22,6 @@ module ActionMailer
end
private
-
def clear_test_deliveries
if ActionMailer::Base.delivery_method == :test
ActionMailer::Base.deliveries.clear
@@ -76,7 +75,6 @@ module ActionMailer
end
private
-
def initialize_test_deliveries
set_delivery_method :test
@old_perform_deliveries = ActionMailer::Base.perform_deliveries
diff --git a/actionmailer/lib/action_mailer/test_helper.rb b/actionmailer/lib/action_mailer/test_helper.rb
index e222301dff..988db2491c 100644
--- a/actionmailer/lib/action_mailer/test_helper.rb
+++ b/actionmailer/lib/action_mailer/test_helper.rb
@@ -152,7 +152,6 @@ module ActionMailer
end
private
-
def delivery_job_filter(job)
job_class = job.is_a?(Hash) ? job.fetch(:job) : job.class
diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb
index c07fca5b5e..4ea5634cd0 100644
--- a/actionmailer/test/base_test.rb
+++ b/actionmailer/test/base_test.rb
@@ -939,7 +939,6 @@ class BaseTest < ActiveSupport::TestCase
end
private
-
# Execute the block setting the given values and restoring old values after
# the block is executed.
def swap(klass, new_values)
diff --git a/actionmailer/test/caching_test.rb b/actionmailer/test/caching_test.rb
index b658c96ec7..c3a3e418d0 100644
--- a/actionmailer/test/caching_test.rb
+++ b/actionmailer/test/caching_test.rb
@@ -189,7 +189,6 @@ class FunctionalFragmentCachingTest < BaseCachingTest
end
private
-
def template_digest(name, format)
ActionView::Digestor.digest(name: name, format: format, finder: @mailer.lookup_context)
end
diff --git a/actionmailer/test/i18n_with_controller_test.rb b/actionmailer/test/i18n_with_controller_test.rb
index 6e75cff347..eea72e06ba 100644
--- a/actionmailer/test/i18n_with_controller_test.rb
+++ b/actionmailer/test/i18n_with_controller_test.rb
@@ -67,7 +67,6 @@ class ActionMailerI18nWithControllerTest < ActionDispatch::IntegrationTest
end
private
-
def with_translation(locale, data)
I18n.backend.store_translations(locale, data)
yield
diff --git a/actionmailer/test/legacy_delivery_job_test.rb b/actionmailer/test/legacy_delivery_job_test.rb
index 3a3872df47..a9b2a160d4 100644
--- a/actionmailer/test/legacy_delivery_job_test.rb
+++ b/actionmailer/test/legacy_delivery_job_test.rb
@@ -69,7 +69,6 @@ class LegacyDeliveryJobTest < ActiveSupport::TestCase
end
private
-
def with_delivery_job(job)
old_params_delivery_job = ParamsMailer.delivery_job
old_regular_delivery_job = DelayedMailer.delivery_job
diff --git a/actionmailer/test/mail_helper_test.rb b/actionmailer/test/mail_helper_test.rb
index 51d6ccb10f..a8ab19a95c 100644
--- a/actionmailer/test/mail_helper_test.rb
+++ b/actionmailer/test/mail_helper_test.rb
@@ -68,7 +68,6 @@ The second
end
private
-
def mail_with_defaults(&block)
mail(to: "test@localhost", from: "tester@example.com",
subject: "using helpers", &block)
diff --git a/actionmailer/test/mailers/proc_mailer.rb b/actionmailer/test/mailers/proc_mailer.rb
index 76e730bb79..75ee5dd9b6 100644
--- a/actionmailer/test/mailers/proc_mailer.rb
+++ b/actionmailer/test/mailers/proc_mailer.rb
@@ -18,7 +18,6 @@ class ProcMailer < ActionMailer::Base
end
private
-
def give_a_greeting
"Thanks for signing up this afternoon"
end
diff --git a/actionmailer/test/parameterized_test.rb b/actionmailer/test/parameterized_test.rb
index 7dd6156744..62dd671f48 100644
--- a/actionmailer/test/parameterized_test.rb
+++ b/actionmailer/test/parameterized_test.rb
@@ -81,7 +81,6 @@ class ParameterizedTest < ActiveSupport::TestCase
end
private
-
def with_delivery_job(job)
old_delivery_job = ParamsMailer.delivery_job
ParamsMailer.delivery_job = job
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 9fcff6a6ca..ca7ae6621b 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,3 +1,79 @@
+* Fix IntegrationTest `follow_redirect!` to follow redirection using the same HTTP verb when following
+ a 307 redirection.
+
+ *Edouard Chin*
+
+* System tests require Capybara 3.26 or newer.
+
+ *George Claghorn*
+
+* Reduced log noise handling ActionController::RoutingErrors.
+
+ *Alberto Fernández-Capel*
+
+* Add DSL for configuring HTTP Feature Policy
+
+ This new DSL provides a way to configure a HTTP Feature Policy at a
+ global or per-controller level. Full details of HTTP Feature Policy
+ specification and guidelines can be found at MDN:
+
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy
+
+ Example global policy
+
+ ```
+ Rails.application.config.feature_policy do |f|
+ f.camera :none
+ f.gyroscope :none
+ f.microphone :none
+ f.usb :none
+ f.fullscreen :self
+ f.payment :self, "https://secure.example.com"
+ end
+ ```
+
+ Example controller level policy
+
+ ```
+ class PagesController < ApplicationController
+ feature_policy do |p|
+ p.geolocation "https://example.com"
+ end
+ end
+ ```
+
+ *Jacob Bednarz*
+
+* Add the ability to set the CSP nonce only to the specified directives.
+
+ Fixes #35137.
+
+ *Yuji Yaginuma*
+
+* Keep part when scope option has value.
+
+ When a route was defined within an optional scope, if that route didn't
+ take parameters the scope was lost when using path helpers. This commit
+ ensures scope is kept both when the route takes parameters or when it
+ doesn't.
+
+ Fixes #33219.
+
+ *Alberto Almagro*
+
+* Added `deep_transform_keys` and `deep_transform_keys!` methods to ActionController::Parameters.
+
+ *Gustavo Gutierrez*
+
+* Calling `ActionController::Parameters#transform_keys/!` without a block now returns
+ an enumerator for the parameters instead of the underlying hash.
+
+ *Eugene Kenny*
+
+* Fix strong parameters blocks all attributes even when only some keys are invalid (non-numerical).
+ It should only block invalid key's values instead.
+
+ *Stan Lo*
Please check [6-0-stable](https://github.com/rails/rails/blob/6-0-stable/actionpack/CHANGELOG.md) for previous changes.
diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb
index 3a98931167..d1ff62a032 100644
--- a/actionpack/lib/abstract_controller.rb
+++ b/actionpack/lib/abstract_controller.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require "action_pack"
+require "active_support"
require "active_support/rails"
require "active_support/i18n"
diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb
index bb42f2e119..3ff922029b 100644
--- a/actionpack/lib/abstract_controller/base.rb
+++ b/actionpack/lib/abstract_controller/base.rb
@@ -176,7 +176,6 @@ module AbstractController
end
private
-
# Returns true if the name can be considered an action because
# it has a method defined in the controller.
#
diff --git a/actionpack/lib/abstract_controller/collector.rb b/actionpack/lib/abstract_controller/collector.rb
index d4a078ab32..0af546cc96 100644
--- a/actionpack/lib/abstract_controller/collector.rb
+++ b/actionpack/lib/abstract_controller/collector.rb
@@ -22,7 +22,6 @@ module AbstractController
end
private
-
def method_missing(symbol, &block)
unless mime_constant = Mime[symbol]
raise NoMethodError, "To respond to a custom format, register it as a MIME type first: " \
diff --git a/actionpack/lib/abstract_controller/helpers.rb b/actionpack/lib/abstract_controller/helpers.rb
index 3913259ecc..abb09456e0 100644
--- a/actionpack/lib/abstract_controller/helpers.rb
+++ b/actionpack/lib/abstract_controller/helpers.rb
@@ -7,7 +7,7 @@ module AbstractController
extend ActiveSupport::Concern
included do
- class_attribute :_helpers, default: Module.new
+ class_attribute :_helpers, default: define_helpers_module(self)
class_attribute :_helper_methods, default: Array.new
end
@@ -31,7 +31,7 @@ module AbstractController
# independently of the child class's.
def inherited(klass)
helpers = _helpers
- klass._helpers = Module.new { include helpers }
+ klass._helpers = define_helpers_module(klass, helpers)
klass.class_eval { default_helper_module! } unless klass.anonymous?
super
end
@@ -61,12 +61,17 @@ module AbstractController
meths.flatten!
self._helper_methods += meths
+ location = caller_locations(1, 1).first
+ file, line = location.path, location.lineno
+
meths.each do |meth|
- _helpers.class_eval <<-ruby_eval, __FILE__, __LINE__ + 1
- def #{meth}(*args, &blk) # def current_user(*args, &blk)
- controller.send(%(#{meth}), *args, &blk) # controller.send(:current_user, *args, &blk)
- end # end
- ruby_eval
+ method_def = [
+ "def #{meth}(*args, &blk)",
+ " controller.send(%(#{meth}), *args, &blk)",
+ "end"
+ ].join(";")
+
+ _helpers.class_eval method_def, file, line
end
end
@@ -170,6 +175,17 @@ module AbstractController
end
private
+ def define_helpers_module(klass, helpers = nil)
+ # In some tests inherited is called explicitly. In that case, just
+ # return the module from the first time it was defined
+ return klass.const_get(:HelperMethods) if klass.const_defined?(:HelperMethods, false)
+
+ mod = Module.new
+ klass.const_set(:HelperMethods, mod)
+ mod.include(helpers) if helpers
+ mod
+ end
+
# Makes all the (instance) methods in the helper module available to templates
# rendered through this controller.
#
diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb
index 29d61c3ceb..22dc229599 100644
--- a/actionpack/lib/action_controller.rb
+++ b/actionpack/lib/action_controller.rb
@@ -1,6 +1,5 @@
# frozen_string_literal: true
-require "active_support/rails"
require "abstract_controller"
require "action_dispatch"
require "action_controller/metal/live"
@@ -28,6 +27,7 @@ module ActionController
autoload :DefaultHeaders
autoload :EtagWithTemplateDigest
autoload :EtagWithFlash
+ autoload :FeaturePolicy
autoload :Flash
autoload :ForceSSL
autoload :Head
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 2e565d5d44..63c138af55 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -226,6 +226,7 @@ module ActionController
FormBuilder,
RequestForgeryProtection,
ContentSecurityPolicy,
+ FeaturePolicy,
ForceSSL,
Streaming,
DataStreaming,
diff --git a/actionpack/lib/action_controller/caching.rb b/actionpack/lib/action_controller/caching.rb
index bf3b00a7b7..83e3e0c37c 100644
--- a/actionpack/lib/action_controller/caching.rb
+++ b/actionpack/lib/action_controller/caching.rb
@@ -30,7 +30,6 @@ module ActionController
end
private
-
def instrument_payload(key)
{
controller: controller_name,
diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb
index b9088e6d86..ec2207b8da 100644
--- a/actionpack/lib/action_controller/metal.rb
+++ b/actionpack/lib/action_controller/metal.rb
@@ -35,7 +35,6 @@ module ActionController
end
private
-
INCLUDE = ->(list, action) { list.include? action }
EXCLUDE = ->(list, action) { !list.include? action }
NULL = ->(list, action) { true }
@@ -148,7 +147,7 @@ module ActionController
attr_internal :response, :request
delegate :session, to: "@_request"
delegate :headers, :status=, :location=, :content_type=,
- :status, :location, :content_type, to: "@_response"
+ :status, :location, :content_type, :media_type, to: "@_response"
def initialize
@_request = nil
diff --git a/actionpack/lib/action_controller/metal/content_security_policy.rb b/actionpack/lib/action_controller/metal/content_security_policy.rb
index b8fab4ebe3..ebd90f07c8 100644
--- a/actionpack/lib/action_controller/metal/content_security_policy.rb
+++ b/actionpack/lib/action_controller/metal/content_security_policy.rb
@@ -36,7 +36,6 @@ module ActionController #:nodoc:
end
private
-
def content_security_policy?
request.content_security_policy
end
diff --git a/actionpack/lib/action_controller/metal/data_streaming.rb b/actionpack/lib/action_controller/metal/data_streaming.rb
index 9ef4f50df1..879745a895 100644
--- a/actionpack/lib/action_controller/metal/data_streaming.rb
+++ b/actionpack/lib/action_controller/metal/data_streaming.rb
@@ -53,7 +53,7 @@ module ActionController #:nodoc:
#
# Show a 404 page in the browser:
#
- # send_file '/path/to/404.html', type: 'text/html; charset=utf-8', status: 404
+ # send_file '/path/to/404.html', type: 'text/html; charset=utf-8', disposition: 'inline', status: 404
#
# Read about the other Content-* HTTP headers if you'd like to
# provide the user with more information (such as Content-Description) in
diff --git a/actionpack/lib/action_controller/metal/feature_policy.rb b/actionpack/lib/action_controller/metal/feature_policy.rb
new file mode 100644
index 0000000000..a627eabea6
--- /dev/null
+++ b/actionpack/lib/action_controller/metal/feature_policy.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module ActionController #:nodoc:
+ # HTTP Feature Policy is a web standard for defining a mechanism to
+ # allow and deny the use of browser features in its own context, and
+ # in content within any <iframe> elements in the document.
+ #
+ # Full details of HTTP Feature Policy specification and guidelines can
+ # be found at MDN:
+ #
+ # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy
+ #
+ # Examples of usage:
+ #
+ # # Global policy
+ # Rails.application.config.feature_policy do |f|
+ # f.camera :none
+ # f.gyroscope :none
+ # f.microphone :none
+ # f.usb :none
+ # f.fullscreen :self
+ # f.payment :self, "https://secure.example.com"
+ # end
+ #
+ # # Controller level policy
+ # class PagesController < ApplicationController
+ # feature_policy do |p|
+ # p.geolocation "https://example.com"
+ # end
+ # end
+ module FeaturePolicy
+ extend ActiveSupport::Concern
+
+ module ClassMethods
+ def feature_policy(**options, &block)
+ before_action(options) do
+ if block_given?
+ policy = request.feature_policy.clone
+ yield policy
+ request.feature_policy = policy
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_controller/metal/instrumentation.rb b/actionpack/lib/action_controller/metal/instrumentation.rb
index 51fac08749..6f7fc0d624 100644
--- a/actionpack/lib/action_controller/metal/instrumentation.rb
+++ b/actionpack/lib/action_controller/metal/instrumentation.rb
@@ -69,7 +69,6 @@ module ActionController
end
private
-
# A hook invoked every time a before callback is halted.
def halted_callback_hook(filter)
ActiveSupport::Notifications.instrument("halted_callback.action_controller", filter: filter)
diff --git a/actionpack/lib/action_controller/metal/live.rb b/actionpack/lib/action_controller/metal/live.rb
index dd69930e25..4454ba1e3d 100644
--- a/actionpack/lib/action_controller/metal/live.rb
+++ b/actionpack/lib/action_controller/metal/live.rb
@@ -107,7 +107,6 @@ module ActionController
end
private
-
def perform_write(json, options)
current_options = @options.merge(options).stringify_keys
@@ -205,7 +204,6 @@ module ActionController
end
private
-
def each_chunk(&block)
loop do
str = nil
@@ -220,7 +218,6 @@ module ActionController
class Response < ActionDispatch::Response #:nodoc: all
private
-
def before_committed
super
jar = request.cookie_jar
@@ -286,7 +283,6 @@ module ActionController
end
private
-
# Spawn a new thread to serve up the controller in. This is to get
# around the fact that Rack isn't based around IOs and we need to use
# a thread to stream data from the response bodies. Nobody should call
diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb
index bf5e7a433f..5c6f7fe396 100644
--- a/actionpack/lib/action_controller/metal/mime_responds.rb
+++ b/actionpack/lib/action_controller/metal/mime_responds.rb
@@ -205,7 +205,7 @@ module ActionController #:nodoc:
yield collector if block_given?
if format = collector.negotiate_format(request)
- if content_type && content_type != format
+ if media_type && media_type != format
raise ActionController::RespondToMismatchError
end
_process_format(format)
diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb
index e635abec8e..150ae2666c 100644
--- a/actionpack/lib/action_controller/metal/params_wrapper.rb
+++ b/actionpack/lib/action_controller/metal/params_wrapper.rb
@@ -246,7 +246,6 @@ module ActionController
end
private
-
# Returns the wrapper key which will be used to store wrapped parameters.
def _wrapper_key
_wrapper_options.name
diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb
index b81d3ef539..a251c29d23 100644
--- a/actionpack/lib/action_controller/metal/renderers.rb
+++ b/actionpack/lib/action_controller/metal/renderers.rb
@@ -157,7 +157,7 @@ module ActionController
json = json.to_json(options) unless json.kind_of?(String)
if options[:callback].present?
- if content_type.nil? || content_type == Mime[:json]
+ if media_type.nil? || media_type == Mime[:json]
self.content_type = Mime[:js]
end
diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb
index 7d0a944381..efa5de313c 100644
--- a/actionpack/lib/action_controller/metal/rendering.rb
+++ b/actionpack/lib/action_controller/metal/rendering.rb
@@ -53,7 +53,6 @@ module ActionController
end
private
-
def _process_variant(options)
if defined?(request) && !request.nil? && request.variant.present?
options[:variant] = request.variant
@@ -73,7 +72,7 @@ module ActionController
end
def _set_rendered_content_type(format)
- if format && !response.content_type
+ if format && !response.media_type
self.content_type = format.to_s
end
end
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index 4bf8d90b69..5a5c04234b 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -151,7 +151,6 @@ module ActionController #:nodoc:
end
private
-
def protection_method_class(name)
ActionController::RequestForgeryProtection::ProtectionMethods.const_get(name.to_s.classify)
rescue NameError
@@ -175,7 +174,6 @@ module ActionController #:nodoc:
end
private
-
class NullSessionHash < Rack::Session::Abstract::SessionHash #:nodoc:
def initialize(req)
super(nil, req)
diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb
index 8dc01a5eb9..94a62e5cab 100644
--- a/actionpack/lib/action_controller/metal/streaming.rb
+++ b/actionpack/lib/action_controller/metal/streaming.rb
@@ -196,7 +196,6 @@ module ActionController #:nodoc:
extend ActiveSupport::Concern
private
-
# Set proper cache control and transfer encoding when streaming
def _process_options(options)
super
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index ae774b01f1..920ae52f2b 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -223,6 +223,12 @@ module ActionController
# config.always_permitted_parameters = %w( controller action format )
cattr_accessor :always_permitted_parameters, default: %w( controller action )
+ class << self
+ def nested_attribute?(key, value) # :nodoc:
+ key =~ /\A-?\d+\z/ && (value.is_a?(Hash) || value.is_a?(Parameters))
+ end
+ end
+
# Returns a new instance of <tt>ActionController::Parameters</tt>.
# Also, sets the +permitted+ attribute to the default value of
# <tt>ActionController::Parameters.permit_all_parameters</tt>.
@@ -253,6 +259,11 @@ module ActionController
@parameters == other
end
end
+ alias eql? ==
+
+ def hash
+ [@parameters.hash, @permitted].hash
+ end
# Returns a safe <tt>ActiveSupport::HashWithIndifferentAccess</tt>
# representation of the parameters with all unpermitted keys removed.
@@ -673,22 +684,37 @@ module ActionController
# Returns a new <tt>ActionController::Parameters</tt> instance with the
# results of running +block+ once for every key. The values are unchanged.
def transform_keys(&block)
- if block
- new_instance_with_inherited_permitted_status(
- @parameters.transform_keys(&block)
- )
- else
- @parameters.transform_keys
- end
+ return to_enum(:transform_keys) unless block_given?
+ new_instance_with_inherited_permitted_status(
+ @parameters.transform_keys(&block)
+ )
end
# Performs keys transformation and returns the altered
# <tt>ActionController::Parameters</tt> instance.
def transform_keys!(&block)
+ return to_enum(:transform_keys!) unless block_given?
@parameters.transform_keys!(&block)
self
end
+ # Returns a new <tt>ActionController::Parameters</tt> instance with the
+ # results of running +block+ once for every key. This includes the keys
+ # from the root hash and from all nested hashes and arrays. The values are unchanged.
+ def deep_transform_keys(&block)
+ new_instance_with_inherited_permitted_status(
+ @parameters.deep_transform_keys(&block)
+ )
+ end
+
+ # Returns the <tt>ActionController::Parameters</tt> instance changing its keys.
+ # This includes the keys from the root hash and from all nested hashes and arrays.
+ # The values are unchanged.
+ def deep_transform_keys!(&block)
+ @parameters.deep_transform_keys!(&block)
+ self
+ end
+
# Deletes a key-value pair from +Parameters+ and returns the value. If
# +key+ is not found, returns +nil+ (or, with optional code block, yields
# +key+ and returns the result). Cf. +#extract!+, which returns the
@@ -723,6 +749,18 @@ module ActionController
end
alias_method :delete_if, :reject!
+ # Returns a new instance of <tt>ActionController::Parameters</tt> without the blank values.
+ # Uses Object#blank? for determining if a value is blank.
+ def compact_blank
+ reject { |_k, v| v.blank? }
+ end
+
+ # Removes all blank values in place and returns self.
+ # Uses Object#blank? for determining if a value is blank.
+ def compact_blank!
+ reject! { |_k, v| v.blank? }
+ end
+
# Returns values that were assigned to the given +keys+. Note that all the
# +Hash+ objects will be converted to <tt>ActionController::Parameters</tt>.
def values_at(*keys)
@@ -811,8 +849,14 @@ module ActionController
attr_writer :permitted
- def fields_for_style?
- @parameters.all? { |k, v| k =~ /\A-?\d+\z/ && (v.is_a?(Hash) || v.is_a?(Parameters)) }
+ def nested_attributes?
+ @parameters.any? { |k, v| Parameters.nested_attribute?(k, v) }
+ end
+
+ def each_nested_attribute
+ hash = self.class.new
+ self.each { |k, v| hash[k] = yield v if Parameters.nested_attribute?(k, v) }
+ hash
end
private
@@ -857,15 +901,13 @@ module ActionController
end
end
- def each_element(object)
+ def each_element(object, &block)
case object
when Array
object.grep(Parameters).map { |el| yield el }.compact
when Parameters
- if object.fields_for_style?
- hash = object.class.new
- object.each { |k, v| hash[k] = yield v }
- hash
+ if object.nested_attributes?
+ object.each_nested_attribute(&block)
else
yield object
end
diff --git a/actionpack/lib/action_controller/template_assertions.rb b/actionpack/lib/action_controller/template_assertions.rb
index dd83c1a283..ec44dbe157 100644
--- a/actionpack/lib/action_controller/template_assertions.rb
+++ b/actionpack/lib/action_controller/template_assertions.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module ActionController
- module TemplateAssertions
+ module TemplateAssertions # :nodoc:
def assert_template(options = {}, message = nil)
raise NoMethodError,
"assert_template has been extracted to a gem. To continue using it,
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 57921f32b7..47e0099f20 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -158,7 +158,6 @@ module ActionController
end.new
private
-
def params_parsers
super.merge @custom_param_parsers
end
@@ -208,7 +207,6 @@ module ActionController
end
private
-
def load!
@id
end
@@ -594,7 +592,6 @@ module ActionController
end
private
-
def scrub_env!(env)
env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ }
env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ }
diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb
index 6a4ba9af4a..67d303a368 100644
--- a/actionpack/lib/action_dispatch.rb
+++ b/actionpack/lib/action_dispatch.rb
@@ -43,6 +43,7 @@ module ActionDispatch
eager_autoload do
autoload_under "http" do
autoload :ContentSecurityPolicy
+ autoload :FeaturePolicy
autoload :Request
autoload :Response
end
diff --git a/actionpack/lib/action_dispatch/http/cache.rb b/actionpack/lib/action_dispatch/http/cache.rb
index 8cc84ff36c..7be30be77a 100644
--- a/actionpack/lib/action_dispatch/http/cache.rb
+++ b/actionpack/lib/action_dispatch/http/cache.rb
@@ -123,7 +123,6 @@ module ActionDispatch
end
private
-
DATE = "Date"
LAST_MODIFIED = "Last-Modified"
SPECIAL_KEYS = Set.new(%w[extras no-cache max-age public private must-revalidate])
diff --git a/actionpack/lib/action_dispatch/http/content_security_policy.rb b/actionpack/lib/action_dispatch/http/content_security_policy.rb
index b1e5a28be5..9c430b57e3 100644
--- a/actionpack/lib/action_dispatch/http/content_security_policy.rb
+++ b/actionpack/lib/action_dispatch/http/content_security_policy.rb
@@ -22,15 +22,15 @@ module ActionDispatch #:nodoc:
if policy = request.content_security_policy
nonce = request.content_security_policy_nonce
+ nonce_directives = request.content_security_policy_nonce_directives
context = request.controller_instance || request
- headers[header_name(request)] = policy.build(context, nonce)
+ headers[header_name(request)] = policy.build(context, nonce, nonce_directives)
end
response
end
private
-
def html_response?(headers)
if content_type = headers[CONTENT_TYPE]
content_type =~ /html/
@@ -55,6 +55,7 @@ module ActionDispatch #:nodoc:
POLICY_REPORT_ONLY = "action_dispatch.content_security_policy_report_only"
NONCE_GENERATOR = "action_dispatch.content_security_policy_nonce_generator"
NONCE = "action_dispatch.content_security_policy_nonce"
+ NONCE_DIRECTIVES = "action_dispatch.content_security_policy_nonce_directives"
def content_security_policy
get_header(POLICY)
@@ -80,6 +81,14 @@ module ActionDispatch #:nodoc:
set_header(NONCE_GENERATOR, generator)
end
+ def content_security_policy_nonce_directives
+ get_header(NONCE_DIRECTIVES)
+ end
+
+ def content_security_policy_nonce_directives=(generator)
+ set_header(NONCE_DIRECTIVES, generator)
+ end
+
def content_security_policy_nonce
if content_security_policy_nonce_generator
if nonce = get_header(NONCE)
@@ -91,7 +100,6 @@ module ActionDispatch #:nodoc:
end
private
-
def generate_content_security_policy_nonce
content_security_policy_nonce_generator.call(self)
end
@@ -129,13 +137,17 @@ module ActionDispatch #:nodoc:
object_src: "object-src",
prefetch_src: "prefetch-src",
script_src: "script-src",
+ script_src_attr: "script-src-attr",
+ script_src_elem: "script-src-elem",
style_src: "style-src",
+ style_src_attr: "style-src-attr",
+ style_src_elem: "style-src-elem",
worker_src: "worker-src"
}.freeze
- NONCE_DIRECTIVES = %w[script-src style-src].freeze
+ DEFAULT_NONCE_DIRECTIVES = %w[script-src style-src].freeze
- private_constant :MAPPINGS, :DIRECTIVES, :NONCE_DIRECTIVES
+ private_constant :MAPPINGS, :DIRECTIVES, :DEFAULT_NONCE_DIRECTIVES
attr_reader :directives
@@ -204,8 +216,9 @@ module ActionDispatch #:nodoc:
end
end
- def build(context = nil, nonce = nil)
- build_directives(context, nonce).compact.join("; ")
+ def build(context = nil, nonce = nil, nonce_directives = nil)
+ nonce_directives = DEFAULT_NONCE_DIRECTIVES if nonce_directives.nil?
+ build_directives(context, nonce, nonce_directives).compact.join("; ")
end
private
@@ -228,10 +241,10 @@ module ActionDispatch #:nodoc:
end
end
- def build_directives(context, nonce)
+ def build_directives(context, nonce, nonce_directives)
@directives.map do |directive, sources|
if sources.is_a?(Array)
- if nonce && nonce_directive?(directive)
+ if nonce && nonce_directive?(directive, nonce_directives)
"#{directive} #{build_directive(sources, context).join(' ')} 'nonce-#{nonce}'"
else
"#{directive} #{build_directive(sources, context).join(' ')}"
@@ -266,8 +279,8 @@ module ActionDispatch #:nodoc:
end
end
- def nonce_directive?(directive)
- NONCE_DIRECTIVES.include?(directive)
+ def nonce_directive?(directive, nonce_directives)
+ nonce_directives.include?(directive)
end
end
end
diff --git a/actionpack/lib/action_dispatch/http/feature_policy.rb b/actionpack/lib/action_dispatch/http/feature_policy.rb
new file mode 100644
index 0000000000..592b6e4393
--- /dev/null
+++ b/actionpack/lib/action_dispatch/http/feature_policy.rb
@@ -0,0 +1,168 @@
+# frozen_string_literal: true
+
+require "active_support/core_ext/object/deep_dup"
+
+module ActionDispatch #:nodoc:
+ class FeaturePolicy
+ class Middleware
+ CONTENT_TYPE = "Content-Type"
+ POLICY = "Feature-Policy"
+
+ def initialize(app)
+ @app = app
+ end
+
+ def call(env)
+ request = ActionDispatch::Request.new(env)
+ _, headers, _ = response = @app.call(env)
+
+ return response unless html_response?(headers)
+ return response if policy_present?(headers)
+
+ if policy = request.feature_policy
+ headers[POLICY] = policy.build(request.controller_instance)
+ end
+
+ if policy_empty?(policy)
+ headers.delete(POLICY)
+ end
+
+ response
+ end
+
+ private
+ def html_response?(headers)
+ if content_type = headers[CONTENT_TYPE]
+ content_type =~ /html/
+ end
+ end
+
+ def policy_present?(headers)
+ headers[POLICY]
+ end
+
+ def policy_empty?(policy)
+ policy.try(:directives) && policy.directives.empty?
+ end
+ end
+
+ module Request
+ POLICY = "action_dispatch.feature_policy"
+
+ def feature_policy
+ get_header(POLICY)
+ end
+
+ def feature_policy=(policy)
+ set_header(POLICY, policy)
+ end
+ end
+
+ MAPPINGS = {
+ self: "'self'",
+ none: "'none'",
+ }.freeze
+
+ # List of available features can be found at
+ # https://github.com/WICG/feature-policy/blob/master/features.md#policy-controlled-features
+ DIRECTIVES = {
+ accelerometer: "accelerometer",
+ ambient_light_sensor: "ambient-light-sensor",
+ autoplay: "autoplay",
+ camera: "camera",
+ encrypted_media: "encrypted-media",
+ fullscreen: "fullscreen",
+ geolocation: "geolocation",
+ gyroscope: "gyroscope",
+ magnetometer: "magnetometer",
+ microphone: "microphone",
+ midi: "midi",
+ payment: "payment",
+ picture_in_picture: "picture-in-picture",
+ speaker: "speaker",
+ usb: "usb",
+ vibrate: "vibrate",
+ vr: "vr",
+ }.freeze
+
+ private_constant :MAPPINGS, :DIRECTIVES
+
+ attr_reader :directives
+
+ def initialize
+ @directives = {}
+ yield self if block_given?
+ end
+
+ def initialize_copy(other)
+ @directives = other.directives.deep_dup
+ end
+
+ DIRECTIVES.each do |name, directive|
+ define_method(name) do |*sources|
+ if sources.first
+ @directives[directive] = apply_mappings(sources)
+ else
+ @directives.delete(directive)
+ end
+ end
+ end
+
+ def build(context = nil)
+ build_directives(context).compact.join("; ")
+ end
+
+ private
+ def apply_mappings(sources)
+ sources.map do |source|
+ case source
+ when Symbol
+ apply_mapping(source)
+ when String, Proc
+ source
+ else
+ raise ArgumentError, "Invalid HTTP feature policy source: #{source.inspect}"
+ end
+ end
+ end
+
+ def apply_mapping(source)
+ MAPPINGS.fetch(source) do
+ raise ArgumentError, "Unknown HTTP feature policy source mapping: #{source.inspect}"
+ end
+ end
+
+ def build_directives(context)
+ @directives.map do |directive, sources|
+ if sources.is_a?(Array)
+ "#{directive} #{build_directive(sources, context).join(' ')}"
+ elsif sources
+ directive
+ else
+ nil
+ end
+ end
+ end
+
+ def build_directive(sources, context)
+ sources.map { |source| resolve_source(source, context) }
+ end
+
+ def resolve_source(source, context)
+ case source
+ when String
+ source
+ when Symbol
+ source.to_s
+ when Proc
+ if context.nil?
+ raise RuntimeError, "Missing context for the dynamic feature policy source: #{source.inspect}"
+ else
+ context.instance_exec(&source)
+ end
+ else
+ raise RuntimeError, "Unexpected feature policy source: #{source.inspect}"
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_dispatch/http/filter_parameters.rb b/actionpack/lib/action_dispatch/http/filter_parameters.rb
index cbb772175c..7a7a493f64 100644
--- a/actionpack/lib/action_dispatch/http/filter_parameters.rb
+++ b/actionpack/lib/action_dispatch/http/filter_parameters.rb
@@ -56,7 +56,6 @@ module ActionDispatch
end
private
-
def parameter_filter # :doc:
parameter_filter_for fetch_header("action_dispatch.parameter_filter") {
return NULL_PARAM_FILTER
diff --git a/actionpack/lib/action_dispatch/http/filter_redirect.rb b/actionpack/lib/action_dispatch/http/filter_redirect.rb
index 8c4e852235..d780d5f793 100644
--- a/actionpack/lib/action_dispatch/http/filter_redirect.rb
+++ b/actionpack/lib/action_dispatch/http/filter_redirect.rb
@@ -14,7 +14,6 @@ module ActionDispatch
end
private
-
def location_filters
if request
request.get_header("action_dispatch.redirect_filter") || []
diff --git a/actionpack/lib/action_dispatch/http/headers.rb b/actionpack/lib/action_dispatch/http/headers.rb
index 6c7d24d2d0..6ab913bfd0 100644
--- a/actionpack/lib/action_dispatch/http/headers.rb
+++ b/actionpack/lib/action_dispatch/http/headers.rb
@@ -116,7 +116,6 @@ module ActionDispatch
def env; @req.env.dup; end
private
-
# Converts an HTTP header name to an environment variable name if it is
# not contained within the headers hash.
def env_name(key)
diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
index 4e81ba12a5..a2cac49082 100644
--- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb
+++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
@@ -154,7 +154,6 @@ module ActionDispatch
end
private
-
BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/
def valid_accept_header # :doc:
diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb
index 88b3a93211..ed1d50f3b9 100644
--- a/actionpack/lib/action_dispatch/http/mime_type.rb
+++ b/actionpack/lib/action_dispatch/http/mime_type.rb
@@ -290,11 +290,9 @@ module Mime
def all?; false; end
protected
-
attr_reader :string, :synonyms
private
-
def to_ary; end
def to_a; end
diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb
index 13d0963a33..3c16817af3 100644
--- a/actionpack/lib/action_dispatch/http/parameters.rb
+++ b/actionpack/lib/action_dispatch/http/parameters.rb
@@ -85,7 +85,6 @@ module ActionDispatch
end
private
-
def set_binary_encoding(params, controller, action)
return params unless controller && controller.valid_encoding?
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 44f23940d3..4ac7c5c2bd 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -23,6 +23,7 @@ module ActionDispatch
include ActionDispatch::Http::FilterParameters
include ActionDispatch::Http::URL
include ActionDispatch::ContentSecurityPolicy::Request
+ include ActionDispatch::FeaturePolicy::Request
include Rack::Request::Env
autoload :Session, "action_dispatch/request/session"
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index 69798f99e0..ea3692951f 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -86,6 +86,7 @@ module ActionDispatch # :nodoc:
cattr_accessor :default_charset, default: "utf-8"
cattr_accessor :default_headers
+ cattr_accessor :return_only_media_type_on_content_type, default: false
include Rack::Response::Helpers
# Aliasing these off because AD::Http::Cache::Response defines them.
@@ -143,7 +144,6 @@ module ActionDispatch # :nodoc:
end
private
-
def each_chunk(&block)
@buf.each(&block)
end
@@ -243,8 +243,22 @@ module ActionDispatch # :nodoc:
end
# Content type of response.
- # It returns just MIME type and does NOT contain charset part.
def content_type
+ if self.class.return_only_media_type_on_content_type
+ ActiveSupport::Deprecation.warn(
+ "Rails 6.1 will return Content-Type header without modification." \
+ " If you want just the MIME type, please use `#media_type` instead."
+ )
+
+ content_type = super
+ content_type ? content_type.split(/;\s*charset=/)[0].presence : content_type
+ else
+ super.presence
+ end
+ end
+
+ # Media type of response.
+ def media_type
parsed_content_type_header.mime_type
end
@@ -405,7 +419,6 @@ module ActionDispatch # :nodoc:
end
private
-
ContentTypeHeader = Struct.new :mime_type, :charset
NullContentTypeHeader = ContentTypeHeader.new nil, nil
@@ -458,7 +471,7 @@ module ActionDispatch # :nodoc:
end
def assign_default_content_type_and_charset!
- return if content_type
+ return if media_type
ct = parsed_content_type_header
set_content_type(ct.mime_type || Mime[:html].to_s,
diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb
index 8227749986..3b0f6378ea 100644
--- a/actionpack/lib/action_dispatch/http/url.rb
+++ b/actionpack/lib/action_dispatch/http/url.rb
@@ -78,7 +78,6 @@ module ActionDispatch
end
private
-
def add_params(path, params)
params = { params: params } unless params.is_a?(Hash)
params.reject! { |_, v| v.to_param.nil? }
diff --git a/actionpack/lib/action_dispatch/journey/formatter.rb b/actionpack/lib/action_dispatch/journey/formatter.rb
index 52396ec901..a4861719f8 100644
--- a/actionpack/lib/action_dispatch/journey/formatter.rb
+++ b/actionpack/lib/action_dispatch/journey/formatter.rb
@@ -62,12 +62,11 @@ module ActionDispatch
end
private
-
def extract_parameterized_parts(route, options, recall, parameterize = nil)
parameterized_parts = recall.merge(options)
keys_to_keep = route.parts.reverse_each.drop_while { |part|
- !options.key?(part) || (options[part] || recall[part]).nil?
+ !(options.key?(part) || route.scope_options.key?(part)) || (options[part] || recall[part]).nil?
} | route.required_parts
parameterized_parts.delete_if do |bad_key, _|
diff --git a/actionpack/lib/action_dispatch/journey/gtg/builder.rb b/actionpack/lib/action_dispatch/journey/gtg/builder.rb
index 44c31053cb..2600e7fb70 100644
--- a/actionpack/lib/action_dispatch/journey/gtg/builder.rb
+++ b/actionpack/lib/action_dispatch/journey/gtg/builder.rb
@@ -128,7 +128,6 @@ module ActionDispatch
end
private
-
def followpos_table
@followpos ||= build_followpos
end
diff --git a/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb
index ea647e051a..5003e92f43 100644
--- a/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb
+++ b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb
@@ -141,7 +141,6 @@ module ActionDispatch
end
private
-
def states_hash_for(sym)
case sym
when String
diff --git a/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb b/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb
index fe55861507..b36003089d 100644
--- a/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb
+++ b/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb
@@ -94,7 +94,6 @@ module ActionDispatch
end
private
-
def inverted
return @inverted if @inverted
diff --git a/actionpack/lib/action_dispatch/journey/path/pattern.rb b/actionpack/lib/action_dispatch/journey/path/pattern.rb
index dee2980eb1..e4ba82ebdd 100644
--- a/actionpack/lib/action_dispatch/journey/path/pattern.rb
+++ b/actionpack/lib/action_dispatch/journey/path/pattern.rb
@@ -174,7 +174,6 @@ module ActionDispatch
end
private
-
def regexp_visitor
@anchored ? AnchoredRegexp : UnanchoredRegexp
end
diff --git a/actionpack/lib/action_dispatch/journey/route.rb b/actionpack/lib/action_dispatch/journey/route.rb
index 8165709a3d..4aee7a6f83 100644
--- a/actionpack/lib/action_dispatch/journey/route.rb
+++ b/actionpack/lib/action_dispatch/journey/route.rb
@@ -4,9 +4,9 @@ module ActionDispatch
# :stopdoc:
module Journey
class Route
- attr_reader :app, :path, :defaults, :name, :precedence
+ attr_reader :app, :path, :defaults, :name, :precedence, :constraints,
+ :internal, :scope_options
- attr_reader :constraints, :internal
alias :conditions :constraints
module VerbMatchers
@@ -49,15 +49,10 @@ module ActionDispatch
end
end
- def self.build(name, app, path, constraints, required_defaults, defaults)
- request_method_match = verb_matcher(constraints.delete(:request_method))
- new name, app, path, constraints, required_defaults, defaults, request_method_match, 0
- end
-
##
# +path+ is a path constraint.
# +constraints+ is a hash of constraints to be applied to this route.
- def initialize(name, app, path, constraints, required_defaults, defaults, request_method_match, precedence, internal = false)
+ def initialize(name:, app: nil, path:, constraints: {}, required_defaults: [], defaults: {}, request_method_match: nil, precedence: 0, scope_options: {}, internal: false)
@name = name
@app = app
@path = path
@@ -72,6 +67,7 @@ module ActionDispatch
@decorated_ast = nil
@precedence = precedence
@path_formatter = @path.build_formatter
+ @scope_options = scope_options
@internal = internal
end
diff --git a/actionpack/lib/action_dispatch/journey/router.rb b/actionpack/lib/action_dispatch/journey/router.rb
index 89a164f968..4a6639af74 100644
--- a/actionpack/lib/action_dispatch/journey/router.rb
+++ b/actionpack/lib/action_dispatch/journey/router.rb
@@ -81,7 +81,6 @@ module ActionDispatch
end
private
-
def partitioned_routes
routes.partition { |r|
r.path.anchored && r.ast.grep(Nodes::Symbol).all? { |n| n.default_regexp? }
diff --git a/actionpack/lib/action_dispatch/journey/routes.rb b/actionpack/lib/action_dispatch/journey/routes.rb
index 3ba8361d77..3f055db66d 100644
--- a/actionpack/lib/action_dispatch/journey/routes.rb
+++ b/actionpack/lib/action_dispatch/journey/routes.rb
@@ -71,7 +71,6 @@ module ActionDispatch
end
private
-
def clear_cache!
@ast = nil
@simulator = nil
diff --git a/actionpack/lib/action_dispatch/journey/scanner.rb b/actionpack/lib/action_dispatch/journey/scanner.rb
index 2a075862e9..eb6fd17aa7 100644
--- a/actionpack/lib/action_dispatch/journey/scanner.rb
+++ b/actionpack/lib/action_dispatch/journey/scanner.rb
@@ -33,7 +33,6 @@ module ActionDispatch
end
private
-
# takes advantage of String @- deduping capabilities in Ruby 2.5 upwards
# see: https://bugs.ruby-lang.org/issues/13077
def dedup_scan(regex)
diff --git a/actionpack/lib/action_dispatch/journey/visitors.rb b/actionpack/lib/action_dispatch/journey/visitors.rb
index d2619cbf3a..ff26c9a3b0 100644
--- a/actionpack/lib/action_dispatch/journey/visitors.rb
+++ b/actionpack/lib/action_dispatch/journey/visitors.rb
@@ -59,7 +59,6 @@ module ActionDispatch
end
private
-
def visit(node)
send(DISPATCH_CACHE[node.type], node)
end
@@ -168,7 +167,6 @@ module ActionDispatch
class String < FunctionalVisitor # :nodoc:
private
-
def binary(node, seed)
visit(node.right, visit(node.left, seed))
end
@@ -214,7 +212,6 @@ module ActionDispatch
end
private
-
def binary(node, seed)
seed.last.concat node.children.map { |c|
"#{node.object_id} -> #{c.object_id};"
diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index b69bcab05c..642f155085 100644
--- a/actionpack/lib/action_dispatch/middleware/cookies.rb
+++ b/actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -252,7 +252,6 @@ module ActionDispatch
end
private
-
def upgrade_legacy_hmac_aes_cbc_cookies?
request.secret_key_base.present? &&
request.encrypted_signed_cookie_salt.present? &&
@@ -287,8 +286,8 @@ module ActionDispatch
DOMAIN_REGEXP = /[^.]*\.([^.]*|..\...|...\...)$/
def self.build(req, cookies)
- new(req).tap do |hash|
- hash.update(cookies)
+ new(req).tap do |jar|
+ jar.update(cookies)
end
end
@@ -428,7 +427,6 @@ module ActionDispatch
mattr_accessor :always_write_cookie, default: false
private
-
def escape(string)
::Rack::Utils.escape(string)
end
diff --git a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
index 0b15c94122..e546d1c11f 100644
--- a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
@@ -4,8 +4,6 @@ require "action_dispatch/http/request"
require "action_dispatch/middleware/exception_wrapper"
require "action_dispatch/routing/inspector"
-require "active_support/actionable_error"
-
require "action_view"
require "action_view/base"
@@ -44,7 +42,6 @@ module ActionDispatch
end
private
-
def invoke_interceptors(request, exception)
backtrace_cleaner = request.get_header("action_dispatch.backtrace_cleaner")
wrapper = ExceptionWrapper.new(backtrace_cleaner, exception)
@@ -140,9 +137,7 @@ module ActionDispatch
return unless logger
exception = wrapper.exception
-
- trace = wrapper.application_trace
- trace = wrapper.framework_trace if trace.empty?
+ trace = wrapper.exception_trace
ActiveSupport::Deprecation.silence do
message = []
diff --git a/actionpack/lib/action_dispatch/middleware/debug_view.rb b/actionpack/lib/action_dispatch/middleware/debug_view.rb
index a03650254e..148662a48b 100644
--- a/actionpack/lib/action_dispatch/middleware/debug_view.rb
+++ b/actionpack/lib/action_dispatch/middleware/debug_view.rb
@@ -56,5 +56,11 @@ module ActionDispatch
def protect_against_forgery?
false
end
+
+ def params_valid?
+ @request.parameters
+ rescue ActionController::BadRequest
+ false
+ end
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
index 0cc56f5013..e4a2a51c57 100644
--- a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
+++ b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
@@ -36,18 +36,23 @@ module ActionDispatch
"ActionView::Template::Error"
]
+ cattr_accessor :silent_exceptions, default: [
+ "ActionController::RoutingError"
+ ]
+
attr_reader :backtrace_cleaner, :exception, :wrapped_causes, :line_number, :file
def initialize(backtrace_cleaner, exception)
@backtrace_cleaner = backtrace_cleaner
@exception = exception
+ @exception_class_name = @exception.class.name
@wrapped_causes = wrapped_causes_for(exception, backtrace_cleaner)
expand_backtrace if exception.is_a?(SyntaxError) || exception.cause.is_a?(SyntaxError)
end
def unwrapped_exception
- if wrapper_exceptions.include?(exception.class.to_s)
+ if wrapper_exceptions.include?(@exception_class_name)
exception.cause
else
exception
@@ -55,13 +60,19 @@ module ActionDispatch
end
def rescue_template
- @@rescue_templates[@exception.class.name]
+ @@rescue_templates[@exception_class_name]
end
def status_code
self.class.status_code_for_exception(unwrapped_exception.class.name)
end
+ def exception_trace
+ trace = application_trace
+ trace = framework_trace if trace.empty? && !silent_exceptions.include?(@exception_class_name)
+ trace
+ end
+
def application_trace
clean_backtrace(:silent)
end
@@ -130,7 +141,6 @@ module ActionDispatch
end
private
-
def backtrace
Array(@exception.backtrace)
end
diff --git a/actionpack/lib/action_dispatch/middleware/host_authorization.rb b/actionpack/lib/action_dispatch/middleware/host_authorization.rb
index b7dff1df41..de7739b9b6 100644
--- a/actionpack/lib/action_dispatch/middleware/host_authorization.rb
+++ b/actionpack/lib/action_dispatch/middleware/host_authorization.rb
@@ -30,7 +30,6 @@ module ActionDispatch
end
private
-
def sanitize_hosts(hosts)
Array(hosts).map do |host|
case host
@@ -87,7 +86,6 @@ module ActionDispatch
end
private
-
def authorized?(request)
origin_host = request.get_header("HTTP_HOST").to_s.sub(/:\d+\z/, "")
forwarded_host = request.x_forwarded_host.to_s.split(/,\s?/).last.to_s.sub(/:\d+\z/, "")
diff --git a/actionpack/lib/action_dispatch/middleware/public_exceptions.rb b/actionpack/lib/action_dispatch/middleware/public_exceptions.rb
index a88ad40f21..3a2a1d7334 100644
--- a/actionpack/lib/action_dispatch/middleware/public_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/public_exceptions.rb
@@ -32,7 +32,6 @@ module ActionDispatch
end
private
-
def render(status, content_type, body)
format = "to_#{content_type.to_sym}" if content_type
if format && body.respond_to?(format)
diff --git a/actionpack/lib/action_dispatch/middleware/remote_ip.rb b/actionpack/lib/action_dispatch/middleware/remote_ip.rb
index a5667573f4..c5d4a0bd31 100644
--- a/actionpack/lib/action_dispatch/middleware/remote_ip.rb
+++ b/actionpack/lib/action_dispatch/middleware/remote_ip.rb
@@ -156,7 +156,6 @@ module ActionDispatch
end
private
-
def ips_from(header) # :doc:
return [] unless header
# Split the comma-separated list into an array of strings.
diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
index 5b0be96223..3815971acb 100644
--- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
@@ -30,7 +30,6 @@ module ActionDispatch
end
private
-
def initialize_sid # :doc:
@default_options.delete(:sidbits)
@default_options.delete(:secure_random)
@@ -83,7 +82,6 @@ module ActionDispatch
include SessionObject
private
-
def set_cookie(request, session_id, cookie)
request.cookie_jar[key] = cookie
end
diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
index 7c43c781c7..892d88803e 100644
--- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
@@ -67,7 +67,6 @@ module ActionDispatch
end
private
-
def extract_session_id(req)
stale_session_check! do
unpacked_cookie_data(req)["session_id"]
diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
index 767143a368..a35c0da3d9 100644
--- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
@@ -40,7 +40,6 @@ module ActionDispatch
end
private
-
def render_exception(request, exception)
backtrace_cleaner = request.get_header "action_dispatch.backtrace_cleaner"
wrapper = ExceptionWrapper.new(backtrace_cleaner, exception)
diff --git a/actionpack/lib/action_dispatch/middleware/stack.rb b/actionpack/lib/action_dispatch/middleware/stack.rb
index f0c869fba0..775110d95e 100644
--- a/actionpack/lib/action_dispatch/middleware/stack.rb
+++ b/actionpack/lib/action_dispatch/middleware/stack.rb
@@ -34,7 +34,11 @@ module ActionDispatch
end
def build(app)
- InstrumentationProxy.new(klass.new(app, *args, &block), inspect)
+ klass.new(app, *args, &block)
+ end
+
+ def build_instrumented(app)
+ InstrumentationProxy.new(build(app), inspect)
end
end
@@ -119,11 +123,17 @@ module ActionDispatch
end
def build(app = nil, &block)
- middlewares.freeze.reverse.inject(app || block) { |a, e| e.build(a) }
+ instrumenting = ActiveSupport::Notifications.notifier.listening?(InstrumentationProxy::EVENT_NAME)
+ middlewares.freeze.reverse.inject(app || block) do |a, e|
+ if instrumenting
+ e.build_instrumented(a)
+ else
+ e.build(a)
+ end
+ end
end
private
-
def assert_index(index, where)
i = index.is_a?(Integer) ? index : middlewares.index { |m| m.klass == index }
raise "No such middleware to insert #{where}: #{index.inspect}" unless i
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
index 49b1e83551..04271d8e8a 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
@@ -6,7 +6,9 @@
<% end %>
<h2 style="margin-top: 30px">Request</h2>
-<p><b>Parameters</b>:</p> <pre><%= debug_params(@request.filtered_parameters) %></pre>
+<% if params_valid? %>
+ <p><b>Parameters</b>:</p> <pre><%= debug_params(@request.filtered_parameters) %></pre>
+<% end %>
<div class="details">
<div class="summary"><a href="#" onclick="return toggleSessionDump()">Toggle session dump</a></div>
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb
index 396768ecee..ca42a6fa8b 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb
@@ -1,5 +1,5 @@
<%
- clean_params = @request.filtered_parameters.clone
+ clean_params = params_valid? ? @request.filtered_parameters.clone : {}
clean_params.delete("action")
clean_params.delete("controller")
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb
index 999e84e4d6..57cdcf9aaf 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb
@@ -1,7 +1,7 @@
<header>
<h1>
<%= @exception.class.to_s %>
- <% if @request.parameters['controller'] %>
+ <% if params_valid? && @request.parameters['controller'] %>
in <%= @request.parameters['controller'].camelize %>Controller<% if @request.parameters['action'] %>#<%= @request.parameters['action'] %><% end %>
<% end %>
</h1>
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb
index 603de54b8b..d3265563a8 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb
@@ -1,5 +1,5 @@
<%= @exception.class.to_s %><%
- if @request.parameters['controller']
+ if params_valid? && @request.parameters['controller']
%> in <%= @request.parameters['controller'].camelize %>Controller<% if @request.parameters['action'] %>#<%= @request.parameters['action'] %><% end %>
<% end %>
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb
index 0f78e23b7f..f535822ccf 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb
@@ -2,11 +2,14 @@
<html lang="en">
<head>
<meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
<title>Action Controller: Exception caught</title>
<style>
body {
background-color: #FAFAFA;
color: #333;
+ color-scheme: light dark;
+ supported-color-schemes: light dark;
margin: 0px;
}
@@ -35,6 +38,7 @@
}
h1 {
+ overflow-wrap: break-word;
margin: 0.2em 0;
line-height: 1.1em;
font-size: 2em;
@@ -50,7 +54,7 @@
border-radius: 4px;
margin: 1em 0px;
display: block;
- width: 978px;
+ max-width: 978px;
}
.summary {
@@ -78,7 +82,7 @@
.source {
border: 1px solid #D9D9D9;
background: #ECECEC;
- width: 978px;
+ max-width: 978px;
}
.source pre {
@@ -114,11 +118,13 @@
}
.line.active {
- background-color: #FFCCCC;
+ background-color: #FCC;
}
.button_to {
display: inline-block;
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
}
.hidden {
@@ -127,10 +133,67 @@
a { color: #980905; }
a:visited { color: #666; }
- a.trace-frames { color: #666; }
+ a.trace-frames {
+ color: #666;
+ overflow-wrap: break-word;
+ }
a:hover { color: #C52F24; }
a.trace-frames.selected { color: #C52F24 }
+ @media (prefers-color-scheme: dark) {
+ body {
+ background-color: #222;
+ color: #ECECEC;
+ }
+
+ .details {
+ border-color: #666;
+ }
+
+ .summary {
+ border-color: #666;
+ }
+
+ .source {
+ border-color: #555;
+ background-color: #333;
+ }
+
+ .source .data {
+ background: #444;
+ }
+
+ .source .data .line_numbers {
+ background: #333;
+ border-color: #222;
+ }
+
+ .line:hover {
+ background: #666;
+ }
+
+ .line.active {
+ background-color: #977;
+ }
+
+ input[type="submit"] {
+ color: #EEE;
+ background-color: #535353;
+ border: none;
+ border-radius: 3px;
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0,0,0,0.15), 0 1px 1px rgba(0,0,0,0.15);
+ padding: 2px 7px;
+ }
+ input[type="submit"]:active {
+ background-color: #777;
+ }
+
+ a { color: #C52F24; }
+ a.trace-frames { color: #999; }
+ a:hover { color: #E9382B; }
+ a.trace-frames.selected { color: #E9382B; }
+ }
+
<%= yield :style %>
</style>
diff --git a/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb b/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb
index 0242b706b2..2fb4650398 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb
@@ -49,6 +49,17 @@
width: 80%;
font-size: inherit;
}
+
+ @media (prefers-color-scheme: dark) {
+ #route_table tbody tr:nth-child(odd) {
+ background: #333;
+ }
+
+ #route_table tbody.exact_matches,
+ #route_table tbody.fuzzy_matches {
+ color: #333;
+ }
+ }
<% end %>
<table id='route_table' class='route_table'>
diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb
index efc3988bc3..2e09aed41d 100644
--- a/actionpack/lib/action_dispatch/railtie.rb
+++ b/actionpack/lib/action_dispatch/railtie.rb
@@ -23,6 +23,7 @@ module ActionDispatch
config.action_dispatch.use_authenticated_cookie_encryption = false
config.action_dispatch.use_cookies_with_metadata = false
config.action_dispatch.perform_deep_munge = true
+ config.action_dispatch.return_only_media_type_on_content_type = true
config.action_dispatch.default_headers = {
"X-Frame-Options" => "SAMEORIGIN",
@@ -43,6 +44,7 @@ module ActionDispatch
ActionDispatch::Request::Utils.perform_deep_munge = app.config.action_dispatch.perform_deep_munge
ActionDispatch::Response.default_charset = app.config.action_dispatch.default_charset || app.config.encoding
ActionDispatch::Response.default_headers = app.config.action_dispatch.default_headers
+ ActionDispatch::Response.return_only_media_type_on_content_type = app.config.action_dispatch.return_only_media_type_on_content_type
ActionDispatch::ExceptionWrapper.rescue_responses.merge!(config.action_dispatch.rescue_responses)
ActionDispatch::ExceptionWrapper.rescue_templates.merge!(config.action_dispatch.rescue_templates)
diff --git a/actionpack/lib/action_dispatch/request/session.rb b/actionpack/lib/action_dispatch/request/session.rb
index bc5e0670e0..8faedf15b9 100644
--- a/actionpack/lib/action_dispatch/request/session.rb
+++ b/actionpack/lib/action_dispatch/request/session.rb
@@ -216,7 +216,6 @@ module ActionDispatch
end
private
-
def load_for_read!
load! if !loaded? && exists?
end
diff --git a/actionpack/lib/action_dispatch/routing/inspector.rb b/actionpack/lib/action_dispatch/routing/inspector.rb
index 413e524ef6..6e40a18009 100644
--- a/actionpack/lib/action_dispatch/routing/inspector.rb
+++ b/actionpack/lib/action_dispatch/routing/inspector.rb
@@ -177,7 +177,6 @@ module ActionDispatch
end
private
-
def draw_section(routes)
header_lengths = ["Prefix", "Verb", "URI Pattern"].map(&:length)
name_width, verb_width, path_width = widths(routes).zip(header_lengths).map(&:max)
@@ -210,7 +209,6 @@ module ActionDispatch
end
private
-
def draw_expanded_section(routes)
routes.map.each_with_index do |r, i|
<<~MESSAGE.chomp
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index f29f66990d..d1100089b1 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -70,17 +70,21 @@ module ActionDispatch
ANCHOR_CHARACTERS_REGEX = %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z}
OPTIONAL_FORMAT_REGEX = %r{(?:\(\.:format\)+|\.:format|/)\Z}
- attr_reader :requirements, :defaults
- attr_reader :to, :default_controller, :default_action
- attr_reader :required_defaults, :ast
+ attr_reader :requirements, :defaults, :to, :default_controller,
+ :default_action, :required_defaults, :ast, :scope_options
def self.build(scope, set, ast, controller, default_action, to, via, formatted, options_constraints, anchor, options)
- options = scope[:options].merge(options) if scope[:options]
-
- defaults = (scope[:defaults] || {}).dup
- scope_constraints = scope[:constraints] || {}
+ scope_params = {
+ blocks: scope[:blocks] || [],
+ constraints: scope[:constraints] || {},
+ defaults: (scope[:defaults] || {}).dup,
+ module: scope[:module],
+ options: scope[:options] || {}
+ }
- new set, ast, defaults, controller, default_action, scope[:module], to, formatted, scope_constraints, scope[:blocks] || [], via, options_constraints, anchor, options
+ new set: set, ast: ast, controller: controller, default_action: default_action,
+ to: to, formatted: formatted, via: via, options_constraints: options_constraints,
+ anchor: anchor, scope_params: scope_params, options: scope_params[:options].merge(options)
end
def self.check_via(via)
@@ -111,10 +115,9 @@ module ActionDispatch
format != false && path !~ OPTIONAL_FORMAT_REGEX
end
- def initialize(set, ast, defaults, controller, default_action, modyoule, to, formatted, scope_constraints, blocks, via, options_constraints, anchor, options)
- @defaults = defaults
- @set = set
-
+ def initialize(set:, ast:, controller:, default_action:, to:, formatted:, via:, options_constraints:, anchor:, scope_params:, options:)
+ @defaults = scope_params[:defaults]
+ @set = set
@to = intern(to)
@default_controller = intern(controller)
@default_action = intern(default_action)
@@ -122,22 +125,23 @@ module ActionDispatch
@anchor = anchor
@via = via
@internal = options.delete(:internal)
+ @scope_options = scope_params[:options]
path_params = ast.find_all(&:symbol?).map(&:to_sym)
options = add_wildcard_options(options, formatted, ast)
- options = normalize_options!(options, path_params, modyoule)
+ options = normalize_options!(options, path_params, scope_params[:module])
split_options = constraints(options, path_params)
- constraints = scope_constraints.merge Hash[split_options[:constraints] || []]
+ constraints = scope_params[:constraints].merge Hash[split_options[:constraints] || []]
if options_constraints.is_a?(Hash)
@defaults = Hash[options_constraints.find_all { |key, default|
URL_OPTIONS.include?(key) && (String === default || Integer === default)
}].merge @defaults
- @blocks = blocks
+ @blocks = scope_params[:blocks]
constraints.merge! options_constraints
else
@blocks = blocks(options_constraints)
@@ -160,8 +164,10 @@ module ActionDispatch
end
def make_route(name, precedence)
- Journey::Route.new(name, application, path, conditions, required_defaults,
- defaults, request_method, precedence, @internal)
+ Journey::Route.new(name: name, app: application, path: path, constraints: conditions,
+ required_defaults: required_defaults, defaults: defaults,
+ request_method_match: request_method, precedence: precedence,
+ scope_options: scope_options, internal: @internal)
end
def application
@@ -1667,7 +1673,6 @@ module ActionDispatch
end
private
-
def parent_resource
@scope[:scope_level_resource]
end
diff --git a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
index 4de5f9e2f7..e3322e99ab 100644
--- a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
+++ b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
@@ -156,7 +156,6 @@ module ActionDispatch
end
private
-
def polymorphic_url_for_action(action, record_or_hash, options)
polymorphic_url(record_or_hash, options.merge(action: action))
end
@@ -323,7 +322,6 @@ module ActionDispatch
end
private
-
def polymorphic_mapping(target, record)
if record.respond_to?(:to_model)
target._routes.polymorphic_mappings[record.to_model.model_name.name]
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index bbb5762b3c..5b35b68c44 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -40,7 +40,6 @@ module ActionDispatch
end
private
-
def controller(req)
req.controller_class
rescue NameError => e
@@ -59,7 +58,6 @@ module ActionDispatch
end
private
-
def controller(_); @controller_class; end
end
@@ -215,7 +213,6 @@ module ActionDispatch
end
private
-
def optimized_helper(args)
params = parameterize_args(args) do
raise_generation_error(args)
diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb
index fcb8ae296b..e02a6541c1 100644
--- a/actionpack/lib/action_dispatch/routing/url_for.rb
+++ b/actionpack/lib/action_dispatch/routing/url_for.rb
@@ -215,13 +215,11 @@ module ActionDispatch
end
protected
-
def optimize_routes_generation?
_routes.optimize_routes_generation? && default_url_options.empty?
end
private
-
def _with_routes(routes) # :doc:
old_routes, @_routes = @_routes, routes
yield
diff --git a/actionpack/lib/action_dispatch/system_test_case.rb b/actionpack/lib/action_dispatch/system_test_case.rb
index 066daa4a12..aae96975c7 100644
--- a/actionpack/lib/action_dispatch/system_test_case.rb
+++ b/actionpack/lib/action_dispatch/system_test_case.rb
@@ -1,16 +1,16 @@
# frozen_string_literal: true
-gem "capybara", ">= 2.15"
+gem "capybara", ">= 3.26"
require "capybara/dsl"
require "capybara/minitest"
+require "selenium/webdriver"
require "action_controller"
require "action_dispatch/system_testing/driver"
require "action_dispatch/system_testing/browser"
require "action_dispatch/system_testing/server"
require "action_dispatch/system_testing/test_helpers/screenshot_helper"
require "action_dispatch/system_testing/test_helpers/setup_and_teardown"
-require "action_dispatch/system_testing/test_helpers/undef_methods"
module ActionDispatch
# = System Testing
@@ -110,12 +110,11 @@ module ActionDispatch
# Because <tt>ActionDispatch::SystemTestCase</tt> is a shim between Capybara
# and Rails, any driver that is supported by Capybara is supported by system
# tests as long as you include the required gems and files.
- class SystemTestCase < IntegrationTest
+ class SystemTestCase < ActiveSupport::TestCase
include Capybara::DSL
include Capybara::Minitest::Assertions
include SystemTesting::TestHelpers::SetupAndTeardown
include SystemTesting::TestHelpers::ScreenshotHelper
- include SystemTesting::TestHelpers::UndefMethods
def initialize(*) # :nodoc:
super
@@ -160,8 +159,33 @@ module ActionDispatch
driven_by :selenium
- ActiveSupport.run_load_hooks(:action_dispatch_system_test_case, self)
- end
+ private
+ def url_helpers
+ @url_helpers ||=
+ if ActionDispatch.test_app
+ Class.new do
+ include ActionDispatch.test_app.routes.url_helpers
+
+ def url_options
+ default_url_options.reverse_merge(host: Capybara.app_host || Capybara.current_session.server_url)
+ end
+ end.new
+ end
+ end
- SystemTestCase.start_application
+ def method_missing(name, *args, &block)
+ if url_helpers.respond_to?(name)
+ url_helpers.public_send(name, *args, &block)
+ else
+ super
+ end
+ end
+
+ def respond_to_missing?(name, include_private = false)
+ url_helpers.respond_to?(name)
+ end
+ end
end
+
+ActiveSupport.run_load_hooks :action_dispatch_system_test_case, ActionDispatch::SystemTestCase
+ActionDispatch::SystemTestCase.start_application
diff --git a/actionpack/lib/action_dispatch/system_testing/browser.rb b/actionpack/lib/action_dispatch/system_testing/browser.rb
index c34907b6cb..e861e52f09 100644
--- a/actionpack/lib/action_dispatch/system_testing/browser.rb
+++ b/actionpack/lib/action_dispatch/system_testing/browser.rb
@@ -39,6 +39,29 @@ module ActionDispatch
end
end
+ # driver_path can be configured as a proc. The webdrivers gem uses this
+ # proc to update web drivers. Running this proc early allows us to only
+ # update the webdriver once and avoid race conditions when using
+ # parallel tests.
+ def preload
+ case type
+ when :chrome
+ if ::Selenium::WebDriver::Service.respond_to? :driver_path=
+ ::Selenium::WebDriver::Chrome::Service.driver_path.try(:call)
+ else
+ # Selenium <= v3.141.0
+ ::Selenium::WebDriver::Chrome.driver_path
+ end
+ when :firefox
+ if ::Selenium::WebDriver::Service.respond_to? :driver_path=
+ ::Selenium::WebDriver::Firefox::Service.driver_path.try(:call)
+ else
+ # Selenium <= v3.141.0
+ ::Selenium::WebDriver::Firefox.driver_path
+ end
+ end
+ end
+
private
def headless_chrome_browser_options
capabilities.args << "--headless"
diff --git a/actionpack/lib/action_dispatch/system_testing/driver.rb b/actionpack/lib/action_dispatch/system_testing/driver.rb
index 25a09dd918..15943a55ea 100644
--- a/actionpack/lib/action_dispatch/system_testing/driver.rb
+++ b/actionpack/lib/action_dispatch/system_testing/driver.rb
@@ -9,6 +9,8 @@ module ActionDispatch
@screen_size = options[:screen_size]
@options = options[:options]
@capabilities = capabilities
+
+ @browser.preload
end
def use
diff --git a/actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb b/actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb
index 7080dbe022..30dc21ebb9 100644
--- a/actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb
+++ b/actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb
@@ -4,16 +4,12 @@ module ActionDispatch
module SystemTesting
module TestHelpers
module SetupAndTeardown # :nodoc:
- DEFAULT_HOST = "http://127.0.0.1"
-
def host!(host)
- super
- Capybara.app_host = host
- end
+ ActiveSupport::Deprecation.warn \
+ "ActionDispatch::SystemTestCase#host! is deprecated with no replacement. " \
+ "Set Capybara.app_host directly or rely on Capybara's default host."
- def before_setup
- host! DEFAULT_HOST
- super
+ Capybara.app_host = host
end
def before_teardown
diff --git a/actionpack/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb b/actionpack/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb
deleted file mode 100644
index d64be3b3d9..0000000000
--- a/actionpack/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# frozen_string_literal: true
-
-module ActionDispatch
- module SystemTesting
- module TestHelpers
- module UndefMethods # :nodoc:
- extend ActiveSupport::Concern
- included do
- METHODS = %i(get post put patch delete).freeze
-
- METHODS.each do |verb|
- undef_method verb
- end
-
- def method_missing(method, *args, &block)
- if METHODS.include?(method)
- raise NoMethodError, "System tests cannot make direct requests via ##{method}; use #visit and #click_on instead. See http://www.rubydoc.info/github/teamcapybara/capybara/master#The_DSL for more information."
- else
- super
- end
- end
- end
- end
- end
- end
-end
diff --git a/actionpack/lib/action_dispatch/testing/assertion_response.rb b/actionpack/lib/action_dispatch/testing/assertion_response.rb
index dc019db6ac..79af372cc1 100644
--- a/actionpack/lib/action_dispatch/testing/assertion_response.rb
+++ b/actionpack/lib/action_dispatch/testing/assertion_response.rb
@@ -35,7 +35,6 @@ module ActionDispatch
end
private
-
def code_from_name(name)
GENERIC_RESPONSE_CODES[name] || Rack::Utils::SYMBOL_TO_STATUS_CODE[name]
end
diff --git a/actionpack/lib/action_dispatch/testing/assertions.rb b/actionpack/lib/action_dispatch/testing/assertions.rb
index 08c2969685..dcaf914ac9 100644
--- a/actionpack/lib/action_dispatch/testing/assertions.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions.rb
@@ -14,7 +14,7 @@ module ActionDispatch
include Rails::Dom::Testing::Assertions
def html_document
- @html_document ||= if @response.content_type.to_s.end_with?("xml")
+ @html_document ||= if @response.media_type.to_s.end_with?("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 bb8b43ad4d..9e7b4301a8 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -3,7 +3,6 @@
require "stringio"
require "uri"
require "active_support/core_ext/kernel/singleton_class"
-require "active_support/core_ext/object/try"
require "rack/test"
require "minitest"
@@ -50,11 +49,16 @@ module ActionDispatch
# Follow a single redirect response. If the last response was not a
# redirect, an exception will be raised. Otherwise, the redirect is
- # performed on the location header. Any arguments are passed to the
- # underlying call to `get`.
+ # performed on the location header. If the redirection is a 307 redirect,
+ # the same HTTP verb will be used when redirecting, otherwise a GET request
+ # will be performed. Any arguments are passed to the
+ # underlying request.
def follow_redirect!(**args)
raise "not a redirect! #{status} #{status_message}" unless redirect?
- get(response.location, **args)
+
+ method = response.status == 307 ? request.method.downcase : :get
+ public_send(method, response.location, **args)
+
status
end
end
diff --git a/actionpack/lib/action_dispatch/testing/test_response.rb b/actionpack/lib/action_dispatch/testing/test_response.rb
index 6f7c86fdcf..f1dd4099c5 100644
--- a/actionpack/lib/action_dispatch/testing/test_response.rb
+++ b/actionpack/lib/action_dispatch/testing/test_response.rb
@@ -19,7 +19,7 @@ module ActionDispatch
end
def response_parser
- @response_parser ||= RequestEncoder.parser(content_type)
+ @response_parser ||= RequestEncoder.parser(media_type)
end
end
end
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index 32a0b8efeb..1decfcee95 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -335,7 +335,6 @@ module RoutingTestHelpers
end
private
-
def make_request(env)
Request.new super, url_helpers, @block, strict
end
diff --git a/actionpack/test/controller/api/conditional_get_test.rb b/actionpack/test/controller/api/conditional_get_test.rb
index e366ce9532..f1cd9e46f9 100644
--- a/actionpack/test/controller/api/conditional_get_test.rb
+++ b/actionpack/test/controller/api/conditional_get_test.rb
@@ -18,7 +18,6 @@ class ConditionalGetApiController < ActionController::API
end
private
-
def handle_last_modified_and_etags
fresh_when(last_modified: Time.now.utc.beginning_of_day, etag: [ :foo, 123 ])
end
diff --git a/actionpack/test/controller/content_type_test.rb b/actionpack/test/controller/content_type_test.rb
index 636b025f2c..fcf767b706 100644
--- a/actionpack/test/controller/content_type_test.rb
+++ b/actionpack/test/controller/content_type_test.rb
@@ -66,73 +66,72 @@ class ContentTypeTest < ActionController::TestCase
def test_render_defaults
get :render_defaults
assert_equal "utf-8", @response.charset
- assert_equal Mime[:text], @response.content_type
+ assert_equal Mime[:text], @response.media_type
end
def test_render_changed_charset_default
with_default_charset "utf-16" do
get :render_defaults
assert_equal "utf-16", @response.charset
- assert_equal Mime[:text], @response.content_type
+ assert_equal Mime[:text], @response.media_type
end
end
# :ported:
def test_content_type_from_body
get :render_content_type_from_body
- assert_equal Mime[:rss], @response.content_type
+ assert_equal Mime[:rss], @response.media_type
assert_equal "utf-8", @response.charset
end
# :ported:
def test_content_type_from_render
get :render_content_type_from_render
- assert_equal Mime[:rss], @response.content_type
+ assert_equal Mime[:rss], @response.media_type
assert_equal "utf-8", @response.charset
end
# :ported:
def test_charset_from_body
get :render_charset_from_body
- assert_equal Mime[:text], @response.content_type
+ assert_equal Mime[:text], @response.media_type
assert_equal "utf-16", @response.charset
end
# :ported:
def test_nil_charset_from_body
get :render_nil_charset_from_body
- assert_equal Mime[:text], @response.content_type
+ assert_equal Mime[:text], @response.media_type
assert_equal "utf-8", @response.charset, @response.headers.inspect
end
def test_nil_default_for_erb
with_default_charset nil do
get :render_default_for_erb
- assert_equal Mime[:html], @response.content_type
+ assert_equal Mime[:html], @response.media_type
assert_nil @response.charset, @response.headers.inspect
end
end
def test_default_for_erb
get :render_default_for_erb
- assert_equal Mime[:html], @response.content_type
+ assert_equal Mime[:html], @response.media_type
assert_equal "utf-8", @response.charset
end
def test_default_for_builder
get :render_default_for_builder
- assert_equal Mime[:xml], @response.content_type
+ assert_equal Mime[:xml], @response.media_type
assert_equal "utf-8", @response.charset
end
def test_change_for_builder
get :render_change_for_builder
- assert_equal Mime[:html], @response.content_type
+ assert_equal Mime[:html], @response.media_type
assert_equal "utf-8", @response.charset
end
private
-
def with_default_charset(charset)
old_default_charset = ActionDispatch::Response.default_charset
ActionDispatch::Response.default_charset = charset
@@ -148,22 +147,22 @@ class AcceptBasedContentTypeTest < ActionController::TestCase
def test_render_default_content_types_for_respond_to
@request.accept = Mime[:html].to_s
get :render_default_content_types_for_respond_to
- assert_equal Mime[:html], @response.content_type
+ assert_equal Mime[:html], @response.media_type
@request.accept = Mime[:js].to_s
get :render_default_content_types_for_respond_to
- assert_equal Mime[:js], @response.content_type
+ assert_equal Mime[:js], @response.media_type
end
def test_render_default_content_types_for_respond_to_with_template
@request.accept = Mime[:xml].to_s
get :render_default_content_types_for_respond_to
- assert_equal Mime[:xml], @response.content_type
+ assert_equal Mime[:xml], @response.media_type
end
def test_render_default_content_types_for_respond_to_with_overwrite
@request.accept = Mime[:rss].to_s
get :render_default_content_types_for_respond_to
- assert_equal Mime[:xml], @response.content_type
+ assert_equal Mime[:xml], @response.media_type
end
end
diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb
index fcee812ee4..40443a9397 100644
--- a/actionpack/test/controller/filters_test.rb
+++ b/actionpack/test/controller/filters_test.rb
@@ -310,7 +310,6 @@ class FilterTest < ActionController::TestCase
after_action :conditional_in_parent_after, only: [:show, :another_action]
private
-
def conditional_in_parent_before
@ran_filter ||= []
@ran_filter << "conditional_in_parent_before"
@@ -508,7 +507,6 @@ class FilterTest < ActionController::TestCase
end
private
-
def filter_one
@filters ||= []
@filters << "filter_one"
@@ -532,7 +530,6 @@ class FilterTest < ActionController::TestCase
before_action :find_except, except: :edit
private
-
def find_only
@only = "Only"
end
diff --git a/actionpack/test/controller/flash_test.rb b/actionpack/test/controller/flash_test.rb
index bf95c633e5..1f44c7a68e 100644
--- a/actionpack/test/controller/flash_test.rb
+++ b/actionpack/test/controller/flash_test.rb
@@ -361,7 +361,6 @@ class FlashIntegrationTest < ActionDispatch::IntegrationTest
end
private
-
# Overwrite get to send SessionSecret in env hash
def get(path, *args)
args[0] ||= {}
diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb
index de8072a994..93a2ba1071 100644
--- a/actionpack/test/controller/helper_test.rb
+++ b/actionpack/test/controller/helper_test.rb
@@ -150,8 +150,8 @@ class HelperTest < ActiveSupport::TestCase
end
def test_default_helpers_only
- assert_equal [JustMeHelper], JustMeController._helpers.ancestors.reject(&:anonymous?)
- assert_equal [MeTooHelper, JustMeHelper], MeTooController._helpers.ancestors.reject(&:anonymous?)
+ assert_equal %w[JustMeHelper], JustMeController._helpers.ancestors.reject(&:anonymous?).map(&:to_s)
+ assert_equal %w[MeTooController::HelperMethods MeTooHelper JustMeHelper], MeTooController._helpers.ancestors.reject(&:anonymous?).map(&:to_s)
end
def test_base_helper_methods_after_clear_helpers
diff --git a/actionpack/test/controller/http_basic_authentication_test.rb b/actionpack/test/controller/http_basic_authentication_test.rb
index 1544a627ee..73524d0443 100644
--- a/actionpack/test/controller/http_basic_authentication_test.rb
+++ b/actionpack/test/controller/http_basic_authentication_test.rb
@@ -32,7 +32,6 @@ class HttpBasicAuthenticationTest < ActionController::TestCase
end
private
-
def authenticate
authenticate_or_request_with_http_basic do |username, password|
username == "lifo" && password == "world"
@@ -172,7 +171,6 @@ class HttpBasicAuthenticationTest < ActionController::TestCase
end
private
-
def encode_credentials(username, password)
"Basic #{::Base64.encode64("#{username}:#{password}")}"
end
diff --git a/actionpack/test/controller/http_digest_authentication_test.rb b/actionpack/test/controller/http_digest_authentication_test.rb
index dd4ff85d11..a0f543f607 100644
--- a/actionpack/test/controller/http_digest_authentication_test.rb
+++ b/actionpack/test/controller/http_digest_authentication_test.rb
@@ -20,7 +20,6 @@ class HttpDigestAuthenticationTest < ActionController::TestCase
end
private
-
def authenticate
authenticate_or_request_with_http_digest("SuperSecret") do |username|
# Returns the password
@@ -254,7 +253,6 @@ class HttpDigestAuthenticationTest < ActionController::TestCase
end
private
-
def encode_credentials(options)
options.reverse_merge!(nc: "00000001", cnonce: "0a4f113b", password_is_ha1: false)
password = options.delete(:password)
diff --git a/actionpack/test/controller/http_token_authentication_test.rb b/actionpack/test/controller/http_token_authentication_test.rb
index 103123f98c..57b78154bc 100644
--- a/actionpack/test/controller/http_token_authentication_test.rb
+++ b/actionpack/test/controller/http_token_authentication_test.rb
@@ -21,7 +21,6 @@ class HttpTokenAuthenticationTest < ActionController::TestCase
end
private
-
def authenticate
authenticate_or_request_with_http_token do |token, _|
token == "lifo"
@@ -190,7 +189,6 @@ class HttpTokenAuthenticationTest < ActionController::TestCase
end
private
-
def sample_request(token, options = { nonce: "def" })
authorization = options.inject([%{Token token="#{token}"}]) do |arr, (k, v)|
arr << "#{k}=\"#{v}\""
diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb
index 4dddd98f9f..caacd66bd6 100644
--- a/actionpack/test/controller/integration_test.rb
+++ b/actionpack/test/controller/integration_test.rb
@@ -213,6 +213,10 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest
redirect_to action_url("get")
end
+ def redirect_307
+ redirect_to action_url("post"), status: 307
+ end
+
def remove_header
response.headers.delete params[:header]
head :ok, "c" => "3"
@@ -337,6 +341,15 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest
end
end
+ def test_307_redirect_uses_the_same_http_verb
+ with_test_route_set do
+ post "/redirect_307"
+ assert_equal 307, status
+ follow_redirect!
+ assert_equal "POST", request.method
+ end
+ end
+
def test_redirect_reset_html_document
with_test_route_set do
get "/redirect"
@@ -522,11 +535,11 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest
with_test_route_set do
get "/get", headers: { "Accept" => "application/json" }, xhr: true
assert_equal "application/json", request.accept
- assert_equal "application/json", response.content_type
+ assert_equal "application/json", response.media_type
get "/get", headers: { "HTTP_ACCEPT" => "application/json" }, xhr: true
assert_equal "application/json", request.accept
- assert_equal "application/json", response.content_type
+ assert_equal "application/json", response.media_type
end
end
@@ -986,7 +999,7 @@ class IntegrationRequestEncodersTest < ActionDispatch::IntegrationTest
def test_encoding_as_json
post_to_foos as: :json do
assert_response :success
- assert_equal "application/json", request.content_type
+ assert_equal "application/json", request.media_type
assert_equal "application/json", request.accepts.first.to_s
assert_equal :json, request.format.ref
assert_equal({ "foo" => "fighters" }, request.request_parameters)
@@ -1025,7 +1038,7 @@ class IntegrationRequestEncodersTest < ActionDispatch::IntegrationTest
post_to_foos as: :wibble do
assert_response :success
assert_equal "/foos_wibble", request.path
- assert_equal "text/wibble", request.content_type
+ assert_equal "text/wibble", request.media_type
assert_equal "text/wibble", request.accepts.first.to_s
assert_equal :wibble, request.format.ref
assert_equal Hash.new, request.request_parameters # Unregistered MIME Type can't be parsed.
diff --git a/actionpack/test/controller/localized_templates_test.rb b/actionpack/test/controller/localized_templates_test.rb
index d84a76fb46..5c5cef66d5 100644
--- a/actionpack/test/controller/localized_templates_test.rb
+++ b/actionpack/test/controller/localized_templates_test.rb
@@ -43,6 +43,6 @@ class LocalizedTemplatesTest < ActionController::TestCase
I18n.locale = :it
get :hello_world
assert_equal "Ciao Mondo", @response.body
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
end
end
diff --git a/actionpack/test/controller/metal/renderers_test.rb b/actionpack/test/controller/metal/renderers_test.rb
index 5f0d125128..f6558f1354 100644
--- a/actionpack/test/controller/metal/renderers_test.rb
+++ b/actionpack/test/controller/metal/renderers_test.rb
@@ -38,13 +38,13 @@ class RenderersMetalTest < ActionController::TestCase
get :one
assert_response :success
assert_equal({ a: "b" }.to_json, @response.body)
- assert_equal "application/json", @response.content_type
+ assert_equal "application/json", @response.media_type
end
def test_render_xml
get :two
assert_response :success
assert_equal(" ", @response.body)
- assert_equal "text/plain", @response.content_type
+ assert_equal "text/plain", @response.media_type
end
end
diff --git a/actionpack/test/controller/mime/accept_format_test.rb b/actionpack/test/controller/mime/accept_format_test.rb
index eed671d593..fb038ae158 100644
--- a/actionpack/test/controller/mime/accept_format_test.rb
+++ b/actionpack/test/controller/mime/accept_format_test.rb
@@ -43,7 +43,6 @@ class PostController < AbstractPostController
end
private
-
def with_iphone
request.format = "iphone" if request.env["HTTP_ACCEPT"] == "text/iphone"
yield
diff --git a/actionpack/test/controller/mime/respond_to_test.rb b/actionpack/test/controller/mime/respond_to_test.rb
index 2f8f191828..fc16c639fb 100644
--- a/actionpack/test/controller/mime/respond_to_test.rb
+++ b/actionpack/test/controller/mime/respond_to_test.rb
@@ -423,12 +423,12 @@ class RespondToControllerTest < ActionController::TestCase
def test_using_defaults
@request.accept = "*/*"
get :using_defaults
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "Hello world!", @response.body
@request.accept = "application/xml"
get :using_defaults
- assert_equal "application/xml", @response.content_type
+ assert_equal "application/xml", @response.media_type
assert_equal "<p>Hello world!</p>\n", @response.body
end
@@ -449,12 +449,12 @@ class RespondToControllerTest < ActionController::TestCase
def test_using_defaults_with_type_list
@request.accept = "*/*"
get :using_defaults_with_type_list
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "Hello world!", @response.body
@request.accept = "application/xml"
get :using_defaults_with_type_list
- assert_equal "application/xml", @response.content_type
+ assert_equal "application/xml", @response.media_type
assert_equal "<p>Hello world!</p>\n", @response.body
end
@@ -468,7 +468,7 @@ class RespondToControllerTest < ActionController::TestCase
def test_using_non_conflicting_nested_js_then_js
@request.accept = "*/*"
get :using_non_conflicting_nested_js_then_js
- assert_equal "text/javascript", @response.content_type
+ assert_equal "text/javascript", @response.media_type
assert_equal "JS", @response.body
end
@@ -499,12 +499,12 @@ class RespondToControllerTest < ActionController::TestCase
def test_custom_types
@request.accept = "application/fancy-xml"
get :custom_type_handling
- assert_equal "application/fancy-xml", @response.content_type
+ assert_equal "application/fancy-xml", @response.media_type
assert_equal "Fancy XML", @response.body
@request.accept = "text/html"
get :custom_type_handling
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "HTML", @response.body
end
@@ -595,7 +595,7 @@ class RespondToControllerTest < ActionController::TestCase
@request.accept = "application/json"
get :json_with_callback
assert_equal "/**/alert(JS)", @response.body
- assert_equal "text/javascript", @response.content_type
+ assert_equal "text/javascript", @response.media_type
end
def test_xhr
@@ -605,13 +605,13 @@ class RespondToControllerTest < ActionController::TestCase
def test_custom_constant
get :custom_constant_handling, format: "mobile"
- assert_equal "text/x-mobile", @response.content_type
+ assert_equal "text/x-mobile", @response.media_type
assert_equal "Mobile", @response.body
end
def test_custom_constant_handling_without_block
get :custom_constant_handling_without_block, format: "mobile"
- assert_equal "text/x-mobile", @response.content_type
+ assert_equal "text/x-mobile", @response.media_type
assert_equal "Mobile", @response.body
end
@@ -664,7 +664,7 @@ class RespondToControllerTest < ActionController::TestCase
assert_equal '<html><div id="html">Hello future from Firefox!</div></html>', @response.body
get :iphone_with_html_response_type, format: "iphone"
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal '<html><div id="iphone">Hello iPhone future from iPhone!</div></html>', @response.body
end
@@ -672,7 +672,7 @@ class RespondToControllerTest < ActionController::TestCase
@request.accept = "text/iphone"
get :iphone_with_html_response_type
assert_equal '<html><div id="iphone">Hello iPhone future from iPhone!</div></html>', @response.body
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
end
def test_invalid_format
@@ -702,7 +702,7 @@ class RespondToControllerTest < ActionController::TestCase
def test_variant_with_implicit_template_rendering
get :variant_with_implicit_template_rendering, params: { v: :mobile }
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "mobile", @response.body
end
@@ -756,137 +756,137 @@ class RespondToControllerTest < ActionController::TestCase
def test_variant_with_format_and_custom_render
get :variant_with_format_and_custom_render, params: { v: :phone }
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "mobile", @response.body
end
def test_multiple_variants_for_format
get :multiple_variants_for_format, params: { v: :tablet }
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "tablet", @response.body
end
def test_no_variant_in_variant_setup
get :variant_plus_none_for_format
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "none", @response.body
end
def test_variant_inline_syntax
get :variant_inline_syntax
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "none", @response.body
get :variant_inline_syntax, params: { v: :phone }
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "phone", @response.body
end
def test_variant_inline_syntax_with_format
get :variant_inline_syntax, format: :js
- assert_equal "text/javascript", @response.content_type
+ assert_equal "text/javascript", @response.media_type
assert_equal "js", @response.body
end
def test_variant_inline_syntax_without_block
get :variant_inline_syntax_without_block, params: { v: :phone }
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "phone", @response.body
end
def test_variant_any
get :variant_any, params: { v: :phone }
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "phone", @response.body
get :variant_any, params: { v: :tablet }
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "any", @response.body
get :variant_any, params: { v: :phablet }
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "any", @response.body
end
def test_variant_any_any
get :variant_any_any
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "any", @response.body
get :variant_any_any, params: { v: :phone }
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "phone", @response.body
get :variant_any_any, params: { v: :yolo }
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "any", @response.body
end
def test_variant_inline_any
get :variant_any, params: { v: :phone }
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "phone", @response.body
get :variant_inline_any, params: { v: :tablet }
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "any", @response.body
get :variant_inline_any, params: { v: :phablet }
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "any", @response.body
end
def test_variant_inline_any_any
get :variant_inline_any_any, params: { v: :phone }
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "phone", @response.body
get :variant_inline_any_any, params: { v: :yolo }
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "any", @response.body
end
def test_variant_any_implicit_render
get :variant_any_implicit_render, params: { v: :tablet }
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "tablet", @response.body
get :variant_any_implicit_render, params: { v: :phablet }
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "phablet", @response.body
end
def test_variant_any_with_none
get :variant_any_with_none
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "none or phone", @response.body
get :variant_any_with_none, params: { v: :phone }
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "none or phone", @response.body
end
def test_format_any_variant_any
get :format_any_variant_any, format: :js, params: { v: :tablet }
- assert_equal "text/javascript", @response.content_type
+ assert_equal "text/javascript", @response.media_type
assert_equal "tablet", @response.body
end
def test_variant_negotiation_inline_syntax
get :variant_inline_syntax_without_block, params: { v: [:tablet, :phone] }
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "phone", @response.body
end
def test_variant_negotiation_block_syntax
get :variant_plus_none_for_format, params: { v: [:tablet, :phone] }
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "phone", @response.body
end
def test_variant_negotiation_without_block
get :variant_inline_syntax_without_block, params: { v: [:tablet, :phone] }
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
assert_equal "phone", @response.body
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 14dc958475..270f75eb9e 100644
--- a/actionpack/test/controller/new_base/render_template_test.rb
+++ b/actionpack/test/controller/new_base/render_template_test.rb
@@ -67,7 +67,6 @@ module RenderTemplate
end
private
-
def show_detailed_exceptions?
request.local?
end
diff --git a/actionpack/test/controller/new_base/render_test.rb b/actionpack/test/controller/new_base/render_test.rb
index eb29203f59..dfeb2e2b15 100644
--- a/actionpack/test/controller/new_base/render_test.rb
+++ b/actionpack/test/controller/new_base/render_test.rb
@@ -37,7 +37,6 @@ module Render
end
private
-
def secretz
render plain: "FAIL WHALE!"
end
diff --git a/actionpack/test/controller/parameters/accessors_test.rb b/actionpack/test/controller/parameters/accessors_test.rb
index 7789e654d5..3d1538ff64 100644
--- a/actionpack/test/controller/parameters/accessors_test.rb
+++ b/actionpack/test/controller/parameters/accessors_test.rb
@@ -203,6 +203,25 @@ class ParametersAccessorsTest < ActiveSupport::TestCase
assert_not_predicate @params.transform_keys { |k| k }, :permitted?
end
+ test "transform_keys without a block returns an enumerator" do
+ assert_kind_of Enumerator, @params.transform_keys
+ assert_kind_of ActionController::Parameters, @params.transform_keys.each { |k| k }
+ end
+
+ test "transform_keys! without a block returns an enumerator" do
+ assert_kind_of Enumerator, @params.transform_keys!
+ assert_kind_of ActionController::Parameters, @params.transform_keys!.each { |k| k }
+ end
+
+ test "deep_transform_keys retains permitted status" do
+ @params.permit!
+ assert_predicate @params.deep_transform_keys { |k| k }, :permitted?
+ end
+
+ test "deep_transform_keys retains unpermitted status" do
+ assert_not_predicate @params.deep_transform_keys { |k| k }, :permitted?
+ end
+
test "transform_values retains permitted status" do
@params.permit!
assert_predicate @params.transform_values { |v| v }, :permitted?
@@ -219,8 +238,9 @@ class ParametersAccessorsTest < ActiveSupport::TestCase
end
end
- test "transform_values without block yieds an enumerator" do
+ test "transform_values without a block returns an enumerator" do
assert_kind_of Enumerator, @params.transform_values
+ assert_kind_of ActionController::Parameters, @params.transform_values.each { |v| v }
end
test "transform_values! converts hashes to parameters" do
@@ -229,8 +249,9 @@ class ParametersAccessorsTest < ActiveSupport::TestCase
end
end
- test "transform_values! without block yields an enumerator" do
+ test "transform_values! without a block returns an enumerator" do
assert_kind_of Enumerator, @params.transform_values!
+ assert_kind_of ActionController::Parameters, @params.transform_values!.each { |v| v }
end
test "value? returns true if the given value is present in the params" do
@@ -263,12 +284,14 @@ class ParametersAccessorsTest < ActiveSupport::TestCase
params1 = ActionController::Parameters.new(a: 1, b: 2)
params2 = ActionController::Parameters.new(a: 1, b: 2)
assert(params1 == params2)
+ assert(params1.hash == params2.hash)
end
test "is equal to Parameters instance with same permitted params" do
params1 = ActionController::Parameters.new(a: 1, b: 2).permit(:a)
params2 = ActionController::Parameters.new(a: 1, b: 2).permit(:a)
assert(params1 == params2)
+ assert(params1.hash == params2.hash)
end
test "is equal to Parameters instance with same different source params, but same permitted params" do
@@ -276,6 +299,8 @@ class ParametersAccessorsTest < ActiveSupport::TestCase
params2 = ActionController::Parameters.new(a: 1, c: 3).permit(:a)
assert(params1 == params2)
assert(params2 == params1)
+ assert(params1.hash == params2.hash)
+ assert(params2.hash == params1.hash)
end
test "is not equal to an unpermitted Parameters instance with same params" do
@@ -283,6 +308,8 @@ class ParametersAccessorsTest < ActiveSupport::TestCase
params2 = ActionController::Parameters.new(a: 1)
assert(params1 != params2)
assert(params2 != params1)
+ assert(params1.hash != params2.hash)
+ assert(params2.hash != params1.hash)
end
test "is not equal to Parameters instance with different permitted params" do
@@ -290,6 +317,8 @@ class ParametersAccessorsTest < ActiveSupport::TestCase
params2 = ActionController::Parameters.new(a: 1, b: 2).permit(:a)
assert(params1 != params2)
assert(params2 != params1)
+ assert(params1.hash != params2.hash)
+ assert(params2.hash != params1.hash)
end
test "equality with simple types works" do
diff --git a/actionpack/test/controller/parameters/log_on_unpermitted_params_test.rb b/actionpack/test/controller/parameters/log_on_unpermitted_params_test.rb
index fc9229ca1d..4fffcf6b10 100644
--- a/actionpack/test/controller/parameters/log_on_unpermitted_params_test.rb
+++ b/actionpack/test/controller/parameters/log_on_unpermitted_params_test.rb
@@ -52,7 +52,6 @@ class LogOnUnpermittedParamsTest < ActiveSupport::TestCase
end
private
-
def assert_logged(message)
old_logger = ActionController::Base.logger
log = StringIO.new
diff --git a/actionpack/test/controller/parameters/mutators_test.rb b/actionpack/test/controller/parameters/mutators_test.rb
index 312b1e5b27..ffffd2996f 100644
--- a/actionpack/test/controller/parameters/mutators_test.rb
+++ b/actionpack/test/controller/parameters/mutators_test.rb
@@ -118,4 +118,31 @@ class ParametersMutatorsTest < ActiveSupport::TestCase
test "transform_values! retains unpermitted status" do
assert_not_predicate @params.transform_values! { |v| v }, :permitted?
end
+
+ test "deep_transform_keys! retains permitted status" do
+ @params.permit!
+ assert_predicate @params.deep_transform_keys! { |k| k }, :permitted?
+ end
+
+ test "deep_transform_keys! retains unpermitted status" do
+ assert_not_predicate @params.deep_transform_keys! { |k| k }, :permitted?
+ end
+
+ test "compact_blank retains permitted status" do
+ @params.permit!
+ assert_predicate @params.compact_blank, :permitted?
+ end
+
+ test "compact_blank retains unpermitted status" do
+ assert_not_predicate @params.compact_blank, :permitted?
+ end
+
+ test "compact_blank! retains permitted status" do
+ @params.permit!
+ assert_predicate @params.compact_blank!, :permitted?
+ end
+
+ test "compact_blank! retains unpermitted status" do
+ assert_not_predicate @params.compact_blank!, :permitted?
+ end
end
diff --git a/actionpack/test/controller/parameters/nested_parameters_permit_test.rb b/actionpack/test/controller/parameters/nested_parameters_permit_test.rb
index 1403e224c0..6243b5c51b 100644
--- a/actionpack/test/controller/parameters/nested_parameters_permit_test.rb
+++ b/actionpack/test/controller/parameters/nested_parameters_permit_test.rb
@@ -125,7 +125,7 @@ class NestedParametersPermitTest < ActiveSupport::TestCase
assert_nil permitted[:book][:genre]
end
- test "fields_for-style nested params" do
+ test "nested params with numeric keys" do
params = ActionController::Parameters.new(
book: {
authors_attributes: {
@@ -150,7 +150,33 @@ class NestedParametersPermitTest < ActiveSupport::TestCase
assert_filtered_out permitted[:book][:authors_attributes]["0"], :age_of_death
end
- test "fields_for-style nested params with negative numbers" do
+ test "nested params with non_numeric keys" do
+ params = ActionController::Parameters.new(
+ book: {
+ authors_attributes: {
+ '0': { name: "William Shakespeare", age_of_death: "52" },
+ '1': { name: "Unattributed Assistant" },
+ '2': "Not a hash",
+ 'new_record': { name: "Some name" }
+ }
+ })
+ permitted = params.permit book: { authors_attributes: [ :name ] }
+
+ assert_not_nil permitted[:book][:authors_attributes]["0"]
+ assert_not_nil permitted[:book][:authors_attributes]["1"]
+
+ assert_nil permitted[:book][:authors_attributes]["2"]
+ assert_nil permitted[:book][:authors_attributes]["new_record"]
+ assert_equal "William Shakespeare", permitted[:book][:authors_attributes]["0"][:name]
+ assert_equal "Unattributed Assistant", permitted[:book][:authors_attributes]["1"][:name]
+
+ assert_equal(
+ { "book" => { "authors_attributes" => { "0" => { "name" => "William Shakespeare" }, "1" => { "name" => "Unattributed Assistant" } } } },
+ permitted.to_h
+ )
+ end
+
+ test "nested params with negative numeric keys" do
params = ActionController::Parameters.new(
book: {
authors_attributes: {
diff --git a/actionpack/test/controller/params_parse_test.rb b/actionpack/test/controller/params_parse_test.rb
index 440ab06fd7..091b567473 100644
--- a/actionpack/test/controller/params_parse_test.rb
+++ b/actionpack/test/controller/params_parse_test.rb
@@ -24,7 +24,6 @@ class ParamsParseTest < ActionController::TestCase
end
private
-
def capture_log_output
output = StringIO.new
request.set_header "action_dispatch.logger", ActiveSupport::Logger.new(output)
diff --git a/actionpack/test/controller/params_wrapper_test.rb b/actionpack/test/controller/params_wrapper_test.rb
index c4c74e8f2b..894a3824c0 100644
--- a/actionpack/test/controller/params_wrapper_test.rb
+++ b/actionpack/test/controller/params_wrapper_test.rb
@@ -411,7 +411,6 @@ class IrregularInflectionParamsWrapperTest < ActionController::TestCase
end
private
-
def with_dup
original = ActiveSupport::Inflector::Inflections.instance_variable_get(:@__instance__)[:en]
ActiveSupport::Inflector::Inflections.instance_variable_set(:@__instance__, en: original.dup)
diff --git a/actionpack/test/controller/render_js_test.rb b/actionpack/test/controller/render_js_test.rb
index 1efc0b9de1..da8f6e8062 100644
--- a/actionpack/test/controller/render_js_test.rb
+++ b/actionpack/test/controller/render_js_test.rb
@@ -2,7 +2,6 @@
require "abstract_unit"
require "controller/fake_models"
-require "pathname"
class RenderJSTest < ActionController::TestCase
class TestController < ActionController::Base
@@ -26,7 +25,7 @@ class RenderJSTest < ActionController::TestCase
def test_render_vanilla_js
get :render_vanilla_js_hello, xhr: true
assert_equal "alert('hello')", @response.body
- assert_equal "text/javascript", @response.content_type
+ assert_equal "text/javascript", @response.media_type
end
def test_should_render_js_partial
diff --git a/actionpack/test/controller/render_json_test.rb b/actionpack/test/controller/render_json_test.rb
index 82c1ba26cb..82c6aaafe5 100644
--- a/actionpack/test/controller/render_json_test.rb
+++ b/actionpack/test/controller/render_json_test.rb
@@ -3,7 +3,6 @@
require "abstract_unit"
require "controller/fake_models"
require "active_support/logger"
-require "pathname"
class RenderJsonTest < ActionController::TestCase
class JsonRenderable
@@ -80,7 +79,7 @@ class RenderJsonTest < ActionController::TestCase
def test_render_json_nil
get :render_json_nil
assert_equal "null", @response.body
- assert_equal "application/json", @response.content_type
+ assert_equal "application/json", @response.media_type
end
def test_render_json_render_to_string
@@ -91,7 +90,7 @@ class RenderJsonTest < ActionController::TestCase
def test_render_json
get :render_json_hello_world
assert_equal '{"hello":"world"}', @response.body
- assert_equal "application/json", @response.content_type
+ assert_equal "application/json", @response.media_type
end
def test_render_json_with_status
@@ -103,31 +102,31 @@ class RenderJsonTest < ActionController::TestCase
def test_render_json_with_callback
get :render_json_hello_world_with_callback, xhr: true
assert_equal '/**/alert({"hello":"world"})', @response.body
- assert_equal "text/javascript", @response.content_type
+ assert_equal "text/javascript", @response.media_type
end
def test_render_json_with_custom_content_type
get :render_json_with_custom_content_type, xhr: true
assert_equal '{"hello":"world"}', @response.body
- assert_equal "text/javascript", @response.content_type
+ assert_equal "text/javascript", @response.media_type
end
def test_render_symbol_json
get :render_symbol_json
assert_equal '{"hello":"world"}', @response.body
- assert_equal "application/json", @response.content_type
+ assert_equal "application/json", @response.media_type
end
def test_render_json_with_render_to_string
get :render_json_with_render_to_string
assert_equal '{"hello":"partial html"}', @response.body
- assert_equal "application/json", @response.content_type
+ assert_equal "application/json", @response.media_type
end
def test_render_json_forwards_extra_options
get :render_json_with_extra_options
assert_equal '{"a":"b"}', @response.body
- assert_equal "application/json", @response.content_type
+ assert_equal "application/json", @response.media_type
end
def test_render_json_calls_to_json_from_object
diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb
index 8bb6617eaa..dd76824413 100644
--- a/actionpack/test/controller/render_test.rb
+++ b/actionpack/test/controller/render_test.rb
@@ -4,6 +4,11 @@ require "abstract_unit"
require "controller/fake_models"
class TestControllerWithExtraEtags < ActionController::Base
+ self.view_paths = [ActionView::FixtureResolver.new(
+ "test/with_implicit_template.erb" => "Hello explicitly!",
+ "test/hello_world.erb" => "Hello world!"
+ )]
+
def self.controller_name; "test"; end
def self.controller_path; "test"; end
@@ -37,6 +42,11 @@ class TestControllerWithExtraEtags < ActionController::Base
end
class ImplicitRenderTestController < ActionController::Base
+ self.view_paths = [ActionView::FixtureResolver.new(
+ "implicit_render_test/hello_world.erb" => "Hello world!",
+ "implicit_render_test/empty_action_with_template.html.erb" => "<h1>Empty action rendered this implicitly.</h1>\n"
+ )]
+
def empty_action
end
@@ -46,6 +56,10 @@ end
module Namespaced
class ImplicitRenderTestController < ActionController::Base
+ self.view_paths = [ActionView::FixtureResolver.new(
+ "namespaced/implicit_render_test/hello_world.erb" => "Hello world!"
+ )]
+
def hello_world
fresh_when(etag: "abc")
end
@@ -265,7 +279,6 @@ class TestController < ActionController::Base
end
private
-
def set_variable_for_layout
@variable_for_layout = nil
end
@@ -294,13 +307,15 @@ end
module TemplateModificationHelper
private
def modify_template(name)
- path = File.expand_path("../fixtures/#{name}.erb", __dir__)
- original = File.read(path)
- File.write(path, "#{original} Modified!")
+ hash = @controller.view_paths.first.instance_variable_get(:@hash)
+ key = name + ".erb"
+ original = hash[key]
+ hash[key] = "#{original} Modified!"
ActionView::LookupContext::DetailsKey.clear
yield
ensure
- File.write(path, original)
+ hash[key] = original
+ ActionView::LookupContext::DetailsKey.clear
end
end
diff --git a/actionpack/test/controller/render_xml_test.rb b/actionpack/test/controller/render_xml_test.rb
index a72d14e4bb..28d8e281ab 100644
--- a/actionpack/test/controller/render_xml_test.rb
+++ b/actionpack/test/controller/render_xml_test.rb
@@ -2,7 +2,6 @@
require "abstract_unit"
require "controller/fake_models"
-require "pathname"
class RenderXmlTest < ActionController::TestCase
class XmlRenderable
@@ -92,11 +91,11 @@ class RenderXmlTest < ActionController::TestCase
def test_should_render_xml_but_keep_custom_content_type
get :render_xml_with_custom_content_type
- assert_equal "application/atomsvc+xml", @response.content_type
+ assert_equal "application/atomsvc+xml", @response.media_type
end
def test_should_use_implicit_content_type
get :implicit_content_type, format: "atom"
- assert_equal Mime[:atom], @response.content_type
+ assert_equal Mime[:atom], @response.media_type
end
end
diff --git a/actionpack/test/controller/renderers_test.rb b/actionpack/test/controller/renderers_test.rb
index d92de6f5d5..96cce664a4 100644
--- a/actionpack/test/controller/renderers_test.rb
+++ b/actionpack/test/controller/renderers_test.rb
@@ -73,7 +73,7 @@ class RenderersTest < ActionController::TestCase
assert_raise ActionView::MissingTemplate do
get :respond_to_mime, format: "csv"
end
- assert_equal Mime[:csv], @response.content_type
+ assert_equal Mime[:csv], @response.media_type
assert_equal "", @response.body
end
@@ -83,7 +83,7 @@ class RenderersTest < ActionController::TestCase
end
@request.accept = "text/csv"
get :respond_to_mime, format: "csv"
- assert_equal Mime[:csv], @response.content_type
+ assert_equal Mime[:csv], @response.media_type
assert_equal "c,s,v", @response.body
ensure
ActionController::Renderers.remove :csv
diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb
index ea94a3e048..01250880f5 100644
--- a/actionpack/test/controller/request_forgery_protection_test.rb
+++ b/actionpack/test/controller/request_forgery_protection_test.rb
@@ -112,7 +112,6 @@ class PrependProtectForgeryBaseController < ActionController::Base
end
private
-
def add_called_callback(name)
@called_callbacks ||= []
@called_callbacks << name
diff --git a/actionpack/test/controller/rescue_test.rb b/actionpack/test/controller/rescue_test.rb
index 089b0b94d4..538bc15fc9 100644
--- a/actionpack/test/controller/rescue_test.rb
+++ b/actionpack/test/controller/rescue_test.rb
@@ -304,7 +304,6 @@ class RescueControllerTest < ActionController::TestCase
end
private
-
def capture_log_output
output = StringIO.new
request.set_header "action_dispatch.logger", ActiveSupport::Logger.new(output)
@@ -351,7 +350,6 @@ class RescueTest < ActionDispatch::IntegrationTest
end
private
-
def with_test_routing
with_routing do |set|
set.draw do
diff --git a/actionpack/test/controller/resources_test.rb b/actionpack/test/controller/resources_test.rb
index d2146f12a5..339025ec52 100644
--- a/actionpack/test/controller/resources_test.rb
+++ b/actionpack/test/controller/resources_test.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require "abstract_unit"
-require "active_support/core_ext/object/try"
require "active_support/core_ext/object/with_options"
require "active_support/core_ext/array/extract_options"
@@ -36,7 +35,6 @@ class ResourcesTest < ActionController::TestCase
collection: collection_methods,
member: member_methods,
path_names: path_names do
-
assert_restful_routes_for :messages,
collection: collection_methods,
member: member_methods,
@@ -58,7 +56,6 @@ class ResourcesTest < ActionController::TestCase
collection: collection_methods,
member: member_methods,
path_names: path_names do |options|
-
collection_methods.each_key do |action|
assert_named_route "/messages/#{path_names[action] || action}", "#{action}_messages_path", action: action
end
@@ -1251,7 +1248,7 @@ class ResourcesTest < ActionController::TestCase
shallow_path = "/#{options[:shallow] ? options[:namespace] : options[:path_prefix]}#{path}"
full_path = "/#{options[:path_prefix]}#{path}"
name_prefix = options[:name_prefix]
- shallow_prefix = options[:shallow] ? options[:namespace].try(:gsub, /\//, "_") : options[:name_prefix]
+ shallow_prefix = options[:shallow] ? options[:namespace]&.gsub(/\//, "_") : options[:name_prefix]
new_action = "new"
edit_action = "edit"
diff --git a/actionpack/test/controller/show_exceptions_test.rb b/actionpack/test/controller/show_exceptions_test.rb
index 8724f9bcdb..8e1068fecf 100644
--- a/actionpack/test/controller/show_exceptions_test.rb
+++ b/actionpack/test/controller/show_exceptions_test.rb
@@ -51,7 +51,6 @@ module ShowExceptions
class ShowExceptionsOverriddenController < ShowExceptionsController
private
-
def show_detailed_exceptions?
params["detailed"] == "1"
end
@@ -76,7 +75,7 @@ module ShowExceptions
@app = ShowExceptionsOverriddenController.action(:boom)
get "/", headers: { "HTTP_ACCEPT" => "application/json" }
assert_response :internal_server_error
- assert_equal "application/json", response.content_type.to_s
+ assert_equal "application/json", response.media_type
assert_equal({ status: 500, error: "Internal Server Error" }.to_json, response.body)
end
@@ -84,7 +83,7 @@ module ShowExceptions
@app = ShowExceptionsOverriddenController.action(:boom)
get "/", headers: { "HTTP_ACCEPT" => "application/xml" }
assert_response :internal_server_error
- assert_equal "application/xml", response.content_type.to_s
+ assert_equal "application/xml", response.media_type
assert_equal({ status: 500, error: "Internal Server Error" }.to_xml, response.body)
end
@@ -92,21 +91,21 @@ module ShowExceptions
@app = ShowExceptionsOverriddenController.action(:boom)
get "/", headers: { "HTTP_ACCEPT" => "text/csv" }
assert_response :internal_server_error
- assert_equal "text/html", response.content_type.to_s
+ assert_equal "text/html", response.media_type
end
end
class ShowFailsafeExceptionsTest < ActionDispatch::IntegrationTest
def test_render_failsafe_exception
@app = ShowExceptionsOverriddenController.action(:boom)
- middleware = @app.instance_variable_get(:@middleware)
+ middleware = @app
@exceptions_app = middleware.instance_variable_get(:@exceptions_app)
middleware.instance_variable_set(:@exceptions_app, nil)
$stderr = StringIO.new
get "/", headers: { "HTTP_ACCEPT" => "text/json" }
assert_response :internal_server_error
- assert_equal "text/plain", response.content_type.to_s
+ assert_equal "text/plain", response.media_type
ensure
middleware.instance_variable_set(:@exceptions_app, @exceptions_app)
$stderr = STDERR
diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb
index 998a495d0d..635a91507d 100644
--- a/actionpack/test/controller/test_case_test.rb
+++ b/actionpack/test/controller/test_case_test.rb
@@ -165,7 +165,6 @@ XML
end
private
-
def generate_url(opts)
url_for(opts.merge(action: "test_uri"))
end
diff --git a/actionpack/test/dispatch/callbacks_test.rb b/actionpack/test/dispatch/callbacks_test.rb
index fc80191c02..aa8640c506 100644
--- a/actionpack/test/dispatch/callbacks_test.rb
+++ b/actionpack/test/dispatch/callbacks_test.rb
@@ -38,7 +38,6 @@ class DispatcherTest < ActiveSupport::TestCase
end
private
-
def dispatch(&block)
ActionDispatch::Callbacks.new(block || DummyApp.new).call(
"rack.input" => StringIO.new("")
diff --git a/actionpack/test/dispatch/content_security_policy_test.rb b/actionpack/test/dispatch/content_security_policy_test.rb
index c8c885f35c..3d60dc1661 100644
--- a/actionpack/test/dispatch/content_security_policy_test.rb
+++ b/actionpack/test/dispatch/content_security_policy_test.rb
@@ -128,12 +128,36 @@ class ContentSecurityPolicyTest < ActiveSupport::TestCase
@policy.script_src false
assert_no_match %r{script-src}, @policy.build
+ @policy.script_src_attr :self
+ assert_match %r{script-src-attr 'self'}, @policy.build
+
+ @policy.script_src_attr false
+ assert_no_match %r{script-src-attr}, @policy.build
+
+ @policy.script_src_elem :self
+ assert_match %r{script-src-elem 'self'}, @policy.build
+
+ @policy.script_src_elem false
+ assert_no_match %r{script-src-elem}, @policy.build
+
@policy.style_src :self
assert_match %r{style-src 'self'}, @policy.build
@policy.style_src false
assert_no_match %r{style-src}, @policy.build
+ @policy.style_src_attr :self
+ assert_match %r{style-src-attr 'self'}, @policy.build
+
+ @policy.style_src_attr false
+ assert_no_match %r{style-src-attr}, @policy.build
+
+ @policy.style_src_elem :self
+ assert_match %r{style-src-elem 'self'}, @policy.build
+
+ @policy.style_src_elem false
+ assert_no_match %r{style-src-elem}, @policy.build
+
@policy.worker_src :self
assert_match %r{worker-src 'self'}, @policy.build
@@ -307,7 +331,6 @@ class DefaultContentSecurityPolicyIntegrationTest < ActionDispatch::IntegrationT
end
private
-
def assert_policy(expected, report_only: false)
if report_only
expected_header = "Content-Security-Policy-Report-Only"
@@ -470,7 +493,6 @@ class ContentSecurityPolicyIntegrationTest < ActionDispatch::IntegrationTest
end
private
-
def assert_policy(expected, report_only: false)
assert_response :success
@@ -544,3 +566,57 @@ class DisabledContentSecurityPolicyIntegrationTest < ActionDispatch::Integration
assert_equal "default-src https://example.com", response.headers["Content-Security-Policy"]
end
end
+
+class NonceDirectiveContentSecurityPolicyIntegrationTest < ActionDispatch::IntegrationTest
+ class PolicyController < ActionController::Base
+ def index
+ head :ok
+ end
+ end
+
+ ROUTES = ActionDispatch::Routing::RouteSet.new
+ ROUTES.draw do
+ scope module: "nonce_directive_content_security_policy_integration_test" do
+ get "/", to: "policy#index"
+ end
+ end
+
+ POLICY = ActionDispatch::ContentSecurityPolicy.new do |p|
+ p.default_src -> { :self }
+ p.script_src -> { :https }
+ p.style_src -> { :https }
+ end
+
+ class PolicyConfigMiddleware
+ def initialize(app)
+ @app = app
+ end
+
+ def call(env)
+ env["action_dispatch.content_security_policy"] = POLICY
+ env["action_dispatch.content_security_policy_nonce_generator"] = proc { "iyhD0Yc0W+c=" }
+ env["action_dispatch.content_security_policy_report_only"] = false
+ env["action_dispatch.content_security_policy_nonce_directives"] = %w(script-src)
+ env["action_dispatch.show_exceptions"] = false
+
+ @app.call(env)
+ end
+ end
+
+ APP = build_app(ROUTES) do |middleware|
+ middleware.use PolicyConfigMiddleware
+ middleware.use ActionDispatch::ContentSecurityPolicy::Middleware
+ end
+
+ def app
+ APP
+ end
+
+ def test_generate_nonce_only_specified_in_nonce_directives
+ get "/"
+
+ assert_response :success
+ assert_match "script-src https: 'nonce-iyhD0Yc0W+c='", response.headers["Content-Security-Policy"]
+ assert_no_match "style-src https: 'nonce-iyhD0Yc0W+c='", response.headers["Content-Security-Policy"]
+ end
+end
diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb
index 5ae8a20ae4..fa629bc761 100644
--- a/actionpack/test/dispatch/debug_exceptions_test.rb
+++ b/actionpack/test/dispatch/debug_exceptions_test.rb
@@ -208,7 +208,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
assert_response 500
assert_no_match(/<header>/, body)
assert_no_match(/<body>/, body)
- assert_equal "text/plain", response.content_type
+ assert_equal "text/plain", response.media_type
assert_match(/RuntimeError\npuke/, body)
Rails.stub :root, Pathname.new(".") do
@@ -222,31 +222,31 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
get "/not_found", headers: xhr_request_env
assert_response 404
assert_no_match(/<body>/, body)
- assert_equal "text/plain", response.content_type
+ assert_equal "text/plain", response.media_type
assert_match(/#{AbstractController::ActionNotFound.name}/, body)
get "/method_not_allowed", headers: xhr_request_env
assert_response 405
assert_no_match(/<body>/, body)
- assert_equal "text/plain", response.content_type
+ assert_equal "text/plain", response.media_type
assert_match(/ActionController::MethodNotAllowed/, body)
get "/unknown_http_method", headers: xhr_request_env
assert_response 405
assert_no_match(/<body>/, body)
- assert_equal "text/plain", response.content_type
+ assert_equal "text/plain", response.media_type
assert_match(/ActionController::UnknownHttpMethod/, body)
get "/bad_request", headers: xhr_request_env
assert_response 400
assert_no_match(/<body>/, body)
- assert_equal "text/plain", response.content_type
+ assert_equal "text/plain", response.media_type
assert_match(/ActionController::BadRequest/, body)
get "/parameter_missing", headers: xhr_request_env
assert_response 400
assert_no_match(/<body>/, body)
- assert_equal "text/plain", response.content_type
+ assert_equal "text/plain", response.media_type
assert_match(/ActionController::ParameterMissing/, body)
end
@@ -257,37 +257,37 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
assert_response 500
assert_no_match(/<header>/, body)
assert_no_match(/<body>/, body)
- assert_equal "application/json", response.content_type
+ assert_equal "application/json", response.media_type
assert_match(/RuntimeError: puke/, body)
get "/not_found", headers: { "action_dispatch.show_exceptions" => true }, as: :json
assert_response 404
assert_no_match(/<body>/, body)
- assert_equal "application/json", response.content_type
+ assert_equal "application/json", response.media_type
assert_match(/#{AbstractController::ActionNotFound.name}/, body)
get "/method_not_allowed", headers: { "action_dispatch.show_exceptions" => true }, as: :json
assert_response 405
assert_no_match(/<body>/, body)
- assert_equal "application/json", response.content_type
+ assert_equal "application/json", response.media_type
assert_match(/ActionController::MethodNotAllowed/, body)
get "/unknown_http_method", headers: { "action_dispatch.show_exceptions" => true }, as: :json
assert_response 405
assert_no_match(/<body>/, body)
- assert_equal "application/json", response.content_type
+ assert_equal "application/json", response.media_type
assert_match(/ActionController::UnknownHttpMethod/, body)
get "/bad_request", headers: { "action_dispatch.show_exceptions" => true }, as: :json
assert_response 400
assert_no_match(/<body>/, body)
- assert_equal "application/json", response.content_type
+ assert_equal "application/json", response.media_type
assert_match(/ActionController::BadRequest/, body)
get "/parameter_missing", headers: { "action_dispatch.show_exceptions" => true }, as: :json
assert_response 400
assert_no_match(/<body>/, body)
- assert_equal "application/json", response.content_type
+ assert_equal "application/json", response.media_type
assert_match(/ActionController::ParameterMissing/, body)
end
@@ -298,7 +298,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
assert_response 500
assert_match(/<header>/, body)
assert_match(/<body>/, body)
- assert_equal "text/html", response.content_type
+ assert_equal "text/html", response.media_type
assert_match(/puke/, body)
end
@@ -307,7 +307,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
get "/index.xml", headers: { "action_dispatch.show_exceptions" => true }
assert_response 500
- assert_equal "application/xml", response.content_type
+ assert_equal "application/xml", response.media_type
assert_match(/RuntimeError: puke/, body)
end
@@ -321,7 +321,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
get "/index", headers: { "action_dispatch.show_exceptions" => true }, as: :wibble
assert_response 500
- assert_equal "application/json", response.content_type
+ assert_equal "application/json", response.media_type
assert_match(/RuntimeError: puke/, body)
ensure
@@ -466,6 +466,8 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
end
test "logs exception backtrace when all lines silenced" do
+ @app = DevelopmentApp
+
output = StringIO.new
backtrace_cleaner = ActiveSupport::BacktraceCleaner.new
backtrace_cleaner.add_silencer { true }
@@ -478,6 +480,27 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
assert_operator((output.rewind && output.read).lines.count, :>, 10)
end
+ test "doesn't log the framework backtrace when error type is a routing error" do
+ @app = ProductionApp
+
+ output = StringIO.new
+ backtrace_cleaner = ActiveSupport::BacktraceCleaner.new
+ backtrace_cleaner.add_silencer { true }
+
+ env = { "action_dispatch.show_exceptions" => true,
+ "action_dispatch.logger" => Logger.new(output),
+ "action_dispatch.backtrace_cleaner" => backtrace_cleaner }
+
+ assert_raises ActionController::RoutingError do
+ get "/pass", headers: env
+ end
+
+ log = output.rewind && output.read
+
+ assert_includes log, "ActionController::RoutingError (No route matches [GET] \"/pass\")"
+ assert_equal 3, log.lines.count
+ end
+
test "display backtrace when error type is SyntaxError" do
@app = DevelopmentApp
@@ -620,4 +643,23 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
assert_select 'input[value="Action 2"]'
end
end
+
+ test "debug exceptions app shows diagnostics when malformed query parameters are provided" do
+ @app = DevelopmentApp
+
+ get "/bad_request?x[y]=1&x[y][][w]=2"
+
+ assert_response 400
+ assert_match "ActionController::BadRequest", body
+ end
+
+ test "debug exceptions app shows diagnostics when malformed query parameters are provided by XHR" do
+ @app = DevelopmentApp
+ xhr_request_env = { "action_dispatch.show_exceptions" => true, "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest" }
+
+ get "/bad_request?x[y]=1&x[y][][w]=2", headers: xhr_request_env
+
+ assert_response 400
+ assert_match "ActionController::BadRequest", body
+ end
end
diff --git a/actionpack/test/dispatch/feature_policy_test.rb b/actionpack/test/dispatch/feature_policy_test.rb
new file mode 100644
index 0000000000..ebcc8a8b6d
--- /dev/null
+++ b/actionpack/test/dispatch/feature_policy_test.rb
@@ -0,0 +1,142 @@
+# frozen_string_literal: true
+
+require "abstract_unit"
+
+class FeaturePolicyTest < ActiveSupport::TestCase
+ def setup
+ @policy = ActionDispatch::FeaturePolicy.new
+ end
+
+ def test_mappings
+ @policy.midi :self
+ assert_equal "midi 'self'", @policy.build
+
+ @policy.midi :none
+ assert_equal "midi 'none'", @policy.build
+ end
+
+ def test_multiple_sources_for_a_single_directive
+ @policy.geolocation :self, "https://example.com"
+ assert_equal "geolocation 'self' https://example.com", @policy.build
+ end
+
+ def test_single_directive_for_multiple_directives
+ @policy.geolocation :self
+ @policy.usb :none
+ assert_equal "geolocation 'self'; usb 'none'", @policy.build
+ end
+
+ def test_multiple_directives_for_multiple_directives
+ @policy.geolocation :self, "https://example.com"
+ @policy.usb :none, "https://example.com"
+ assert_equal "geolocation 'self' https://example.com; usb 'none' https://example.com", @policy.build
+ end
+
+ def test_invalid_directive_source
+ exception = assert_raises(ArgumentError) do
+ @policy.vr [:non_existent]
+ end
+
+ assert_equal "Invalid HTTP feature policy source: [:non_existent]", exception.message
+ end
+end
+
+class FeaturePolicyIntegrationTest < ActionDispatch::IntegrationTest
+ class PolicyController < ActionController::Base
+ feature_policy only: :index do |f|
+ f.gyroscope :none
+ end
+
+ feature_policy only: :sample_controller do |f|
+ f.gyroscope nil
+ f.usb :self
+ end
+
+ feature_policy only: :multiple_directives do |f|
+ f.gyroscope nil
+ f.usb :self
+ f.autoplay "https://example.com"
+ f.payment "https://secure.example.com"
+ end
+
+ def index
+ head :ok
+ end
+
+ def sample_controller
+ head :ok
+ end
+
+ def multiple_directives
+ head :ok
+ end
+ end
+
+ ROUTES = ActionDispatch::Routing::RouteSet.new
+ ROUTES.draw do
+ scope module: "feature_policy_integration_test" do
+ get "/", to: "policy#index"
+ get "/sample_controller", to: "policy#sample_controller"
+ get "/multiple_directives", to: "policy#multiple_directives"
+ end
+ end
+
+ POLICY = ActionDispatch::FeaturePolicy.new do |p|
+ p.gyroscope :self
+ end
+
+ class PolicyConfigMiddleware
+ def initialize(app)
+ @app = app
+ end
+
+ def call(env)
+ env["action_dispatch.feature_policy"] = POLICY
+ env["action_dispatch.show_exceptions"] = false
+
+ @app.call(env)
+ end
+ end
+
+ APP = build_app(ROUTES) do |middleware|
+ middleware.use PolicyConfigMiddleware
+ middleware.use ActionDispatch::FeaturePolicy::Middleware
+ end
+
+ def app
+ APP
+ end
+
+ def test_generates_feature_policy_header
+ get "/"
+ assert_policy "gyroscope 'none'"
+ end
+
+ def test_generates_per_controller_feature_policy_header
+ get "/sample_controller"
+ assert_policy "usb 'self'"
+ end
+
+ def test_generates_multiple_directives_feature_policy_header
+ get "/multiple_directives"
+ assert_policy "usb 'self'; autoplay https://example.com; payment https://secure.example.com"
+ end
+
+ private
+ def env_config
+ Rails.application.env_config
+ end
+
+ def feature_policy
+ env_config["action_dispatch.feature_policy"]
+ end
+
+ def feature_policy=(policy)
+ env_config["action_dispatch.feature_policy"] = policy
+ end
+
+ def assert_policy(expected)
+ assert_response :success
+ assert_equal expected, response.headers["Feature-Policy"]
+ end
+end
diff --git a/actionpack/test/dispatch/middleware_stack_test.rb b/actionpack/test/dispatch/middleware_stack_test.rb
index 90f2eccd19..c534e60c74 100644
--- a/actionpack/test/dispatch/middleware_stack_test.rb
+++ b/actionpack/test/dispatch/middleware_stack_test.rb
@@ -121,9 +121,6 @@ class MiddlewareStackTest < ActiveSupport::TestCase
end
test "instruments the execution of middlewares" do
- app = @stack.build(proc { |env| [200, {}, []] })
- env = {}
-
events = []
subscriber = proc do |*args|
@@ -131,6 +128,9 @@ class MiddlewareStackTest < ActiveSupport::TestCase
end
ActiveSupport::Notifications.subscribed(subscriber, "process_middleware.action_dispatch") do
+ app = @stack.build(proc { |env| [200, {}, []] })
+
+ env = {}
app.call(env)
end
diff --git a/actionpack/test/dispatch/request_id_test.rb b/actionpack/test/dispatch/request_id_test.rb
index 9df4712dab..036180c297 100644
--- a/actionpack/test/dispatch/request_id_test.rb
+++ b/actionpack/test/dispatch/request_id_test.rb
@@ -29,7 +29,6 @@ class RequestIdTest < ActiveSupport::TestCase
end
private
-
def stub_request(env = {})
ActionDispatch::RequestId.new(lambda { |environment| [ 200, environment, [] ] }).call(env)
ActionDispatch::Request.new(env)
@@ -58,7 +57,6 @@ class RequestIdResponseTest < ActionDispatch::IntegrationTest
end
private
-
def with_test_route_set
with_routing do |set|
set.draw do
diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb
index eb49396145..0ec8dd25e0 100644
--- a/actionpack/test/dispatch/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -681,7 +681,6 @@ end
class RequestMethod < BaseRequestTest
test "method returns environment's request method when it has not been
overridden by middleware".squish do
-
ActionDispatch::Request::HTTP_METHODS.each do |method|
request = stub_request("REQUEST_METHOD" => method)
diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb
index 7758b0406a..ed64d89902 100644
--- a/actionpack/test/dispatch/response_test.rb
+++ b/actionpack/test/dispatch/response_test.rb
@@ -290,8 +290,8 @@ class ResponseTest < ActiveSupport::TestCase
resp.to_a
assert_equal("utf-16", resp.charset)
- assert_equal(Mime[:xml], resp.content_type)
-
+ assert_equal(Mime[:xml], resp.media_type)
+ assert_equal("application/xml; charset=utf-16", resp.content_type)
assert_equal("application/xml; charset=utf-16", resp.headers["Content-Type"])
end
@@ -503,8 +503,8 @@ class ResponseIntegrationTest < ActionDispatch::IntegrationTest
assert_response :success
assert_equal("utf-16", @response.charset)
- assert_equal(Mime[:xml], @response.content_type)
-
+ assert_equal(Mime[:xml], @response.media_type)
+ assert_equal("application/xml; charset=utf-16", @response.content_type)
assert_equal("application/xml; charset=utf-16", @response.headers["Content-Type"])
end
@@ -519,8 +519,8 @@ class ResponseIntegrationTest < ActionDispatch::IntegrationTest
assert_response :success
assert_equal("utf-16", @response.charset)
- assert_equal(Mime[:xml], @response.content_type)
-
+ assert_equal(Mime[:xml], @response.media_type)
+ assert_equal("application/xml; charset=utf-16", @response.content_type)
assert_equal("application/xml; charset=utf-16", @response.headers["Content-Type"])
end
@@ -553,7 +553,26 @@ class ResponseIntegrationTest < ActionDispatch::IntegrationTest
assert_response :success
assert_equal("text/csv; charset=utf-16; header=present", @response.headers["Content-Type"])
- assert_equal("text/csv", @response.content_type)
+ assert_equal("text/csv; charset=utf-16; header=present", @response.content_type)
+ assert_equal("text/csv", @response.media_type)
+ assert_equal("utf-16", @response.charset)
+ end
+
+ test "response Content-Type with optional parameters that set before charset" do
+ @app = lambda { |env|
+ [
+ 200,
+ { "Content-Type" => "text/csv; header=present; charset=utf-16" },
+ ["Hello"]
+ ]
+ }
+
+ get "/"
+ assert_response :success
+
+ assert_equal("text/csv; header=present; charset=utf-16", @response.headers["Content-Type"])
+ assert_equal("text/csv; header=present; charset=utf-16", @response.content_type)
+ assert_equal("text/csv", @response.media_type)
assert_equal("utf-16", @response.charset)
end
@@ -570,7 +589,37 @@ class ResponseIntegrationTest < ActionDispatch::IntegrationTest
assert_response :success
assert_equal('text/csv; header=present; charset="utf-16"', @response.headers["Content-Type"])
- assert_equal("text/csv", @response.content_type)
+ assert_equal('text/csv; header=present; charset="utf-16"', @response.content_type)
+ assert_equal("text/csv", @response.media_type)
assert_equal("utf-16", @response.charset)
end
+
+ test "`content type` returns header that excludes `charset` when specified `return_only_media_type_on_content_type`" do
+ original = ActionDispatch::Response.return_only_media_type_on_content_type
+ ActionDispatch::Response.return_only_media_type_on_content_type = true
+
+ @app = lambda { |env|
+ if env["PATH_INFO"] == "/with_parameters"
+ [200, { "Content-Type" => "text/csv; header=present; charset=utf-16" }, [""]]
+ else
+ [200, { "Content-Type" => "text/csv; charset=utf-16" }, [""]]
+ end
+ }
+
+ get "/"
+ assert_response :success
+
+ assert_deprecated do
+ assert_equal("text/csv", @response.content_type)
+ end
+
+ get "/with_parameters"
+ assert_response :success
+
+ assert_deprecated do
+ assert_equal("text/csv; header=present", @response.content_type)
+ end
+ ensure
+ ActionDispatch::Response.return_only_media_type_on_content_type = original
+ end
end
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index 362488d585..b67b1dd347 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -3810,7 +3810,6 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
private
-
def draw(&block)
self.class.stub_controllers do |routes|
routes.default_url_options = { host: "www.example.com" }
@@ -4953,12 +4952,52 @@ class TestPartialDynamicPathSegments < ActionDispatch::IntegrationTest
end
private
-
def assert_params(params)
assert_equal(params, request.path_parameters)
end
end
+class TestOptionalScopesWithOrWithoutParams < ActionDispatch::IntegrationTest
+ Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
+ app.draw do
+ scope module: "test_optional_scopes_with_or_without_params" do
+ scope "(:locale)", locale: /en|es/ do
+ get "home", to: "home#index"
+ get "with_param/:foo", to: "home#with_param", as: "with_param"
+ get "without_param", to: "home#without_param"
+ end
+ end
+ end
+ end
+
+ class HomeController < ActionController::Base
+ include Routes.url_helpers
+
+ def index
+ render inline: "<%= with_param_path(foo: 'bar') %> | <%= without_param_path %>"
+ end
+
+ def with_param; end
+ def without_param; end
+ end
+
+ APP = build_app Routes
+
+ def app
+ APP
+ end
+
+ def test_stays_unscoped_with_or_without_params
+ get "/home"
+ assert_equal "/with_param/bar | /without_param", response.body
+ end
+
+ def test_preserves_scope_with_or_without_params
+ get "/es/home"
+ assert_equal "/es/with_param/bar | /es/without_param", response.body
+ end
+end
+
class TestPathParameters < ActionDispatch::IntegrationTest
Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
app.draw do
@@ -5143,7 +5182,6 @@ class TestRecognizePath < ActionDispatch::IntegrationTest
end
private
-
def recognize_path(*args)
Routes.recognize_path(*args)
end
diff --git a/actionpack/test/dispatch/session/cookie_store_test.rb b/actionpack/test/dispatch/session/cookie_store_test.rb
index e34426a471..b6f83f4062 100644
--- a/actionpack/test/dispatch/session/cookie_store_test.rb
+++ b/actionpack/test/dispatch/session/cookie_store_test.rb
@@ -379,7 +379,6 @@ class CookieStoreTest < ActionDispatch::IntegrationTest
end
private
-
# Overwrite get to send SessionSecret in env hash
def get(path, *args)
args[0] ||= {}
diff --git a/actionpack/test/dispatch/static_test.rb b/actionpack/test/dispatch/static_test.rb
index d44aa00122..1f93d594a6 100644
--- a/actionpack/test/dispatch/static_test.rb
+++ b/actionpack/test/dispatch/static_test.rb
@@ -232,7 +232,6 @@ module StaticTests
end
private
-
def assert_gzip(file_name, response)
expected = File.read("#{FIXTURE_LOAD_PATH}/#{public_path}" + file_name)
actual = ActiveSupport::Gzip.decompress(response.body)
diff --git a/actionpack/test/dispatch/system_testing/driver_test.rb b/actionpack/test/dispatch/system_testing/driver_test.rb
index 0d08f17af3..d3b16d0328 100644
--- a/actionpack/test/dispatch/system_testing/driver_test.rb
+++ b/actionpack/test/dispatch/system_testing/driver_test.rb
@@ -66,7 +66,7 @@ class DriverTest < ActiveSupport::TestCase
end
driver.use
- expected = { args: ["start-maximized"], mobileEmulation: { deviceName: "iphone 6" }, prefs: { detach: true } }
+ expected = { "goog:chromeOptions" => { args: ["start-maximized"], mobileEmulation: { deviceName: "iphone 6" }, prefs: { detach: true } } }
assert_equal expected, driver_option.as_json
end
@@ -81,7 +81,7 @@ class DriverTest < ActiveSupport::TestCase
end
driver.use
- expected = { args: ["start-maximized"], mobileEmulation: { deviceName: "iphone 6" }, prefs: { detach: true } }
+ expected = { "goog:chromeOptions" => { args: ["start-maximized"], mobileEmulation: { deviceName: "iphone 6" }, prefs: { detach: true } } }
assert_equal expected, driver_option.as_json
end
@@ -120,4 +120,17 @@ class DriverTest < ActiveSupport::TestCase
driver.use
end
end
+
+ test "preloads browser's driver_path" do
+ called = false
+
+ original_driver_path = ::Selenium::WebDriver::Chrome::Service.driver_path
+ ::Selenium::WebDriver::Chrome::Service.driver_path = -> { called = true }
+
+ ActionDispatch::SystemTesting::Driver.new(:selenium, screen_size: [1400, 1400], using: :chrome)
+
+ assert called
+ ensure
+ ::Selenium::WebDriver::Chrome::Service.driver_path = original_driver_path
+ end
end
diff --git a/actionpack/test/dispatch/system_testing/system_test_case_test.rb b/actionpack/test/dispatch/system_testing/system_test_case_test.rb
index 847b09dcfe..d235f7ad89 100644
--- a/actionpack/test/dispatch/system_testing/system_test_case_test.rb
+++ b/actionpack/test/dispatch/system_testing/system_test_case_test.rb
@@ -36,50 +36,11 @@ class SetDriverToSeleniumHeadlessFirefoxTest < DrivenBySeleniumWithHeadlessFiref
end
class SetHostTest < DrivenByRackTest
- test "sets default host" do
- assert_equal "http://127.0.0.1", Capybara.app_host
- end
-
test "overrides host" do
- host! "http://example.com"
-
- assert_equal "http://example.com", Capybara.app_host
- end
-end
-
-class UndefMethodsTest < DrivenBySeleniumWithChrome
- test "get" do
- exception = assert_raise NoMethodError do
- get "http://example.com"
+ assert_deprecated do
+ host! "http://example.com"
end
- assert_equal "System tests cannot make direct requests via #get; use #visit and #click_on instead. See http://www.rubydoc.info/github/teamcapybara/capybara/master#The_DSL for more information.", exception.message
- end
- test "post" do
- exception = assert_raise NoMethodError do
- post "http://example.com"
- end
- assert_equal "System tests cannot make direct requests via #post; use #visit and #click_on instead. See http://www.rubydoc.info/github/teamcapybara/capybara/master#The_DSL for more information.", exception.message
- end
-
- test "put" do
- exception = assert_raise NoMethodError do
- put "http://example.com"
- end
- assert_equal "System tests cannot make direct requests via #put; use #visit and #click_on instead. See http://www.rubydoc.info/github/teamcapybara/capybara/master#The_DSL for more information.", exception.message
- end
-
- test "patch" do
- exception = assert_raise NoMethodError do
- patch "http://example.com"
- end
- assert_equal "System tests cannot make direct requests via #patch; use #visit and #click_on instead. See http://www.rubydoc.info/github/teamcapybara/capybara/master#The_DSL for more information.", exception.message
- end
-
- test "delete" do
- exception = assert_raise NoMethodError do
- delete "http://example.com"
- end
- assert_equal "System tests cannot make direct requests via #delete; use #visit and #click_on instead. See http://www.rubydoc.info/github/teamcapybara/capybara/master#The_DSL for more information.", exception.message
+ assert_equal "http://example.com", Capybara.app_host
end
end
diff --git a/actionpack/test/journey/route/definition/scanner_test.rb b/actionpack/test/journey/route/definition/scanner_test.rb
index 092177d315..e55ed92cc8 100644
--- a/actionpack/test/journey/route/definition/scanner_test.rb
+++ b/actionpack/test/journey/route/definition/scanner_test.rb
@@ -66,7 +66,6 @@ module ActionDispatch
end
private
-
def assert_tokens(expected_tokens, scanner, pattern)
actual_tokens = []
while token = scanner.next_token
diff --git a/actionpack/test/journey/route_test.rb b/actionpack/test/journey/route_test.rb
index a8bf4a11e2..8828201e4f 100644
--- a/actionpack/test/journey/route_test.rb
+++ b/actionpack/test/journey/route_test.rb
@@ -9,7 +9,7 @@ module ActionDispatch
app = Object.new
path = Path::Pattern.from_string "/:controller(/:action(/:id(.:format)))"
defaults = {}
- route = Route.build("name", app, path, {}, [], defaults)
+ route = Route.new(name: "name", app: app, path: path, defaults: defaults)
assert_equal app, route.app
assert_equal path, route.path
@@ -17,10 +17,9 @@ module ActionDispatch
end
def test_route_adds_itself_as_memo
- app = Object.new
- path = Path::Pattern.from_string "/:controller(/:action(/:id(.:format)))"
- defaults = {}
- route = Route.build("name", app, path, {}, [], defaults)
+ app = Object.new
+ path = Path::Pattern.from_string "/:controller(/:action(/:id(.:format)))"
+ route = Route.new(name: "name", app: app, path: path)
route.ast.grep(Nodes::Terminal).each do |node|
assert_equal route, node.memo
@@ -28,30 +27,30 @@ module ActionDispatch
end
def test_path_requirements_override_defaults
- path = Path::Pattern.build(":name", { name: /love/ }, "/", true)
- defaults = { name: "tender" }
- route = Route.build("name", nil, path, {}, [], defaults)
+ path = Path::Pattern.build(":name", { name: /love/ }, "/", true)
+ defaults = { name: "tender" }
+ route = Route.new(name: "name", path: path, defaults: defaults)
assert_equal(/love/, route.requirements[:name])
end
def test_ip_address
path = Path::Pattern.from_string "/messages/:id(.:format)"
- route = Route.build("name", nil, path, { ip: "192.168.1.1" }, [],
- controller: "foo", action: "bar")
+ route = Route.new(name: "name", path: path, constraints: { ip: "192.168.1.1" },
+ defaults: { controller: "foo", action: "bar" })
assert_equal "192.168.1.1", route.ip
end
def test_default_ip
path = Path::Pattern.from_string "/messages/:id(.:format)"
- route = Route.build("name", nil, path, {}, [],
- controller: "foo", action: "bar")
+ route = Route.new(name: "name", path: path,
+ defaults: { controller: "foo", action: "bar" })
assert_equal(//, route.ip)
end
def test_format_with_star
path = Path::Pattern.from_string "/:controller/*extra"
- route = Route.build("name", nil, path, {}, [],
- controller: "foo", action: "bar")
+ route = Route.new(name: "name", path: path,
+ defaults: { controller: "foo", action: "bar" })
assert_equal "/foo/himom", route.format(
controller: "foo",
extra: "himom")
@@ -59,7 +58,8 @@ module ActionDispatch
def test_connects_all_match
path = Path::Pattern.from_string "/:controller(/:action(/:id(.:format)))"
- route = Route.build("name", nil, path, { action: "bar" }, [], controller: "foo")
+ route = Route.new(name: "name", path: path, constraints: { action: "bar" },
+ defaults: { controller: "foo" })
assert_equal "/foo/bar/10", route.format(
controller: "foo",
@@ -69,34 +69,33 @@ module ActionDispatch
def test_extras_are_not_included_if_optional
path = Path::Pattern.from_string "/page/:id(/:action)"
- route = Route.build("name", nil, path, {}, [], action: "show")
+ route = Route.new(name: "name", path: path, defaults: { action: "show" })
assert_equal "/page/10", route.format(id: 10)
end
def test_extras_are_not_included_if_optional_with_parameter
path = Path::Pattern.from_string "(/sections/:section)/pages/:id"
- route = Route.build("name", nil, path, {}, [], action: "show")
+ route = Route.new(name: "name", path: path, defaults: { action: "show" })
assert_equal "/pages/10", route.format(id: 10)
end
def test_extras_are_not_included_if_optional_parameter_is_nil
path = Path::Pattern.from_string "(/sections/:section)/pages/:id"
- route = Route.build("name", nil, path, {}, [], action: "show")
+ route = Route.new(name: "name", path: path, defaults: { action: "show" })
assert_equal "/pages/10", route.format(id: 10, section: nil)
end
def test_score
- constraints = {}
defaults = { controller: "pages", action: "show" }
path = Path::Pattern.from_string "/page/:id(/:action)(.:format)"
- specific = Route.build "name", nil, path, constraints, [:controller, :action], defaults
+ specific = Route.new name: "name", path: path, required_defaults: [:controller, :action], defaults: defaults
path = Path::Pattern.from_string "/:controller(/:action(/:id))(.:format)"
- generic = Route.build "name", nil, path, constraints, [], {}
+ generic = Route.new name: "name", path: path
knowledge = { "id" => true, "controller" => true, "action" => true }
diff --git a/actionpack/test/journey/router_test.rb b/actionpack/test/journey/router_test.rb
index f8d89def6a..fe0e3a975b 100644
--- a/actionpack/test/journey/router_test.rb
+++ b/actionpack/test/journey/router_test.rb
@@ -503,7 +503,6 @@ module ActionDispatch
end
private
-
def get(*args)
ActiveSupport::Deprecation.silence do
mapper.get(*args)
diff --git a/actiontext/.gitignore b/actiontext/.gitignore
index 739e00a2cb..9a67d93d26 100644
--- a/actiontext/.gitignore
+++ b/actiontext/.gitignore
@@ -1,5 +1,6 @@
/test/dummy/db/*.sqlite3
/test/dummy/db/*.sqlite3-journal
/test/dummy/log/*.log
+/test/dummy/public/packs-test
/test/dummy/tmp/
/tmp/
diff --git a/actiontext/CHANGELOG.md b/actiontext/CHANGELOG.md
index b165f8b323..d28799279f 100644
--- a/actiontext/CHANGELOG.md
+++ b/actiontext/CHANGELOG.md
@@ -1,3 +1,21 @@
+* The `fill_in_rich_text_area` system test helper locates a Trix editor and fills it in with the given HTML:
+
+ ```ruby
+ # <trix-editor id="message_content" ...></trix-editor>
+ fill_in_rich_text_area "message_content", with: "Hello <em>world!</em>"
+
+ # <trix-editor placeholder="Your message here" ...></trix-editor>
+ fill_in_rich_text_area "Your message here", with: "Hello <em>world!</em>"
+
+ # <trix-editor aria-label="Message content" ...></trix-editor>
+ fill_in_rich_text_area "Message content", with: "Hello <em>world!</em>"
+
+ # <input id="trix_input_1" name="message[content]" type="hidden">
+ # <trix-editor input="trix_input_1"></trix-editor>
+ fill_in_rich_text_area "message[content]", with: "Hello <em>world!</em>"
+ ```
+
+ *George Claghorn*
Please check [6-0-stable](https://github.com/rails/rails/blob/6-0-stable/actiontext/CHANGELOG.md) for previous changes.
diff --git a/actiontext/Rakefile b/actiontext/Rakefile
index 36aed17282..a759a22190 100644
--- a/actiontext/Rakefile
+++ b/actiontext/Rakefile
@@ -8,7 +8,13 @@ task :package
Rake::TestTask.new do |t|
t.libs << "test"
- t.pattern = "test/**/*_test.rb"
+ t.test_files = FileList["test/**/*_test.rb"].exclude("test/system/**/*", "test/dummy/**/*")
+ t.verbose = true
+end
+
+Rake::TestTask.new "test:system" do |t|
+ t.libs << "test"
+ t.test_files = FileList["test/system/**/*_test.rb"]
t.verbose = true
end
diff --git a/actiontext/app/models/action_text/rich_text.rb b/actiontext/app/models/action_text/rich_text.rb
index 19fa3e030e..1a3ffdfa27 100644
--- a/actiontext/app/models/action_text/rich_text.rb
+++ b/actiontext/app/models/action_text/rich_text.rb
@@ -15,7 +15,7 @@ module ActionText
has_many_attached :embeds
before_save do
- self.embeds = body.attachables.grep(ActiveStorage::Blob) if body.present?
+ self.embeds = body.attachables.grep(ActiveStorage::Blob).uniq if body.present?
end
def to_plain_text
diff --git a/actiontext/lib/action_text/engine.rb b/actiontext/lib/action_text/engine.rb
index 51ff5b575b..0f55d460a1 100644
--- a/actiontext/lib/action_text/engine.rb
+++ b/actiontext/lib/action_text/engine.rb
@@ -25,6 +25,10 @@ module ActionText
def previewable_attachable?
representable?
end
+
+ def attachable_plain_text_representation(caption = nil)
+ "[#{caption || filename}]"
+ end
end
end
@@ -46,5 +50,12 @@ module ActionText
before_action { ActionText::Content.renderer = ApplicationController.renderer.new(request.env) }
end
end
+
+ initializer "action_text.system_test_helper" do
+ ActiveSupport.on_load(:action_dispatch_system_test_case) do
+ require "action_text/system_test_helper"
+ include ActionText::SystemTestHelper
+ end
+ end
end
end
diff --git a/actiontext/lib/action_text/system_test_helper.rb b/actiontext/lib/action_text/system_test_helper.rb
new file mode 100644
index 0000000000..77fc9eb50b
--- /dev/null
+++ b/actiontext/lib/action_text/system_test_helper.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+module ActionText
+ module SystemTestHelper
+ # Locates a Trix editor and fills it in with the given HTML.
+ #
+ # The editor can be found by:
+ # * its +id+
+ # * its +placeholder+
+ # * its +aria-label+
+ # * the +name+ of its input
+ #
+ # Examples:
+ #
+ # # <trix-editor id="message_content" ...></trix-editor>
+ # fill_in_rich_text_area "message_content", with: "Hello <em>world!</em>"
+ #
+ # # <trix-editor placeholder="Your message here" ...></trix-editor>
+ # fill_in_rich_text_area "Your message here", with: "Hello <em>world!</em>"
+ #
+ # # <trix-editor aria-label="Message content" ...></trix-editor>
+ # fill_in_rich_text_area "Message content", with: "Hello <em>world!</em>"
+ #
+ # # <input id="trix_input_1" name="message[content]" type="hidden">
+ # # <trix-editor input="trix_input_1"></trix-editor>
+ # fill_in_rich_text_area "message[content]", with: "Hello <em>world!</em>"
+ def fill_in_rich_text_area(locator = nil, with:)
+ find(:rich_text_area, locator).execute_script("this.editor.loadHTML(arguments[0])", with.to_s)
+ end
+ end
+end
+
+Capybara.add_selector :rich_text_area do
+ label "rich-text area"
+ xpath do |locator|
+ if locator.nil?
+ XPath.descendant(:"trix-editor")
+ else
+ input_located_by_name = XPath.anywhere(:input).where(XPath.attr(:name) == locator).attr(:id)
+
+ XPath.descendant(:"trix-editor").where \
+ XPath.attr(:id).equals(locator) |
+ XPath.attr(:placeholder).equals(locator) |
+ XPath.attr(:"aria-label").equals(locator) |
+ XPath.attr(:input).equals(input_located_by_name)
+ end
+ end
+end
diff --git a/actiontext/test/application_system_test_case.rb b/actiontext/test/application_system_test_case.rb
new file mode 100644
index 0000000000..a24f473598
--- /dev/null
+++ b/actiontext/test/application_system_test_case.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require "test_helper"
+
+class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
+ driven_by :selenium, using: :headless_chrome
+end
+
+Capybara.server = :puma, { Silent: true }
diff --git a/actiontext/test/dummy/.babelrc b/actiontext/test/dummy/.babelrc
deleted file mode 100644
index ded31c0d80..0000000000
--- a/actiontext/test/dummy/.babelrc
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "presets": [
- ["env", {
- "modules": false,
- "targets": {
- "browsers": "> 1%",
- "uglify": true
- },
- "useBuiltIns": true
- }]
- ],
-
- "plugins": [
- "syntax-dynamic-import",
- "transform-object-rest-spread",
- ["transform-class-properties", { "spec": true }]
- ]
-}
diff --git a/actiontext/test/dummy/.browserslistrc b/actiontext/test/dummy/.browserslistrc
new file mode 100644
index 0000000000..e94f8140cc
--- /dev/null
+++ b/actiontext/test/dummy/.browserslistrc
@@ -0,0 +1 @@
+defaults
diff --git a/actiontext/test/dummy/app/javascript/packs/application.js b/actiontext/test/dummy/app/javascript/packs/application.js
index 13ac17ed58..091bb5839e 100644
--- a/actiontext/test/dummy/app/javascript/packs/application.js
+++ b/actiontext/test/dummy/app/javascript/packs/application.js
@@ -1 +1,2 @@
+import "trix"
import "@rails/actiontext"
diff --git a/actiontext/test/dummy/app/views/messages/_form.html.erb b/actiontext/test/dummy/app/views/messages/_form.html.erb
index 3b8a174884..cbaf675fff 100644
--- a/actiontext/test/dummy/app/views/messages/_form.html.erb
+++ b/actiontext/test/dummy/app/views/messages/_form.html.erb
@@ -18,7 +18,8 @@
<div class="field">
<%= form.label :content %>
- <%= form.rich_text_area :content, class: "trix-content" %>
+ <%= form.rich_text_area :content, class: "trix-content",
+ placeholder: "Your message here", aria: { label: "Message content" } %>
</div>
<div class="actions">
diff --git a/actiontext/test/dummy/babel.config.js b/actiontext/test/dummy/babel.config.js
new file mode 100644
index 0000000000..f930f3e0a0
--- /dev/null
+++ b/actiontext/test/dummy/babel.config.js
@@ -0,0 +1,70 @@
+module.exports = function(api) {
+ var validEnv = ['development', 'test', 'production']
+ var currentEnv = api.env()
+ var isDevelopmentEnv = api.env('development')
+ var isProductionEnv = api.env('production')
+ var isTestEnv = api.env('test')
+
+ if (!validEnv.includes(currentEnv)) {
+ throw new Error(
+ 'Please specify a valid `NODE_ENV` or ' +
+ '`BABEL_ENV` environment variables. Valid values are "development", ' +
+ '"test", and "production". Instead, received: ' +
+ JSON.stringify(currentEnv) +
+ '.'
+ )
+ }
+
+ return {
+ presets: [
+ isTestEnv && [
+ require('@babel/preset-env').default,
+ {
+ targets: {
+ node: 'current'
+ }
+ }
+ ],
+ (isProductionEnv || isDevelopmentEnv) && [
+ require('@babel/preset-env').default,
+ {
+ forceAllTransforms: true,
+ useBuiltIns: 'entry',
+ modules: false,
+ exclude: ['transform-typeof-symbol']
+ }
+ ]
+ ].filter(Boolean),
+ plugins: [
+ require('babel-plugin-macros'),
+ require('@babel/plugin-syntax-dynamic-import').default,
+ isTestEnv && require('babel-plugin-dynamic-import-node'),
+ require('@babel/plugin-transform-destructuring').default,
+ [
+ require('@babel/plugin-proposal-class-properties').default,
+ {
+ loose: true
+ }
+ ],
+ [
+ require('@babel/plugin-proposal-object-rest-spread').default,
+ {
+ useBuiltIns: true
+ }
+ ],
+ [
+ require('@babel/plugin-transform-runtime').default,
+ {
+ helpers: false,
+ regenerator: true
+ }
+ ],
+ [
+ require('@babel/plugin-transform-regenerator').default,
+ {
+ async: false
+ }
+ ]
+ ].filter(Boolean)
+ }
+}
diff --git a/actiontext/test/dummy/bin/bundle b/actiontext/test/dummy/bin/bundle
index f19acf5b5c..0962d6a66f 100755
--- a/actiontext/test/dummy/bin/bundle
+++ b/actiontext/test/dummy/bin/bundle
@@ -1,3 +1,3 @@
#!/usr/bin/env ruby
-ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __dir__)
load Gem.bin_path('bundler', 'bundle')
diff --git a/actiontext/test/dummy/bin/webpack b/actiontext/test/dummy/bin/webpack
new file mode 100755
index 0000000000..008ecb22f7
--- /dev/null
+++ b/actiontext/test/dummy/bin/webpack
@@ -0,0 +1,19 @@
+#!/usr/bin/env ruby
+
+ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
+ENV["NODE_ENV"] ||= "development"
+
+require "pathname"
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
+ Pathname.new(__FILE__).realpath)
+
+require "rubygems"
+require "bundler/setup"
+
+require "webpacker"
+require "webpacker/webpack_runner"
+
+APP_ROOT = File.expand_path("..", __dir__)
+Dir.chdir(APP_ROOT) do
+ Webpacker::WebpackRunner.run(ARGV)
+end
diff --git a/actiontext/test/dummy/bin/webpack-dev-server b/actiontext/test/dummy/bin/webpack-dev-server
new file mode 100755
index 0000000000..a931a9b7fc
--- /dev/null
+++ b/actiontext/test/dummy/bin/webpack-dev-server
@@ -0,0 +1,19 @@
+#!/usr/bin/env ruby
+
+ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
+ENV["NODE_ENV"] ||= "development"
+
+require "pathname"
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
+ Pathname.new(__FILE__).realpath)
+
+require "rubygems"
+require "bundler/setup"
+
+require "webpacker"
+require "webpacker/dev_server_runner"
+
+APP_ROOT = File.expand_path("..", __dir__)
+Dir.chdir(APP_ROOT) do
+ Webpacker::DevServerRunner.run(ARGV)
+end
diff --git a/actiontext/test/dummy/config/webpack/development.js b/actiontext/test/dummy/config/webpack/development.js
index 81269f6513..c5edff94ad 100644
--- a/actiontext/test/dummy/config/webpack/development.js
+++ b/actiontext/test/dummy/config/webpack/development.js
@@ -1,3 +1,5 @@
+process.env.NODE_ENV = process.env.NODE_ENV || 'development'
+
const environment = require('./environment')
module.exports = environment.toWebpackConfig()
diff --git a/actiontext/test/dummy/config/webpack/production.js b/actiontext/test/dummy/config/webpack/production.js
index 81269f6513..be0f53aacf 100644
--- a/actiontext/test/dummy/config/webpack/production.js
+++ b/actiontext/test/dummy/config/webpack/production.js
@@ -1,3 +1,5 @@
+process.env.NODE_ENV = process.env.NODE_ENV || 'production'
+
const environment = require('./environment')
module.exports = environment.toWebpackConfig()
diff --git a/actiontext/test/dummy/config/webpack/test.js b/actiontext/test/dummy/config/webpack/test.js
index 81269f6513..c5edff94ad 100644
--- a/actiontext/test/dummy/config/webpack/test.js
+++ b/actiontext/test/dummy/config/webpack/test.js
@@ -1,3 +1,5 @@
+process.env.NODE_ENV = process.env.NODE_ENV || 'development'
+
const environment = require('./environment')
module.exports = environment.toWebpackConfig()
diff --git a/actiontext/test/dummy/config/webpacker.yml b/actiontext/test/dummy/config/webpacker.yml
index d3f24e1b4b..6fd531213f 100644
--- a/actiontext/test/dummy/config/webpacker.yml
+++ b/actiontext/test/dummy/config/webpacker.yml
@@ -3,8 +3,11 @@
default: &default
source_path: app/javascript
source_entry_path: packs
+ public_root_path: public
public_output_path: packs
cache_path: tmp/cache/webpacker
+ check_yarn_integrity: false
+ webpack_compile_output: false
# Additional paths webpack should lookup modules
# ['app/assets', 'engine/foo/app/assets']
@@ -13,11 +16,32 @@ default: &default
# Reload manifest.json on all requests so we reload latest compiled packs
cache_manifest: false
+ # Extract and emit a css file
+ extract_css: false
+
+ static_assets_extensions:
+ - .jpg
+ - .jpeg
+ - .png
+ - .gif
+ - .tiff
+ - .ico
+ - .svg
+ - .eot
+ - .otf
+ - .ttf
+ - .woff
+ - .woff2
+
extensions:
+ - .mjs
- .js
- .sass
- .scss
- .css
+ - .module.sass
+ - .module.scss
+ - .module.css
- .png
- .svg
- .gif
@@ -28,6 +52,9 @@ development:
<<: *default
compile: true
+ # Verifies that versions and hashed value of the package contents in the project's package.json
+ check_yarn_integrity: true
+
# Reference: https://webpack.js.org/configuration/dev-server/
dev_server:
https: false
@@ -45,7 +72,7 @@ development:
headers:
'Access-Control-Allow-Origin': '*'
watch_options:
- ignored: /node_modules/
+ ignored: '**/node_modules/**'
test:
@@ -61,5 +88,8 @@ production:
# Production depends on precompilation of packs prior to booting for performance.
compile: false
+ # Extract and emit a css file
+ extract_css: true
+
# Cache manifest.json for performance
cache_manifest: true
diff --git a/actiontext/test/dummy/package.json b/actiontext/test/dummy/package.json
index 177a97c1e6..cb3bbbddf2 100644
--- a/actiontext/test/dummy/package.json
+++ b/actiontext/test/dummy/package.json
@@ -3,9 +3,10 @@
"private": true,
"dependencies": {
"@rails/webpacker": "^4.0.2",
- "actiontext": "file:../.."
+ "actiontext": "file:../..",
+ "trix": "^1.1.1"
},
"devDependencies": {
- "webpack-dev-server": "^3.2.1"
+ "webpack-dev-server": "^3.3.1"
}
}
diff --git a/actiontext/test/dummy/postcss.config.js b/actiontext/test/dummy/postcss.config.js
new file mode 100644
index 0000000000..aa5998a809
--- /dev/null
+++ b/actiontext/test/dummy/postcss.config.js
@@ -0,0 +1,12 @@
+module.exports = {
+ plugins: [
+ require('postcss-import'),
+ require('postcss-flexbugs-fixes'),
+ require('postcss-preset-env')({
+ autoprefixer: {
+ flexbox: 'no-2009'
+ },
+ stage: 3
+ })
+ ]
+}
diff --git a/actiontext/test/dummy/yarn.lock b/actiontext/test/dummy/yarn.lock
index 6cd01debdc..891f6e7856 100644
--- a/actiontext/test/dummy/yarn.lock
+++ b/actiontext/test/dummy/yarn.lock
@@ -10,17 +10,17 @@
"@babel/highlight" "^7.0.0"
"@babel/core@^7.3.4":
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.3.4.tgz#921a5a13746c21e32445bf0798680e9d11a6530b"
- integrity sha512-jRsuseXBo9pN197KnDwhhaaBzyZr2oIcLHHTt2oDdQrej5Qp57dCCJafWx5ivU8/alEYDpssYqv1MUqcxwQlrA==
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.4.4.tgz#84055750b05fcd50f9915a826b44fa347a825250"
+ integrity sha512-lQgGX3FPRgbz2SKmhMtYgJvVzGZrmjaF4apZ2bLwofAKiSjxU0drPh4S/VasyYXwaTs+A1gvQ45BN8SQJzHsQQ==
dependencies:
"@babel/code-frame" "^7.0.0"
- "@babel/generator" "^7.3.4"
- "@babel/helpers" "^7.2.0"
- "@babel/parser" "^7.3.4"
- "@babel/template" "^7.2.2"
- "@babel/traverse" "^7.3.4"
- "@babel/types" "^7.3.4"
+ "@babel/generator" "^7.4.4"
+ "@babel/helpers" "^7.4.4"
+ "@babel/parser" "^7.4.4"
+ "@babel/template" "^7.4.4"
+ "@babel/traverse" "^7.4.4"
+ "@babel/types" "^7.4.4"
convert-source-map "^1.1.0"
debug "^4.1.0"
json5 "^2.1.0"
@@ -29,12 +29,12 @@
semver "^5.4.1"
source-map "^0.5.0"
-"@babel/generator@^7.3.4":
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.4.tgz#9aa48c1989257877a9d971296e5b73bfe72e446e"
- integrity sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg==
+"@babel/generator@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.4.4.tgz#174a215eb843fc392c7edcaabeaa873de6e8f041"
+ integrity sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ==
dependencies:
- "@babel/types" "^7.3.4"
+ "@babel/types" "^7.4.4"
jsesc "^2.5.1"
lodash "^4.17.11"
source-map "^0.5.0"
@@ -55,35 +55,35 @@
"@babel/helper-explode-assignable-expression" "^7.1.0"
"@babel/types" "^7.0.0"
-"@babel/helper-call-delegate@^7.1.0":
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.1.0.tgz#6a957f105f37755e8645343d3038a22e1449cc4a"
- integrity sha512-YEtYZrw3GUK6emQHKthltKNZwszBcHK58Ygcis+gVUrF4/FmTVr5CCqQNSfmvg2y+YDEANyYoaLz/SHsnusCwQ==
+"@babel/helper-call-delegate@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz#87c1f8ca19ad552a736a7a27b1c1fcf8b1ff1f43"
+ integrity sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ==
dependencies:
- "@babel/helper-hoist-variables" "^7.0.0"
- "@babel/traverse" "^7.1.0"
- "@babel/types" "^7.0.0"
+ "@babel/helper-hoist-variables" "^7.4.4"
+ "@babel/traverse" "^7.4.4"
+ "@babel/types" "^7.4.4"
-"@babel/helper-create-class-features-plugin@^7.3.4":
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.3.4.tgz#092711a7a3ad8ea34de3e541644c2ce6af1f6f0c"
- integrity sha512-uFpzw6L2omjibjxa8VGZsJUPL5wJH0zzGKpoz0ccBkzIa6C8kWNUbiBmQ0rgOKWlHJ6qzmfa6lTiGchiV8SC+g==
+"@babel/helper-create-class-features-plugin@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.4.4.tgz#fc3d690af6554cc9efc607364a82d48f58736dba"
+ integrity sha512-UbBHIa2qeAGgyiNR9RszVF7bUHEdgS4JAUNT8SiqrAN6YJVxlOxeLr5pBzb5kan302dejJ9nla4RyKcR1XT6XA==
dependencies:
"@babel/helper-function-name" "^7.1.0"
"@babel/helper-member-expression-to-functions" "^7.0.0"
"@babel/helper-optimise-call-expression" "^7.0.0"
"@babel/helper-plugin-utils" "^7.0.0"
- "@babel/helper-replace-supers" "^7.3.4"
- "@babel/helper-split-export-declaration" "^7.0.0"
+ "@babel/helper-replace-supers" "^7.4.4"
+ "@babel/helper-split-export-declaration" "^7.4.4"
-"@babel/helper-define-map@^7.1.0":
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.1.0.tgz#3b74caec329b3c80c116290887c0dd9ae468c20c"
- integrity sha512-yPPcW8dc3gZLN+U1mhYV91QU3n5uTbx7DUdf8NnPbjS0RMwBuHi9Xt2MUgppmNz7CJxTBWsGczTiEp1CSOTPRg==
+"@babel/helper-define-map@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.4.4.tgz#6969d1f570b46bdc900d1eba8e5d59c48ba2c12a"
+ integrity sha512-IX3Ln8gLhZpSuqHJSnTNBWGDE9kdkTEWl21A/K7PQ00tseBwbqCHTvNLHSBd9M0R5rER4h5Rsvj9vw0R5SieBg==
dependencies:
"@babel/helper-function-name" "^7.1.0"
- "@babel/types" "^7.0.0"
- lodash "^4.17.10"
+ "@babel/types" "^7.4.4"
+ lodash "^4.17.11"
"@babel/helper-explode-assignable-expression@^7.1.0":
version "7.1.0"
@@ -109,12 +109,12 @@
dependencies:
"@babel/types" "^7.0.0"
-"@babel/helper-hoist-variables@^7.0.0":
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.0.0.tgz#46adc4c5e758645ae7a45deb92bab0918c23bb88"
- integrity sha512-Ggv5sldXUeSKsuzLkddtyhyHe2YantsxWKNi7A+7LeD12ExRDWTRk29JCXpaHPAbMaIPZSil7n+lq78WY2VY7w==
+"@babel/helper-hoist-variables@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz#0298b5f25c8c09c53102d52ac4a98f773eb2850a"
+ integrity sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w==
dependencies:
- "@babel/types" "^7.0.0"
+ "@babel/types" "^7.4.4"
"@babel/helper-member-expression-to-functions@^7.0.0":
version "7.0.0"
@@ -130,17 +130,17 @@
dependencies:
"@babel/types" "^7.0.0"
-"@babel/helper-module-transforms@^7.1.0":
- version "7.2.2"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.2.2.tgz#ab2f8e8d231409f8370c883d20c335190284b963"
- integrity sha512-YRD7I6Wsv+IHuTPkAmAS4HhY0dkPobgLftHp0cRGZSdrRvmZY8rFvae/GVu3bD00qscuvK3WPHB3YdNpBXUqrA==
+"@babel/helper-module-transforms@^7.1.0", "@babel/helper-module-transforms@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.4.4.tgz#96115ea42a2f139e619e98ed46df6019b94414b8"
+ integrity sha512-3Z1yp8TVQf+B4ynN7WoHPKS8EkdTbgAEy0nU0rs/1Kw4pDgmvYH3rz3aI11KgxKCba2cn7N+tqzV1mY2HMN96w==
dependencies:
"@babel/helper-module-imports" "^7.0.0"
"@babel/helper-simple-access" "^7.1.0"
- "@babel/helper-split-export-declaration" "^7.0.0"
- "@babel/template" "^7.2.2"
- "@babel/types" "^7.2.2"
- lodash "^4.17.10"
+ "@babel/helper-split-export-declaration" "^7.4.4"
+ "@babel/template" "^7.4.4"
+ "@babel/types" "^7.4.4"
+ lodash "^4.17.11"
"@babel/helper-optimise-call-expression@^7.0.0":
version "7.0.0"
@@ -154,12 +154,12 @@
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250"
integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==
-"@babel/helper-regex@^7.0.0":
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.0.0.tgz#2c1718923b57f9bbe64705ffe5640ac64d9bdb27"
- integrity sha512-TR0/N0NDCcUIUEbqV6dCO+LptmmSQFQ7q70lfcEB4URsjD0E1HzicrwUH+ap6BAQ2jhCX9Q4UqZy4wilujWlkg==
+"@babel/helper-regex@^7.0.0", "@babel/helper-regex@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.4.4.tgz#a47e02bc91fb259d2e6727c2a30013e3ac13c4a2"
+ integrity sha512-Y5nuB/kESmR3tKjU8Nkn1wMGEx1tjJX076HBMeL3XLQCu6vA/YRzuTW0bbb+qRnXvQGn+d6Rx953yffl8vEy7Q==
dependencies:
- lodash "^4.17.10"
+ lodash "^4.17.11"
"@babel/helper-remap-async-to-generator@^7.1.0":
version "7.1.0"
@@ -172,15 +172,15 @@
"@babel/traverse" "^7.1.0"
"@babel/types" "^7.0.0"
-"@babel/helper-replace-supers@^7.1.0", "@babel/helper-replace-supers@^7.3.4":
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.3.4.tgz#a795208e9b911a6eeb08e5891faacf06e7013e13"
- integrity sha512-pvObL9WVf2ADs+ePg0jrqlhHoxRXlOa+SHRHzAXIz2xkYuOHfGl+fKxPMaS4Fq+uje8JQPobnertBBvyrWnQ1A==
+"@babel/helper-replace-supers@^7.1.0", "@babel/helper-replace-supers@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.4.4.tgz#aee41783ebe4f2d3ab3ae775e1cc6f1a90cefa27"
+ integrity sha512-04xGEnd+s01nY1l15EuMS1rfKktNF+1CkKmHoErDppjAAZL+IUBZpzT748x262HF7fibaQPhbvWUl5HeSt1EXg==
dependencies:
"@babel/helper-member-expression-to-functions" "^7.0.0"
"@babel/helper-optimise-call-expression" "^7.0.0"
- "@babel/traverse" "^7.3.4"
- "@babel/types" "^7.3.4"
+ "@babel/traverse" "^7.4.4"
+ "@babel/types" "^7.4.4"
"@babel/helper-simple-access@^7.1.0":
version "7.1.0"
@@ -190,12 +190,12 @@
"@babel/template" "^7.1.0"
"@babel/types" "^7.0.0"
-"@babel/helper-split-export-declaration@^7.0.0":
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz#3aae285c0311c2ab095d997b8c9a94cad547d813"
- integrity sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==
+"@babel/helper-split-export-declaration@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677"
+ integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==
dependencies:
- "@babel/types" "^7.0.0"
+ "@babel/types" "^7.4.4"
"@babel/helper-wrap-function@^7.1.0":
version "7.2.0"
@@ -207,14 +207,14 @@
"@babel/traverse" "^7.1.0"
"@babel/types" "^7.2.0"
-"@babel/helpers@^7.2.0":
- version "7.3.1"
- resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.3.1.tgz#949eec9ea4b45d3210feb7dc1c22db664c9e44b9"
- integrity sha512-Q82R3jKsVpUV99mgX50gOPCWwco9Ec5Iln/8Vyu4osNIOQgSrd9RFrQeUvmvddFNoLwMyOUWU+5ckioEKpDoGA==
+"@babel/helpers@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.4.4.tgz#868b0ef59c1dd4e78744562d5ce1b59c89f2f2a5"
+ integrity sha512-igczbR/0SeuPR8RFfC7tGrbdTbFL3QTvH6D+Z6zNxnTe//GyqmtHmDkzrqDmyZ3eSwPqB/LhyKoU5DXsp+Vp2A==
dependencies:
- "@babel/template" "^7.1.2"
- "@babel/traverse" "^7.1.5"
- "@babel/types" "^7.3.0"
+ "@babel/template" "^7.4.4"
+ "@babel/traverse" "^7.4.4"
+ "@babel/types" "^7.4.4"
"@babel/highlight@^7.0.0":
version "7.0.0"
@@ -225,10 +225,10 @@
esutils "^2.0.2"
js-tokens "^4.0.0"
-"@babel/parser@^7.2.2", "@babel/parser@^7.3.4":
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.4.tgz#a43357e4bbf4b92a437fb9e465c192848287f27c"
- integrity sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==
+"@babel/parser@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.4.4.tgz#5977129431b8fe33471730d255ce8654ae1250b6"
+ integrity sha512-5pCS4mOsL+ANsFZGdvNLybx4wtqAZJ0MJjMHxvzI3bvIsz6sQvzW8XX92EYIkiPtIvcfG3Aj+Ir5VNyjnZhP7w==
"@babel/plugin-proposal-async-generator-functions@^7.2.0":
version "7.2.0"
@@ -240,11 +240,11 @@
"@babel/plugin-syntax-async-generators" "^7.2.0"
"@babel/plugin-proposal-class-properties@^7.3.4":
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.3.4.tgz#410f5173b3dc45939f9ab30ca26684d72901405e"
- integrity sha512-lUf8D3HLs4yYlAo8zjuneLvfxN7qfKv1Yzbj5vjqaqMJxgJA3Ipwp4VUJ+OrOdz53Wbww6ahwB8UhB2HQyLotA==
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.4.4.tgz#93a6486eed86d53452ab9bab35e368e9461198ce"
+ integrity sha512-WjKTI8g8d5w1Bc9zgwSz2nfrsNQsXcCf9J9cdCvrJV6RF56yztwm4TmJC0MgJ9tvwO9gUA/mcYe89bLdGfiXFg==
dependencies:
- "@babel/helper-create-class-features-plugin" "^7.3.4"
+ "@babel/helper-create-class-features-plugin" "^7.4.4"
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/plugin-proposal-json-strings@^7.2.0":
@@ -255,10 +255,10 @@
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/plugin-syntax-json-strings" "^7.2.0"
-"@babel/plugin-proposal-object-rest-spread@^7.3.4":
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.4.tgz#47f73cf7f2a721aad5c0261205405c642e424654"
- integrity sha512-j7VQmbbkA+qrzNqbKHrBsW3ddFnOeva6wzSe/zB7T+xaxGc+RCpwo44wCmRixAIGRoIpmVgvzFzNJqQcO3/9RA==
+"@babel/plugin-proposal-object-rest-spread@^7.3.4", "@babel/plugin-proposal-object-rest-spread@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.4.4.tgz#1ef173fcf24b3e2df92a678f027673b55e7e3005"
+ integrity sha512-dMBG6cSPBbHeEBdFXeQ2QLc5gUpg4Vkaz8octD4aoW/ISO+jBOcsuxYL7bsb5WSu8RLP6boxrBIALEHgoHtO9g==
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/plugin-syntax-object-rest-spread" "^7.2.0"
@@ -271,14 +271,14 @@
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/plugin-syntax-optional-catch-binding" "^7.2.0"
-"@babel/plugin-proposal-unicode-property-regex@^7.2.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.2.0.tgz#abe7281fe46c95ddc143a65e5358647792039520"
- integrity sha512-LvRVYb7kikuOtIoUeWTkOxQEV1kYvL5B6U3iWEGCzPNRus1MzJweFqORTj+0jkxozkTSYNJozPOddxmqdqsRpw==
+"@babel/plugin-proposal-unicode-property-regex@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.4.4.tgz#501ffd9826c0b91da22690720722ac7cb1ca9c78"
+ integrity sha512-j1NwnOqMG9mFUOH58JTFsA/+ZYzQLUZ/drqWUqxCYLGeu2JFZL8YrNC9hBxKmWtAuOCHPcRpgv7fhap09Fb4kA==
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
- "@babel/helper-regex" "^7.0.0"
- regexpu-core "^4.2.0"
+ "@babel/helper-regex" "^7.4.4"
+ regexpu-core "^4.5.4"
"@babel/plugin-syntax-async-generators@^7.2.0":
version "7.2.0"
@@ -322,10 +322,10 @@
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
-"@babel/plugin-transform-async-to-generator@^7.3.4":
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.3.4.tgz#4e45408d3c3da231c0e7b823f407a53a7eb3048c"
- integrity sha512-Y7nCzv2fw/jEZ9f678MuKdMo99MFDJMT/PvD9LisrR5JDFcJH6vYeH6RnjVt3p5tceyGRvTtEN0VOlU+rgHZjA==
+"@babel/plugin-transform-async-to-generator@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.4.4.tgz#a3f1d01f2f21cadab20b33a82133116f14fb5894"
+ integrity sha512-YiqW2Li8TXmzgbXw+STsSqPBPFnGviiaSp6CYOq55X8GQ2SGVLrXB6pNid8HkqkZAzOH6knbai3snhP7v0fNwA==
dependencies:
"@babel/helper-module-imports" "^7.0.0"
"@babel/helper-plugin-utils" "^7.0.0"
@@ -338,26 +338,26 @@
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
-"@babel/plugin-transform-block-scoping@^7.3.4":
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.3.4.tgz#5c22c339de234076eee96c8783b2fed61202c5c4"
- integrity sha512-blRr2O8IOZLAOJklXLV4WhcEzpYafYQKSGT3+R26lWG41u/FODJuBggehtOwilVAcFu393v3OFj+HmaE6tVjhA==
+"@babel/plugin-transform-block-scoping@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.4.4.tgz#c13279fabf6b916661531841a23c4b7dae29646d"
+ integrity sha512-jkTUyWZcTrwxu5DD4rWz6rDB5Cjdmgz6z7M7RLXOJyCUkFBawssDGcGh8M/0FTSB87avyJI1HsTwUXp9nKA1PA==
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
lodash "^4.17.11"
-"@babel/plugin-transform-classes@^7.3.4":
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.3.4.tgz#dc173cb999c6c5297e0b5f2277fdaaec3739d0cc"
- integrity sha512-J9fAvCFBkXEvBimgYxCjvaVDzL6thk0j0dBvCeZmIUDBwyt+nv6HfbImsSrWsYXfDNDivyANgJlFXDUWRTZBuA==
+"@babel/plugin-transform-classes@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.4.4.tgz#0ce4094cdafd709721076d3b9c38ad31ca715eb6"
+ integrity sha512-/e44eFLImEGIpL9qPxSRat13I5QNRgBLu2hOQJCF7VLy/otSM/sypV1+XaIw5+502RX/+6YaSAPmldk+nhHDPw==
dependencies:
"@babel/helper-annotate-as-pure" "^7.0.0"
- "@babel/helper-define-map" "^7.1.0"
+ "@babel/helper-define-map" "^7.4.4"
"@babel/helper-function-name" "^7.1.0"
"@babel/helper-optimise-call-expression" "^7.0.0"
"@babel/helper-plugin-utils" "^7.0.0"
- "@babel/helper-replace-supers" "^7.3.4"
- "@babel/helper-split-export-declaration" "^7.0.0"
+ "@babel/helper-replace-supers" "^7.4.4"
+ "@babel/helper-split-export-declaration" "^7.4.4"
globals "^11.1.0"
"@babel/plugin-transform-computed-properties@^7.2.0":
@@ -367,21 +367,21 @@
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
-"@babel/plugin-transform-destructuring@^7.2.0", "@babel/plugin-transform-destructuring@^7.3.2":
- version "7.3.2"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.3.2.tgz#f2f5520be055ba1c38c41c0e094d8a461dd78f2d"
- integrity sha512-Lrj/u53Ufqxl/sGxyjsJ2XNtNuEjDyjpqdhMNh5aZ+XFOdThL46KBj27Uem4ggoezSYBxKWAil6Hu8HtwqesYw==
+"@babel/plugin-transform-destructuring@^7.3.2", "@babel/plugin-transform-destructuring@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.4.4.tgz#9d964717829cc9e4b601fc82a26a71a4d8faf20f"
+ integrity sha512-/aOx+nW0w8eHiEHm+BTERB2oJn5D127iye/SUQl7NjHy0lf+j7h4MKMMSOwdazGq9OxgiNADncE+SRJkCxjZpQ==
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
-"@babel/plugin-transform-dotall-regex@^7.2.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.2.0.tgz#f0aabb93d120a8ac61e925ea0ba440812dbe0e49"
- integrity sha512-sKxnyHfizweTgKZf7XsXu/CNupKhzijptfTM+bozonIuyVrLWVUvYjE2bhuSBML8VQeMxq4Mm63Q9qvcvUcciQ==
+"@babel/plugin-transform-dotall-regex@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.4.tgz#361a148bc951444312c69446d76ed1ea8e4450c3"
+ integrity sha512-P05YEhRc2h53lZDjRPk/OektxCVevFzZs2Gfjd545Wde3k+yFDbXORgl2e0xpbq8mLcKJ7Idss4fAg0zORN/zg==
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
- "@babel/helper-regex" "^7.0.0"
- regexpu-core "^4.1.3"
+ "@babel/helper-regex" "^7.4.4"
+ regexpu-core "^4.5.4"
"@babel/plugin-transform-duplicate-keys@^7.2.0":
version "7.2.0"
@@ -398,17 +398,17 @@
"@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0"
"@babel/helper-plugin-utils" "^7.0.0"
-"@babel/plugin-transform-for-of@^7.2.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.2.0.tgz#ab7468befa80f764bb03d3cb5eef8cc998e1cad9"
- integrity sha512-Kz7Mt0SsV2tQk6jG5bBv5phVbkd0gd27SgYD4hH1aLMJRchM0dzHaXvrWhVZ+WxAlDoAKZ7Uy3jVTW2mKXQ1WQ==
+"@babel/plugin-transform-for-of@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz#0267fc735e24c808ba173866c6c4d1440fc3c556"
+ integrity sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ==
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
-"@babel/plugin-transform-function-name@^7.2.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.2.0.tgz#f7930362829ff99a3174c39f0afcc024ef59731a"
- integrity sha512-kWgksow9lHdvBC2Z4mxTsvc7YdY7w/V6B2vy9cTIPtLEE9NhwoWivaxdNM/S37elu5bqlLP/qOY906LukO9lkQ==
+"@babel/plugin-transform-function-name@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz#e1436116abb0610c2259094848754ac5230922ad"
+ integrity sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA==
dependencies:
"@babel/helper-function-name" "^7.1.0"
"@babel/helper-plugin-utils" "^7.0.0"
@@ -420,6 +420,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
+"@babel/plugin-transform-member-expression-literals@^7.2.0":
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.2.0.tgz#fa10aa5c58a2cb6afcf2c9ffa8cb4d8b3d489a2d"
+ integrity sha512-HiU3zKkSU6scTidmnFJ0bMX8hz5ixC93b4MHMiYebmk2lUVNGOboPsqQvx5LzooihijUoLR/v7Nc1rbBtnc7FA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.0.0"
+
"@babel/plugin-transform-modules-amd@^7.2.0":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.2.0.tgz#82a9bce45b95441f617a24011dc89d12da7f4ee6"
@@ -428,21 +435,21 @@
"@babel/helper-module-transforms" "^7.1.0"
"@babel/helper-plugin-utils" "^7.0.0"
-"@babel/plugin-transform-modules-commonjs@^7.2.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.2.0.tgz#c4f1933f5991d5145e9cfad1dfd848ea1727f404"
- integrity sha512-V6y0uaUQrQPXUrmj+hgnks8va2L0zcZymeU7TtWEgdRLNkceafKXEduv7QzgQAE4lT+suwooG9dC7LFhdRAbVQ==
+"@babel/plugin-transform-modules-commonjs@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.4.4.tgz#0bef4713d30f1d78c2e59b3d6db40e60192cac1e"
+ integrity sha512-4sfBOJt58sEo9a2BQXnZq+Q3ZTSAUXyK3E30o36BOGnJ+tvJ6YSxF0PG6kERvbeISgProodWuI9UVG3/FMY6iw==
dependencies:
- "@babel/helper-module-transforms" "^7.1.0"
+ "@babel/helper-module-transforms" "^7.4.4"
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/helper-simple-access" "^7.1.0"
-"@babel/plugin-transform-modules-systemjs@^7.3.4":
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.3.4.tgz#813b34cd9acb6ba70a84939f3680be0eb2e58861"
- integrity sha512-VZ4+jlGOF36S7TjKs8g4ojp4MEI+ebCQZdswWb/T9I4X84j8OtFAyjXjt/M16iIm5RIZn0UMQgg/VgIwo/87vw==
+"@babel/plugin-transform-modules-systemjs@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.4.4.tgz#dc83c5665b07d6c2a7b224c00ac63659ea36a405"
+ integrity sha512-MSiModfILQc3/oqnG7NrP1jHaSPryO6tA2kOMmAQApz5dayPxWiHqmq4sWH2xF5LcQK56LlbKByCd8Aah/OIkQ==
dependencies:
- "@babel/helper-hoist-variables" "^7.0.0"
+ "@babel/helper-hoist-variables" "^7.4.4"
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/plugin-transform-modules-umd@^7.2.0":
@@ -453,17 +460,17 @@
"@babel/helper-module-transforms" "^7.1.0"
"@babel/helper-plugin-utils" "^7.0.0"
-"@babel/plugin-transform-named-capturing-groups-regex@^7.3.0":
- version "7.3.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.3.0.tgz#140b52985b2d6ef0cb092ef3b29502b990f9cd50"
- integrity sha512-NxIoNVhk9ZxS+9lSoAQ/LM0V2UEvARLttEHUrRDGKFaAxOYQcrkN/nLRE+BbbicCAvZPl7wMP0X60HsHE5DtQw==
+"@babel/plugin-transform-named-capturing-groups-regex@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.4.4.tgz#5611d96d987dfc4a3a81c4383bb173361037d68d"
+ integrity sha512-Ki+Y9nXBlKfhD+LXaRS7v95TtTGYRAf9Y1rTDiE75zf8YQz4GDaWRXosMfJBXxnk88mGFjWdCRIeqDbon7spYA==
dependencies:
regexp-tree "^0.1.0"
-"@babel/plugin-transform-new-target@^7.0.0":
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0.tgz#ae8fbd89517fa7892d20e6564e641e8770c3aa4a"
- integrity sha512-yin069FYjah+LbqfGeTfzIBODex/e++Yfa0rH0fpfam9uTbuEeEOx5GLGr210ggOV77mVRNoeqSYqeuaqSzVSw==
+"@babel/plugin-transform-new-target@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz#18d120438b0cc9ee95a47f2c72bc9768fbed60a5"
+ integrity sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA==
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
@@ -475,26 +482,40 @@
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/helper-replace-supers" "^7.1.0"
-"@babel/plugin-transform-parameters@^7.2.0":
- version "7.3.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.3.3.tgz#3a873e07114e1a5bee17d04815662c8317f10e30"
- integrity sha512-IrIP25VvXWu/VlBWTpsjGptpomtIkYrN/3aDp4UKm7xK6UxZY88kcJ1UwETbzHAlwN21MnNfwlar0u8y3KpiXw==
+"@babel/plugin-transform-parameters@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz#7556cf03f318bd2719fe4c922d2d808be5571e16"
+ integrity sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw==
dependencies:
- "@babel/helper-call-delegate" "^7.1.0"
+ "@babel/helper-call-delegate" "^7.4.4"
"@babel/helper-get-function-arity" "^7.0.0"
"@babel/helper-plugin-utils" "^7.0.0"
-"@babel/plugin-transform-regenerator@^7.3.4":
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.3.4.tgz#1601655c362f5b38eead6a52631f5106b29fa46a"
- integrity sha512-hvJg8EReQvXT6G9H2MvNPXkv9zK36Vxa1+csAVTpE1J3j0zlHplw76uudEbJxgvqZzAq9Yh45FLD4pk5mKRFQA==
+"@babel/plugin-transform-property-literals@^7.2.0":
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.2.0.tgz#03e33f653f5b25c4eb572c98b9485055b389e905"
+ integrity sha512-9q7Dbk4RhgcLp8ebduOpCbtjh7C0itoLYHXd9ueASKAG/is5PQtMR5VJGka9NKqGhYEGn5ITahd4h9QeBMylWQ==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-regenerator@^7.3.4", "@babel/plugin-transform-regenerator@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.4.tgz#5b4da4df79391895fca9e28f99e87e22cfc02072"
+ integrity sha512-Zz3w+pX1SI0KMIiqshFZkwnVGUhDZzpX2vtPzfJBKQQq8WsP/Xy9DNdELWivxcKOCX/Pywge4SiEaPaLtoDT4g==
dependencies:
regenerator-transform "^0.13.4"
+"@babel/plugin-transform-reserved-words@^7.2.0":
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.2.0.tgz#4792af87c998a49367597d07fedf02636d2e1634"
+ integrity sha512-fz43fqW8E1tAB3DKF19/vxbpib1fuyCwSPE418ge5ZxILnBhWyhtPgz8eh1RCGGJlwvksHkyxMxh0eenFi+kFw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.0.0"
+
"@babel/plugin-transform-runtime@^7.3.4":
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.3.4.tgz#57805ac8c1798d102ecd75c03b024a5b3ea9b431"
- integrity sha512-PaoARuztAdd5MgeVjAxnIDAIUet5KpogqaefQvPOmPYCxYoaPhautxDh3aO8a4xHsKgT/b9gSxR0BKK1MIewPA==
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.4.4.tgz#a50f5d16e9c3a4ac18a1a9f9803c107c380bce08"
+ integrity sha512-aMVojEjPszvau3NRg+TIH14ynZLvPewH4xhlCW1w6A3rkxTS1m4uwzRclYR9oS+rl/dr+kT+pzbfHuAWP/lc7Q==
dependencies:
"@babel/helper-module-imports" "^7.0.0"
"@babel/helper-plugin-utils" "^7.0.0"
@@ -523,10 +544,10 @@
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/helper-regex" "^7.0.0"
-"@babel/plugin-transform-template-literals@^7.2.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.2.0.tgz#d87ed01b8eaac7a92473f608c97c089de2ba1e5b"
- integrity sha512-FkPix00J9A/XWXv4VoKJBMeSkyY9x/TqIh76wzcdfl57RJJcf8CehQ08uwfhCDNtRQYtHQKBTwKZDEyjE13Lwg==
+"@babel/plugin-transform-template-literals@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz#9d28fea7bbce637fb7612a0750989d8321d4bcb0"
+ integrity sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g==
dependencies:
"@babel/helper-annotate-as-pure" "^7.0.0"
"@babel/helper-plugin-utils" "^7.0.0"
@@ -538,107 +559,112 @@
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
-"@babel/plugin-transform-unicode-regex@^7.2.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.2.0.tgz#4eb8db16f972f8abb5062c161b8b115546ade08b"
- integrity sha512-m48Y0lMhrbXEJnVUaYly29jRXbQ3ksxPrS1Tg8t+MHqzXhtBYAvI51euOBaoAlZLPHsieY9XPVMf80a5x0cPcA==
+"@babel/plugin-transform-unicode-regex@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz#ab4634bb4f14d36728bf5978322b35587787970f"
+ integrity sha512-il+/XdNw01i93+M9J9u4T7/e/Ue/vWfNZE4IRUQjplu2Mqb/AFTDimkw2tdEdSH50wuQXZAbXSql0UphQke+vA==
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
- "@babel/helper-regex" "^7.0.0"
- regexpu-core "^4.1.3"
+ "@babel/helper-regex" "^7.4.4"
+ regexpu-core "^4.5.4"
"@babel/polyfill@^7.2.5":
- version "7.2.5"
- resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.2.5.tgz#6c54b964f71ad27edddc567d065e57e87ed7fa7d"
- integrity sha512-8Y/t3MWThtMLYr0YNC/Q76tqN1w30+b0uQMeFUYauG2UGTR19zyUtFrAzT23zNtBxPp+LbE5E/nwV/q/r3y6ug==
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.4.4.tgz#78801cf3dbe657844eeabf31c1cae3828051e893"
+ integrity sha512-WlthFLfhQQhh+A2Gn5NSFl0Huxz36x86Jn+E9OW7ibK8edKPq+KLy4apM1yDpQ8kJOVi1OVjpP4vSDLdrI04dg==
dependencies:
- core-js "^2.5.7"
- regenerator-runtime "^0.12.0"
+ core-js "^2.6.5"
+ regenerator-runtime "^0.13.2"
"@babel/preset-env@^7.3.4":
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.3.4.tgz#887cf38b6d23c82f19b5135298bdb160062e33e1"
- integrity sha512-2mwqfYMK8weA0g0uBKOt4FE3iEodiHy9/CW0b+nWXcbL+pGzLx8ESYc+j9IIxr6LTDHWKgPm71i9smo02bw+gA==
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.4.4.tgz#b6f6825bfb27b3e1394ca3de4f926482722c1d6f"
+ integrity sha512-FU1H+ACWqZZqfw1x2G1tgtSSYSfxJLkpaUQL37CenULFARDo+h4xJoVHzRoHbK+85ViLciuI7ME4WTIhFRBBlw==
dependencies:
"@babel/helper-module-imports" "^7.0.0"
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/plugin-proposal-async-generator-functions" "^7.2.0"
"@babel/plugin-proposal-json-strings" "^7.2.0"
- "@babel/plugin-proposal-object-rest-spread" "^7.3.4"
+ "@babel/plugin-proposal-object-rest-spread" "^7.4.4"
"@babel/plugin-proposal-optional-catch-binding" "^7.2.0"
- "@babel/plugin-proposal-unicode-property-regex" "^7.2.0"
+ "@babel/plugin-proposal-unicode-property-regex" "^7.4.4"
"@babel/plugin-syntax-async-generators" "^7.2.0"
"@babel/plugin-syntax-json-strings" "^7.2.0"
"@babel/plugin-syntax-object-rest-spread" "^7.2.0"
"@babel/plugin-syntax-optional-catch-binding" "^7.2.0"
"@babel/plugin-transform-arrow-functions" "^7.2.0"
- "@babel/plugin-transform-async-to-generator" "^7.3.4"
+ "@babel/plugin-transform-async-to-generator" "^7.4.4"
"@babel/plugin-transform-block-scoped-functions" "^7.2.0"
- "@babel/plugin-transform-block-scoping" "^7.3.4"
- "@babel/plugin-transform-classes" "^7.3.4"
+ "@babel/plugin-transform-block-scoping" "^7.4.4"
+ "@babel/plugin-transform-classes" "^7.4.4"
"@babel/plugin-transform-computed-properties" "^7.2.0"
- "@babel/plugin-transform-destructuring" "^7.2.0"
- "@babel/plugin-transform-dotall-regex" "^7.2.0"
+ "@babel/plugin-transform-destructuring" "^7.4.4"
+ "@babel/plugin-transform-dotall-regex" "^7.4.4"
"@babel/plugin-transform-duplicate-keys" "^7.2.0"
"@babel/plugin-transform-exponentiation-operator" "^7.2.0"
- "@babel/plugin-transform-for-of" "^7.2.0"
- "@babel/plugin-transform-function-name" "^7.2.0"
+ "@babel/plugin-transform-for-of" "^7.4.4"
+ "@babel/plugin-transform-function-name" "^7.4.4"
"@babel/plugin-transform-literals" "^7.2.0"
+ "@babel/plugin-transform-member-expression-literals" "^7.2.0"
"@babel/plugin-transform-modules-amd" "^7.2.0"
- "@babel/plugin-transform-modules-commonjs" "^7.2.0"
- "@babel/plugin-transform-modules-systemjs" "^7.3.4"
+ "@babel/plugin-transform-modules-commonjs" "^7.4.4"
+ "@babel/plugin-transform-modules-systemjs" "^7.4.4"
"@babel/plugin-transform-modules-umd" "^7.2.0"
- "@babel/plugin-transform-named-capturing-groups-regex" "^7.3.0"
- "@babel/plugin-transform-new-target" "^7.0.0"
+ "@babel/plugin-transform-named-capturing-groups-regex" "^7.4.4"
+ "@babel/plugin-transform-new-target" "^7.4.4"
"@babel/plugin-transform-object-super" "^7.2.0"
- "@babel/plugin-transform-parameters" "^7.2.0"
- "@babel/plugin-transform-regenerator" "^7.3.4"
+ "@babel/plugin-transform-parameters" "^7.4.4"
+ "@babel/plugin-transform-property-literals" "^7.2.0"
+ "@babel/plugin-transform-regenerator" "^7.4.4"
+ "@babel/plugin-transform-reserved-words" "^7.2.0"
"@babel/plugin-transform-shorthand-properties" "^7.2.0"
"@babel/plugin-transform-spread" "^7.2.0"
"@babel/plugin-transform-sticky-regex" "^7.2.0"
- "@babel/plugin-transform-template-literals" "^7.2.0"
+ "@babel/plugin-transform-template-literals" "^7.4.4"
"@babel/plugin-transform-typeof-symbol" "^7.2.0"
- "@babel/plugin-transform-unicode-regex" "^7.2.0"
- browserslist "^4.3.4"
+ "@babel/plugin-transform-unicode-regex" "^7.4.4"
+ "@babel/types" "^7.4.4"
+ browserslist "^4.5.2"
+ core-js-compat "^3.0.0"
invariant "^2.2.2"
js-levenshtein "^1.1.3"
- semver "^5.3.0"
+ semver "^5.5.0"
-"@babel/runtime@^7.3.4":
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.3.4.tgz#73d12ba819e365fcf7fd152aed56d6df97d21c83"
- integrity sha512-IvfvnMdSaLBateu0jfsYIpZTxAc2cKEXEMiezGGN75QcBcecDUKd3PgLAncT0oOgxKy8dd8hrJKj9MfzgfZd6g==
+"@babel/runtime@^7.3.4", "@babel/runtime@^7.4.2":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.4.tgz#dc2e34982eb236803aa27a07fea6857af1b9171d"
+ integrity sha512-w0+uT71b6Yi7i5SE0co4NioIpSYS6lLiXvCzWzGSKvpK5vdQtCbICHMj+gbAKAOtxiV6HsVh/MBdaF9EQ6faSg==
dependencies:
- regenerator-runtime "^0.12.0"
+ regenerator-runtime "^0.13.2"
-"@babel/template@^7.1.0", "@babel/template@^7.1.2", "@babel/template@^7.2.2":
- version "7.2.2"
- resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.2.2.tgz#005b3fdf0ed96e88041330379e0da9a708eb2907"
- integrity sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==
+"@babel/template@^7.1.0", "@babel/template@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237"
+ integrity sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==
dependencies:
"@babel/code-frame" "^7.0.0"
- "@babel/parser" "^7.2.2"
- "@babel/types" "^7.2.2"
+ "@babel/parser" "^7.4.4"
+ "@babel/types" "^7.4.4"
-"@babel/traverse@^7.1.0", "@babel/traverse@^7.1.5", "@babel/traverse@^7.3.4":
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.3.4.tgz#1330aab72234f8dea091b08c4f8b9d05c7119e06"
- integrity sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==
+"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.4.4.tgz#0776f038f6d78361860b6823887d4f3937133fe8"
+ integrity sha512-Gw6qqkw/e6AGzlyj9KnkabJX7VcubqPtkUQVAwkc0wUMldr3A/hezNB3Rc5eIvId95iSGkGIOe5hh1kMKf951A==
dependencies:
"@babel/code-frame" "^7.0.0"
- "@babel/generator" "^7.3.4"
+ "@babel/generator" "^7.4.4"
"@babel/helper-function-name" "^7.1.0"
- "@babel/helper-split-export-declaration" "^7.0.0"
- "@babel/parser" "^7.3.4"
- "@babel/types" "^7.3.4"
+ "@babel/helper-split-export-declaration" "^7.4.4"
+ "@babel/parser" "^7.4.4"
+ "@babel/types" "^7.4.4"
debug "^4.1.0"
globals "^11.1.0"
lodash "^4.17.11"
-"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.3.0", "@babel/types@^7.3.4":
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.3.4.tgz#bf482eaeaffb367a28abbf9357a94963235d90ed"
- integrity sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==
+"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.4.4":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.4.4.tgz#8db9e9a629bb7c29370009b4b779ed93fe57d5f0"
+ integrity sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==
dependencies:
esutils "^2.0.2"
lodash "^4.17.11"
@@ -699,10 +725,34 @@
webpack-cli "^3.2.3"
webpack-sources "^1.3.0"
+"@types/events@*":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
+ integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
+
+"@types/glob@^7.1.1":
+ version "7.1.1"
+ resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
+ integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==
+ dependencies:
+ "@types/events" "*"
+ "@types/minimatch" "*"
+ "@types/node" "*"
+
+"@types/minimatch@*":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
+ integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
+
+"@types/node@*":
+ version "12.0.0"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-12.0.0.tgz#d11813b9c0ff8aaca29f04cbc12817f4c7d656e5"
+ integrity sha512-Jrb/x3HT4PTJp6a4avhmJCDEVrPdqLfl3e8GGMbpkGGdwAV5UGlIs4vVEfsHHfylZVOKZWpOqmqFH8CbfOZ6kg==
+
"@types/q@^1.5.1":
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.1.tgz#48fd98c1561fe718b61733daed46ff115b496e18"
- integrity sha512-eqz8c/0kwNi/OEHQfvIuJVLTst3in0e7uTKeuY+WL/zfKn0xVujOTp42bS/vUUokhK5P2BppLd9JXMOMHcgbjA==
+ version "1.5.2"
+ resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8"
+ integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==
"@webassemblyjs/ast@1.8.5":
version "1.8.5"
@@ -865,13 +915,13 @@ abbrev@1:
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
-accepts@~1.3.4:
- version "1.3.4"
- resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.4.tgz#86246758c7dd6d21a6474ff084a4740ec05eb21f"
- integrity sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=
+accepts@~1.3.4, accepts@~1.3.5:
+ version "1.3.7"
+ resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
+ integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
dependencies:
- mime-types "~2.1.16"
- negotiator "0.6.1"
+ mime-types "~2.1.24"
+ negotiator "0.6.2"
acorn-dynamic-import@^4.0.0:
version "4.0.0"
@@ -884,7 +934,7 @@ acorn@^6.0.5:
integrity sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==
"actiontext@file:../..":
- version "6.0.0-beta2"
+ version "6.1.0-alpha"
dependencies:
"@rails/activestorage" "^6.0.0-alpha"
@@ -894,28 +944,11 @@ ajv-errors@^1.0.0:
integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==
ajv-keywords@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.1.0.tgz#ac2b27939c543e95d2c06e7f7f5c27be4aa543be"
- integrity sha1-rCsnk5xUPpXSwG5/f1wnvkqlQ74=
-
-ajv@^4.9.1:
- version "4.11.8"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536"
- integrity sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=
- dependencies:
- co "^4.6.0"
- json-stable-stringify "^1.0.1"
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.0.tgz#4b831e7b531415a7cc518cd404e73f6193c6349d"
+ integrity sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw==
-ajv@^6.1.0:
- version "6.1.1"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.1.1.tgz#978d597fbc2b7d0e5a5c3ddeb149a682f2abfa0e"
- integrity sha1-l41Zf7wrfQ5aXD3esUmmgvKr+g4=
- dependencies:
- fast-deep-equal "^1.0.0"
- fast-json-stable-stringify "^2.0.0"
- json-schema-traverse "^0.3.0"
-
-ajv@^6.5.5:
+ajv@^6.1.0, ajv@^6.5.5:
version "6.10.0"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1"
integrity sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==
@@ -981,17 +1014,17 @@ aproba@^1.0.3, aproba@^1.1.1:
integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
are-we-there-yet@~1.1.2:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d"
- integrity sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
+ integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==
dependencies:
delegates "^1.0.0"
readable-stream "^2.0.6"
argparse@^1.0.7:
- version "1.0.9"
- resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86"
- integrity sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
+ integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
dependencies:
sprintf-js "~1.0.2"
@@ -1021,9 +1054,9 @@ array-flatten@1.1.1:
integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
array-flatten@^2.1.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.1.tgz#426bb9da84090c1838d812c8150af20a8331e296"
- integrity sha1-Qmu52oQJDBg42BLIFQryCoMx4pY=
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099"
+ integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==
array-union@^1.0.1:
version "1.0.2"
@@ -1043,34 +1076,32 @@ array-unique@^0.3.2:
integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
asn1.js@^4.0.0:
- version "4.9.2"
- resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.2.tgz#8117ef4f7ed87cd8f89044b5bff97ac243a16c9a"
- integrity sha512-b/OsSjvWEo8Pi8H0zsDd2P6Uqo2TK2pH8gNLSJtNLM2Db0v2QaAZ0pBQJXVjAn4gBuugeVDr7s63ZogpUIwWDg==
+ version "4.10.1"
+ resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0"
+ integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==
dependencies:
bn.js "^4.0.0"
inherits "^2.0.1"
minimalistic-assert "^1.0.0"
asn1@~0.2.3:
- version "0.2.3"
- resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86"
- integrity sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=
+ version "0.2.4"
+ resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
+ integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
+ dependencies:
+ safer-buffer "~2.1.0"
assert-plus@1.0.0, assert-plus@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
-assert-plus@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234"
- integrity sha1-104bh+ev/A24qttwIfP+SBAasjQ=
-
assert@^1.1.1:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91"
- integrity sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb"
+ integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==
dependencies:
+ object-assign "^4.1.1"
util "0.10.3"
assign-symbols@^1.0.0:
@@ -1078,10 +1109,10 @@ assign-symbols@^1.0.0:
resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=
-async-each@^1.0.0, async-each@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
- integrity sha1-GdOGodntxufByF04iu28xW0zYC0=
+async-each@^1.0.1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf"
+ integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==
async-foreach@^0.1.3:
version "0.1.3"
@@ -1098,38 +1129,28 @@ asynckit@^0.4.0:
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
-atob@^2.0.0:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/atob/-/atob-2.0.3.tgz#19c7a760473774468f20b2d2d03372ad7d4cbf5d"
- integrity sha1-GcenYEc3dEaPILLS0DNyrX1Mv10=
+atob@^2.1.1:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
+ integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
autoprefixer@^9.4.9:
- version "9.4.10"
- resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.4.10.tgz#e1be61fc728bacac8f4252ed242711ec0dcc6a7b"
- integrity sha512-XR8XZ09tUrrSzgSlys4+hy5r2/z4Jp7Ag3pHm31U4g/CTccYPOVe19AkaJ4ey/vRd1sfj+5TtuD6I0PXtutjvQ==
+ version "9.5.1"
+ resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.5.1.tgz#243b1267b67e7e947f28919d786b50d3bb0fb357"
+ integrity sha512-KJSzkStUl3wP0D5sdMlP82Q52JLy5+atf2MHAre48+ckWkXgixmfHyWmA77wFDy6jTHU6mIgXv6hAQ2mf1PjJQ==
dependencies:
- browserslist "^4.4.2"
- caniuse-lite "^1.0.30000940"
+ browserslist "^4.5.4"
+ caniuse-lite "^1.0.30000957"
normalize-range "^0.1.2"
num2fraction "^1.2.2"
postcss "^7.0.14"
postcss-value-parser "^3.3.1"
-aws-sign2@~0.6.0:
- version "0.6.0"
- resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
- integrity sha1-FDQt0428yU0OW4fXY81jYSwOeU8=
-
aws-sign2@~0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
-aws4@^1.2.1:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e"
- integrity sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=
-
aws4@^1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
@@ -1153,12 +1174,13 @@ babel-plugin-dynamic-import-node@^2.2.0:
object.assign "^4.1.0"
babel-plugin-macros@^2.5.0:
- version "2.5.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.5.0.tgz#01f4d3b50ed567a67b80a30b9da066e94f4097b6"
- integrity sha512-BWw0lD0kVZAXRD3Od1kMrdmfudqzDzYv2qrN3l2ISR1HVp1EgLKfbOrYV9xmY5k3qx3RIu5uPAUZZZHpo0o5Iw==
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.5.1.tgz#4a119ac2c2e19b458c259b9accd7ee34fd57ec6f"
+ integrity sha512-xN3KhAxPzsJ6OQTktCanNpIFnnMsCV+t8OloKxIL72D6+SUZYFn9qfklPgef5HyyDtzYZqqb+fs1S12+gQY82Q==
dependencies:
- cosmiconfig "^5.0.5"
- resolve "^1.8.1"
+ "@babel/runtime" "^7.4.2"
+ cosmiconfig "^5.2.0"
+ resolve "^1.10.0"
balanced-match@^1.0.0:
version "1.0.0"
@@ -1166,9 +1188,9 @@ balanced-match@^1.0.0:
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
base64-js@^1.0.2:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886"
- integrity sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3"
+ integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==
base@^0.11.1:
version "0.11.2"
@@ -1189,26 +1211,21 @@ batch@0.6.1:
integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=
bcrypt-pbkdf@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d"
- integrity sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
+ integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
dependencies:
tweetnacl "^0.14.3"
-big.js@^3.1.3:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e"
- integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==
-
big.js@^5.2.2:
version "5.2.2"
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
binary-extensions@^1.0.0:
- version "1.11.0"
- resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205"
- integrity sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=
+ version "1.13.1"
+ resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
+ integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==
block-stream@*:
version "0.0.9"
@@ -1218,30 +1235,30 @@ block-stream@*:
inherits "~2.0.0"
bluebird@^3.5.3:
- version "3.5.3"
- resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7"
- integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==
+ version "3.5.4"
+ resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.4.tgz#d6cc661595de30d5b3af5fcedd3c0b3ef6ec5714"
+ integrity sha512-FG+nFEZChJrbQ9tIccIfZJBz3J7mLrAhxakAbnrJWn8d7aKOC+LWifa0G+p4ZqKp4y13T7juYvdhq9NzKdsrjw==
bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
version "4.11.8"
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==
-body-parser@1.18.2:
- version "1.18.2"
- resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454"
- integrity sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=
+body-parser@1.18.3:
+ version "1.18.3"
+ resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4"
+ integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=
dependencies:
bytes "3.0.0"
content-type "~1.0.4"
debug "2.6.9"
- depd "~1.1.1"
- http-errors "~1.6.2"
- iconv-lite "0.4.19"
+ depd "~1.1.2"
+ http-errors "~1.6.3"
+ iconv-lite "0.4.23"
on-finished "~2.3.0"
- qs "6.5.1"
- raw-body "2.3.2"
- type-is "~1.6.15"
+ qs "6.5.2"
+ raw-body "2.3.3"
+ type-is "~1.6.16"
bonjour@^3.5.0:
version "3.5.0"
@@ -1260,13 +1277,6 @@ boolbase@^1.0.0, boolbase@~1.0.0:
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
-boom@2.x.x:
- version "2.10.1"
- resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f"
- integrity sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=
- dependencies:
- hoek "2.x.x"
-
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@@ -1275,23 +1285,6 @@ brace-expansion@^1.1.7:
balanced-match "^1.0.0"
concat-map "0.0.1"
-braces@^2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.0.tgz#a46941cb5fb492156b3d6a656e06c35364e3e66e"
- integrity sha512-P4O8UQRdGiMLWSizsApmXVQDBS6KCt7dSexgLKBmH5Hr1CZq7vsnscFh8oR1sP1ab1Zj0uCHCEzZeV6SfUf3rA==
- dependencies:
- arr-flatten "^1.1.0"
- array-unique "^0.3.2"
- define-property "^1.0.0"
- extend-shallow "^2.0.1"
- fill-range "^4.0.0"
- isobject "^3.0.1"
- repeat-element "^1.1.2"
- snapdragon "^0.8.1"
- snapdragon-node "^2.0.1"
- split-string "^3.0.2"
- to-regex "^3.0.1"
-
braces@^2.3.1, braces@^2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
@@ -1314,9 +1307,9 @@ brorand@^1.0.1:
integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=
browserify-aes@^1.0.0, browserify-aes@^1.0.4:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.1.1.tgz#38b7ab55edb806ff2dcda1a7f1620773a477c49f"
- integrity sha512-UGnTYAnB2a3YuYKIRy1/4FB2HdM866E0qC46JXvVTYKlBlZlnvfpSfY6OKfXZAkv70eJ2a1SqzpAo5CRhZGDFg==
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48"
+ integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==
dependencies:
buffer-xor "^1.0.3"
cipher-base "^1.0.0"
@@ -1326,22 +1319,23 @@ browserify-aes@^1.0.0, browserify-aes@^1.0.4:
safe-buffer "^5.0.1"
browserify-cipher@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a"
- integrity sha1-mYgkSHS/XtTijalWZtzWasj8Njo=
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0"
+ integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==
dependencies:
browserify-aes "^1.0.4"
browserify-des "^1.0.0"
evp_bytestokey "^1.0.0"
browserify-des@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd"
- integrity sha1-2qJ3cXRwki7S/hhZQRihdUOXId0=
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c"
+ integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==
dependencies:
cipher-base "^1.0.1"
des.js "^1.0.0"
inherits "^2.0.1"
+ safe-buffer "^5.1.2"
browserify-rsa@^4.0.0:
version "4.0.1"
@@ -1371,14 +1365,14 @@ browserify-zlib@^0.2.0:
dependencies:
pako "~1.0.5"
-browserslist@^4.0.0, browserslist@^4.3.4, browserslist@^4.4.2:
- version "4.4.2"
- resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.4.2.tgz#6ea8a74d6464bb0bd549105f659b41197d8f0ba2"
- integrity sha512-ISS/AIAiHERJ3d45Fz0AVYKkgcy+F/eJHzKEvv1j0wwKGKD9T3BrwKr/5g45L+Y4XIK5PlTqefHciRFcfE1Jxg==
+browserslist@^4.0.0, browserslist@^4.4.2, browserslist@^4.5.2, browserslist@^4.5.4:
+ version "4.5.6"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.5.6.tgz#ea42e8581ca2513fa7f371d4dd66da763938163d"
+ integrity sha512-o/hPOtbU9oX507lIqon+UvPYqpx3mHc8cV3QemSBTXwkG8gSQSK6UKvXcE/DcleU3+A59XTUHyCvZ5qGy8xVAg==
dependencies:
- caniuse-lite "^1.0.30000939"
- electron-to-chromium "^1.3.113"
- node-releases "^1.1.8"
+ caniuse-lite "^1.0.30000963"
+ electron-to-chromium "^1.3.127"
+ node-releases "^1.1.17"
buffer-from@^1.0.0:
version "1.1.1"
@@ -1404,11 +1398,6 @@ buffer@^4.3.0:
ieee754 "^1.1.4"
isarray "^1.0.0"
-builtin-modules@^1.0.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
- integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=
-
builtin-status-codes@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
@@ -1491,15 +1480,10 @@ camelcase@^3.0.0:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo=
-camelcase@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
- integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
-
camelcase@^5.0.0, camelcase@^5.2.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.2.0.tgz#e7522abda5ed94cc0489e1b8466610e88404cf45"
- integrity sha512-IXFsBS2pC+X0j0N/GE7Dm7j3bsEBp+oTpb7F50dwEVX7rf3IgwO9XatnegTsDtniKCUtEJH4fSU6Asw7uoVLfQ==
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
+ integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
caniuse-api@^3.0.0:
version "3.0.0"
@@ -1511,15 +1495,10 @@ caniuse-api@^3.0.0:
lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0"
-caniuse-lite@^1.0.0:
- version "1.0.30000808"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000808.tgz#7d759b5518529ea08b6705a19e70dbf401628ffc"
- integrity sha512-vT0JLmHdvq1UVbYXioxCXHYdNw55tyvi+IUWyX0Zeh1OFQi2IllYtm38IJnSgHWCv/zUnX1hdhy3vMJvuTNSqw==
-
-caniuse-lite@^1.0.30000939, caniuse-lite@^1.0.30000940:
- version "1.0.30000942"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000942.tgz#454139b28274bce70bfe1d50c30970df7430c6e4"
- integrity sha512-wLf+IhZUy2rfz48tc40OH7jHjXjnvDFEYqBHluINs/6MgzoNLPf25zhE4NOVzqxLKndf+hau81sAW0RcGHIaBQ==
+caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000939, caniuse-lite@^1.0.30000957, caniuse-lite@^1.0.30000963:
+ version "1.0.30000967"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000967.tgz#a5039577806fccee80a04aaafb2c0890b1ee2f73"
+ integrity sha512-rUBIbap+VJfxTzrM4akJ00lkvVb5/n5v3EGXfWzSH5zT8aJmGzjA8HWhJ4U6kCpzxozUSnB+yvAYDRPY6mRpgQ==
case-sensitive-paths-webpack-plugin@^2.2.0:
version "2.2.0"
@@ -1551,29 +1530,10 @@ chalk@^2.0, chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2:
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
-chokidar@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.1.tgz#6e67e9998fe10e8f651e975ca62460456ff8e297"
- integrity sha512-rv5iP8ENhpqvDWr677rAXcB+SMoPQ1urd4ch79+PhM4lQwbATdJUQK69t0lJIKNB+VXpqxt5V1gvqs59XEPKnw==
- dependencies:
- anymatch "^2.0.0"
- async-each "^1.0.0"
- braces "^2.3.0"
- glob-parent "^3.1.0"
- inherits "^2.0.1"
- is-binary-path "^1.0.0"
- is-glob "^4.0.0"
- normalize-path "^2.1.1"
- path-is-absolute "^1.0.0"
- readdirp "^2.0.0"
- upath "1.0.0"
- optionalDependencies:
- fsevents "^1.0.0"
-
-chokidar@^2.0.2:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.2.tgz#9c23ea40b01638439e0513864d362aeacc5ad058"
- integrity sha512-IwXUx0FXc5ibYmPC2XeEj5mpXoV66sR+t3jqu2NS2GYwCktt3KF1/Qqjws/NkegajBA4RbZ5+DDwlOiJsxDHEg==
+chokidar@^2.0.2, chokidar@^2.1.5:
+ version "2.1.5"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.5.tgz#0ae8434d962281a5f56c72869e79cb6d9d86ad4d"
+ integrity sha512-i0TprVWp+Kj4WRPtInjexJ8Q+BqTE909VpH8xVhXrJkoc5QC8VO9TryGOqTr+2hljzc1sC62t22h5tZePodM/A==
dependencies:
anymatch "^2.0.0"
async-each "^1.0.1"
@@ -1585,7 +1545,7 @@ chokidar@^2.0.2:
normalize-path "^3.0.0"
path-is-absolute "^1.0.0"
readdirp "^2.2.1"
- upath "^1.1.0"
+ upath "^1.1.1"
optionalDependencies:
fsevents "^1.2.7"
@@ -1647,11 +1607,6 @@ clone-deep@^2.0.1:
kind-of "^6.0.0"
shallow-clone "^1.0.0"
-co@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
- integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=
-
coa@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3"
@@ -1675,40 +1630,38 @@ collection-visit@^1.0.0:
object-visit "^1.0.0"
color-convert@^1.9.0, color-convert@^1.9.1:
- version "1.9.1"
- resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed"
- integrity sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==
+ version "1.9.3"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+ integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
dependencies:
- color-name "^1.1.1"
+ color-name "1.1.3"
-color-name@^1.0.0, color-name@^1.1.1:
+color-name@1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
+color-name@^1.0.0:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+ integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
color-string@^1.5.2:
- version "1.5.2"
- resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.2.tgz#26e45814bc3c9a7cbd6751648a41434514a773a9"
- integrity sha1-JuRYFLw8mny9Z1FkikFDRRSnc6k=
+ version "1.5.3"
+ resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc"
+ integrity sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==
dependencies:
color-name "^1.0.0"
simple-swizzle "^0.2.2"
color@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/color/-/color-3.1.0.tgz#d8e9fb096732875774c84bf922815df0308d0ffc"
- integrity sha512-CwyopLkuRYO5ei2EpzpIh6LqJMt6Mt+jZhO5VI5f/wJLZriXQE32/SSqzmrh+QB+AZT81Cj8yv+7zwToW8ahZg==
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/color/-/color-3.1.1.tgz#7abf5c0d38e89378284e873c207ae2172dcc8a61"
+ integrity sha512-PvUltIXRjehRKPSy89VnDWFKY58xyhTLyxIg21vwQBI6qLwZNPmC8k3C1uytIgFKEpOIzN4y32iPm8231zFHIg==
dependencies:
color-convert "^1.9.1"
color-string "^1.5.2"
-combined-stream@^1.0.5, combined-stream@~1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
- integrity sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=
- dependencies:
- delayed-stream "~1.0.0"
-
combined-stream@^1.0.6, combined-stream@~1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828"
@@ -1716,10 +1669,10 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
dependencies:
delayed-stream "~1.0.0"
-commander@~2.17.1:
- version "2.17.1"
- resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
- integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
+commander@^2.19.0:
+ version "2.20.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
+ integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
commondir@^1.0.1:
version "1.0.1"
@@ -1727,16 +1680,16 @@ commondir@^1.0.1:
integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
component-emitter@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
- integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
+ integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
-compressible@~2.0.11:
- version "2.0.12"
- resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.12.tgz#c59a5c99db76767e9876500e271ef63b3493bd66"
- integrity sha1-xZpcmdt2dn6YdlAOJx72OzSTvWY=
+compressible@~2.0.16:
+ version "2.0.17"
+ resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.17.tgz#6e8c108a16ad58384a977f3a482ca20bff2f38c1"
+ integrity sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw==
dependencies:
- mime-db ">= 1.30.0 < 2"
+ mime-db ">= 1.40.0 < 2"
compression-webpack-plugin@^2.0.0:
version "2.0.0"
@@ -1750,17 +1703,17 @@ compression-webpack-plugin@^2.0.0:
serialize-javascript "^1.4.0"
webpack-sources "^1.0.1"
-compression@^1.5.2:
- version "1.7.1"
- resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.1.tgz#eff2603efc2e22cf86f35d2eb93589f9875373db"
- integrity sha1-7/JgPvwuIs+G810uuTWJ+YdTc9s=
+compression@^1.7.4:
+ version "1.7.4"
+ resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f"
+ integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==
dependencies:
- accepts "~1.3.4"
+ accepts "~1.3.5"
bytes "3.0.0"
- compressible "~2.0.11"
+ compressible "~2.0.16"
debug "2.6.9"
- on-headers "~1.0.1"
- safe-buffer "5.1.1"
+ on-headers "~1.0.2"
+ safe-buffer "5.1.2"
vary "~1.1.2"
concat-map@0.0.1:
@@ -1769,18 +1722,19 @@ concat-map@0.0.1:
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
concat-stream@^1.5.0:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7"
- integrity sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=
+ version "1.6.2"
+ resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
+ integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
dependencies:
+ buffer-from "^1.0.0"
inherits "^2.0.3"
readable-stream "^2.2.2"
typedarray "^0.0.6"
-connect-history-api-fallback@^1.3.0:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz#b06873934bc5e344fef611a196a6faae0aee015a"
- integrity sha1-sGhzk0vF40T+9hGhlqb6rgruAVo=
+connect-history-api-fallback@^1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc"
+ integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==
console-browserify@^1.1.0:
version "1.1.0"
@@ -1843,7 +1797,27 @@ copy-descriptor@^0.1.0:
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
-core-js@^2.5.7:
+core-js-compat@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.0.1.tgz#bff73ba31ca8687431b9c88f78d3362646fb76f0"
+ integrity sha512-2pC3e+Ht/1/gD7Sim/sqzvRplMiRnFQVlPpDVaHtY9l7zZP7knamr3VRD6NyGfHd84MrDC0tAM9ulNxYMW0T3g==
+ dependencies:
+ browserslist "^4.5.4"
+ core-js "3.0.1"
+ core-js-pure "3.0.1"
+ semver "^6.0.0"
+
+core-js-pure@3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.0.1.tgz#37358fb0d024e6b86d443d794f4e37e949098cbe"
+ integrity sha512-mSxeQ6IghKW3MoyF4cz19GJ1cMm7761ON+WObSyLfTu/Jn3x7w4NwNFnrZxgl4MTSvYYepVLNuRtlB4loMwJ5g==
+
+core-js@3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.0.1.tgz#1343182634298f7f38622f95e73f54e48ddf4738"
+ integrity sha512-sco40rF+2KlE0ROMvydjkrVMMG1vYilP2ALoRXcYR4obqbYIuV3Bg+51GEDW+HF8n7NRA+iaA4qD0nD9lo9mew==
+
+core-js@^2.6.5:
version "2.6.5"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.5.tgz#44bc8d249e7fb2ff5d00e0341a7ffb94fbf67895"
integrity sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==
@@ -1863,39 +1837,39 @@ cosmiconfig@^4.0.0:
parse-json "^4.0.0"
require-from-string "^2.0.1"
-cosmiconfig@^5.0.0, cosmiconfig@^5.0.5:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.1.0.tgz#6c5c35e97f37f985061cdf653f114784231185cf"
- integrity sha512-kCNPvthka8gvLtzAxQXvWo4FxqRB+ftRZyPZNuab5ngvM9Y7yw7hbEysglptLgpkGX9nAOKTBVkHUAe8xtYR6Q==
+cosmiconfig@^5.0.0, cosmiconfig@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.0.tgz#45038e4d28a7fe787203aede9c25bca4a08b12c8"
+ integrity sha512-nxt+Nfc3JAqf4WIWd0jXLjTJZmsPLrA9DDc4nRw2KFJQJK7DNooqSXrNI7tzLG50CF8axczly5UV929tBmh/7g==
dependencies:
import-fresh "^2.0.0"
is-directory "^0.3.1"
- js-yaml "^3.9.0"
- lodash.get "^4.4.2"
+ js-yaml "^3.13.0"
parse-json "^4.0.0"
create-ecdh@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d"
- integrity sha1-iIxyNZbN92EvZJgjPuvXo1MBc30=
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff"
+ integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==
dependencies:
bn.js "^4.1.0"
elliptic "^6.0.0"
create-hash@^1.1.0, create-hash@^1.1.2:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd"
- integrity sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0=
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196"
+ integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==
dependencies:
cipher-base "^1.0.1"
inherits "^2.0.1"
- ripemd160 "^2.0.0"
+ md5.js "^1.3.4"
+ ripemd160 "^2.0.1"
sha.js "^2.4.0"
create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
- version "1.1.6"
- resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06"
- integrity sha1-rLniIaThe9sHbpBlfEK5PjcmzwY=
+ version "1.1.7"
+ resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff"
+ integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==
dependencies:
cipher-base "^1.0.3"
create-hash "^1.1.0"
@@ -1923,13 +1897,6 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5:
shebang-command "^1.2.0"
which "^1.2.9"
-cryptiles@2.x.x:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
- integrity sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=
- dependencies:
- boom "2.x.x"
-
crypto-browserify@^3.11.0:
version "3.12.0"
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
@@ -2159,7 +2126,7 @@ date-now@^0.1.4:
resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=
-debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3:
+debug@2.6.9, debug@^2.2.0, debug@^2.3.3:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
@@ -2185,13 +2152,6 @@ decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0:
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
-decamelize@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-2.0.0.tgz#656d7bbc8094c4c788ea53c5840908c9c7d063c7"
- integrity sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg==
- dependencies:
- xregexp "4.0.0"
-
decode-uri-component@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
@@ -2207,12 +2167,7 @@ deep-extend@^0.6.0:
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
-deep-extend@~0.4.0:
- version "0.4.2"
- resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f"
- integrity sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=
-
-default-gateway@^4.0.1:
+default-gateway@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b"
integrity sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==
@@ -2220,15 +2175,7 @@ default-gateway@^4.0.1:
execa "^1.0.0"
ip-regex "^2.1.0"
-define-properties@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94"
- integrity sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=
- dependencies:
- foreach "^2.0.5"
- object-keys "^1.0.8"
-
-define-properties@^1.1.3:
+define-properties@^1.1.2, define-properties@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
@@ -2257,17 +2204,18 @@ define-property@^2.0.2:
is-descriptor "^1.0.2"
isobject "^3.0.1"
-del@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/del/-/del-3.0.0.tgz#53ecf699ffcbcb39637691ab13baf160819766e5"
- integrity sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=
+del@^4.1.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4"
+ integrity sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==
dependencies:
+ "@types/glob" "^7.1.1"
globby "^6.1.0"
- is-path-cwd "^1.0.0"
- is-path-in-cwd "^1.0.0"
- p-map "^1.1.1"
- pify "^3.0.0"
- rimraf "^2.2.8"
+ is-path-cwd "^2.0.0"
+ is-path-in-cwd "^2.0.0"
+ p-map "^2.0.0"
+ pify "^4.0.1"
+ rimraf "^2.6.3"
delayed-stream@~1.0.0:
version "1.0.0"
@@ -2279,12 +2227,7 @@ delegates@^1.0.0:
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
-depd@1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359"
- integrity sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=
-
-depd@~1.1.1:
+depd@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
@@ -2318,9 +2261,9 @@ detect-node@^2.0.4:
integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==
diffie-hellman@^5.0.0:
- version "5.0.2"
- resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e"
- integrity sha1-tYNXOScM/ias9jIJn97SoH8gnl4=
+ version "5.0.3"
+ resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
+ integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==
dependencies:
bn.js "^4.1.0"
miller-rabin "^4.0.0"
@@ -2379,10 +2322,10 @@ dot-prop@^4.1.1:
dependencies:
is-obj "^1.0.0"
-duplexify@^3.4.2, duplexify@^3.5.3:
- version "3.5.3"
- resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.3.tgz#8b5818800df92fd0125b27ab896491912858243e"
- integrity sha512-g8ID9OroF9hKt2POf8YLayy+9594PzmM3scI00/uBXocX3TWNgoB67hjzkFe9ITAbQOne/lLdBxHXvYUM4ZgGA==
+duplexify@^3.4.2, duplexify@^3.6.0:
+ version "3.7.1"
+ resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309"
+ integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==
dependencies:
end-of-stream "^1.0.0"
inherits "^2.0.1"
@@ -2390,26 +2333,27 @@ duplexify@^3.4.2, duplexify@^3.5.3:
stream-shift "^1.0.0"
ecc-jsbn@~0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
- integrity sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
+ integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=
dependencies:
jsbn "~0.1.0"
+ safer-buffer "^2.1.0"
ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
-electron-to-chromium@^1.3.113:
- version "1.3.113"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.113.tgz#b1ccf619df7295aea17bc6951dc689632629e4a9"
- integrity sha512-De+lPAxEcpxvqPTyZAXELNpRZXABRxf+uL/rSykstQhzj/B0l1150G/ExIIxKc16lI89Hgz81J0BHAcbTqK49g==
+electron-to-chromium@^1.3.127:
+ version "1.3.133"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.133.tgz#c47639c19b91feee3e22fad69f5556142007008c"
+ integrity sha512-lyoC8aoqbbDqsprb6aPdt9n3DpOZZzdz/T4IZKsR0/dkZIxnJVUjjcpOSwA66jPRIOyDAamCTAUqweU05kKNSg==
elliptic@^6.0.0:
- version "6.4.0"
- resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df"
- integrity sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=
+ version "6.4.1"
+ resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.1.tgz#c2d0b7776911b86722c632c3c06c60f2f819939a"
+ integrity sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==
dependencies:
bn.js "^4.4.0"
brorand "^1.0.1"
@@ -2424,7 +2368,7 @@ emojis-list@^2.0.0:
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k=
-encodeurl@~1.0.1:
+encodeurl@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
@@ -2450,21 +2394,14 @@ entities@^1.1.1:
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==
-errno@^0.1.3, errno@^0.1.4:
- version "0.1.6"
- resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.6.tgz#c386ce8a6283f14fc09563b71560908c9bf53026"
- integrity sha512-IsORQDpaaSwcDP4ZZnHxgE85werpo34VYn1Ud3mq+eUsF593faR8oCZNXrROVkpFu2TsbrNhHin0aUrTsQ9vNw==
+errno@^0.1.3, errno@~0.1.7:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
+ integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==
dependencies:
prr "~1.0.1"
-error-ex@^1.2.0:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc"
- integrity sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=
- dependencies:
- is-arrayish "^0.2.1"
-
-error-ex@^1.3.1:
+error-ex@^1.2.0, error-ex@^1.3.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
@@ -2503,25 +2440,24 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
eslint-scope@^4.0.0:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.2.tgz#5f10cd6cabb1965bf479fa65745673439e21cb0e"
- integrity sha512-5q1+B/ogmHl8+paxtOKx38Z8LtWkVGuNt3+GQNErqwLl6ViNp/gdJGMCjZNxZ8j/VYjDNZ2Fo+eQc1TAVPIzbg==
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848"
+ integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==
dependencies:
esrecurse "^4.1.0"
estraverse "^4.1.1"
esprima@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804"
- integrity sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
+ integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
esrecurse@^4.1.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163"
- integrity sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf"
+ integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==
dependencies:
estraverse "^4.1.0"
- object-assign "^4.0.1"
estraverse@^4.1.0, estraverse@^4.1.1:
version "4.2.0"
@@ -2539,14 +2475,14 @@ etag@~1.8.1:
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
eventemitter3@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163"
- integrity sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7"
+ integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==
-events@^1.0.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
- integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=
+events@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88"
+ integrity sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==
eventsource@^1.0.7:
version "1.0.7"
@@ -2596,39 +2532,39 @@ expand-tilde@^2.0.0, expand-tilde@^2.0.2:
dependencies:
homedir-polyfill "^1.0.1"
-express@^4.16.2:
- version "4.16.2"
- resolved "https://registry.yarnpkg.com/express/-/express-4.16.2.tgz#e35c6dfe2d64b7dca0a5cd4f21781be3299e076c"
- integrity sha1-41xt/i1kt9ygpc1PIXgb4ymeB2w=
+express@^4.16.4:
+ version "4.16.4"
+ resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e"
+ integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==
dependencies:
- accepts "~1.3.4"
+ accepts "~1.3.5"
array-flatten "1.1.1"
- body-parser "1.18.2"
+ body-parser "1.18.3"
content-disposition "0.5.2"
content-type "~1.0.4"
cookie "0.3.1"
cookie-signature "1.0.6"
debug "2.6.9"
- depd "~1.1.1"
- encodeurl "~1.0.1"
+ depd "~1.1.2"
+ encodeurl "~1.0.2"
escape-html "~1.0.3"
etag "~1.8.1"
- finalhandler "1.1.0"
+ finalhandler "1.1.1"
fresh "0.5.2"
merge-descriptors "1.0.1"
methods "~1.1.2"
on-finished "~2.3.0"
parseurl "~1.3.2"
path-to-regexp "0.1.7"
- proxy-addr "~2.0.2"
- qs "6.5.1"
+ proxy-addr "~2.0.4"
+ qs "6.5.2"
range-parser "~1.2.0"
- safe-buffer "5.1.1"
- send "0.16.1"
- serve-static "1.13.1"
+ safe-buffer "5.1.2"
+ send "0.16.2"
+ serve-static "1.13.2"
setprototypeof "1.1.0"
- statuses "~1.3.1"
- type-is "~1.6.15"
+ statuses "~1.4.0"
+ type-is "~1.6.16"
utils-merge "1.0.1"
vary "~1.1.2"
@@ -2647,17 +2583,12 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2:
assign-symbols "^1.0.0"
is-extendable "^1.0.1"
-extend@~3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"
- integrity sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=
-
extend@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
-extglob@^2.0.2, extglob@^2.0.4:
+extglob@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==
@@ -2681,11 +2612,6 @@ extsprintf@^1.2.0:
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
-fast-deep-equal@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff"
- integrity sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=
-
fast-deep-equal@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
@@ -2733,26 +2659,26 @@ fill-range@^4.0.0:
repeat-string "^1.6.1"
to-regex-range "^2.1.0"
-finalhandler@1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5"
- integrity sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=
+finalhandler@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105"
+ integrity sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==
dependencies:
debug "2.6.9"
- encodeurl "~1.0.1"
+ encodeurl "~1.0.2"
escape-html "~1.0.3"
on-finished "~2.3.0"
parseurl "~1.3.2"
- statuses "~1.3.1"
+ statuses "~1.4.0"
unpipe "~1.0.0"
find-cache-dir@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.0.0.tgz#4c1faed59f45184530fb9d7fa123a4d04a98472d"
- integrity sha512-LDUY6V1Xs5eFskUVYtIwatojt6+9xC9Chnlk/jYOOvn3FAFfSaWddxahDGyNHh0b2dMXa6YW2m0tk8TdVaXHlA==
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7"
+ integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==
dependencies:
commondir "^1.0.1"
- make-dir "^1.0.0"
+ make-dir "^2.0.0"
pkg-dir "^3.0.0"
find-up@^1.0.0:
@@ -2791,12 +2717,12 @@ flatten@^1.0.2:
integrity sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=
flush-write-stream@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.2.tgz#c81b90d8746766f1a609a46809946c45dd8ae417"
- integrity sha1-yBuQ2HRnZvGmCaRoCZRsRd2K5Bc=
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8"
+ integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==
dependencies:
- inherits "^2.0.1"
- readable-stream "^2.0.4"
+ inherits "^2.0.3"
+ readable-stream "^2.3.6"
follow-redirects@^1.0.0:
version "1.7.0"
@@ -2822,25 +2748,11 @@ for-own@^1.0.0:
dependencies:
for-in "^1.0.1"
-foreach@^2.0.5:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
- integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k=
-
forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
-form-data@~2.1.1:
- version "2.1.4"
- resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1"
- integrity sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=
- dependencies:
- asynckit "^0.4.0"
- combined-stream "^1.0.5"
- mime-types "^2.1.12"
-
form-data@~2.3.2:
version "2.3.3"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
@@ -2897,32 +2809,15 @@ fs.realpath@^1.0.0:
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
-fsevents@^1.0.0:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8"
- integrity sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==
- dependencies:
- nan "^2.3.0"
- node-pre-gyp "^0.6.39"
-
fsevents@^1.2.7:
- version "1.2.7"
- resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.7.tgz#4851b664a3783e52003b3c66eb0eee1074933aa4"
- integrity sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw==
+ version "1.2.9"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f"
+ integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==
dependencies:
- nan "^2.9.2"
- node-pre-gyp "^0.10.0"
-
-fstream-ignore@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105"
- integrity sha1-nDHa40dnAY/h0kmyTa2mfQktoQU=
- dependencies:
- fstream "^1.0.0"
- inherits "2"
- minimatch "^3.0.0"
+ nan "^2.12.1"
+ node-pre-gyp "^0.12.0"
-fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2:
+fstream@^1.0.0, fstream@^1.0.2:
version "1.0.11"
resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171"
integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=
@@ -2932,7 +2827,7 @@ fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2:
mkdirp ">=0.5 0"
rimraf "2"
-function-bind@^1.0.2, function-bind@^1.1.1:
+function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
@@ -2952,16 +2847,16 @@ gauge@~2.7.3:
wide-align "^1.1.0"
gaze@^1.0.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.2.tgz#847224677adb8870d679257ed3388fdb61e40105"
- integrity sha1-hHIkZ3rbiHDWeSV+0ziP22HkAQU=
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a"
+ integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==
dependencies:
globule "^1.0.0"
get-caller-file@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
- integrity sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
+ integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==
get-stdin@^4.0.1:
version "4.0.1"
@@ -2995,33 +2890,10 @@ glob-parent@^3.1.0:
is-glob "^3.1.0"
path-dirname "^1.0.0"
-glob@^6.0.4:
- version "6.0.4"
- resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22"
- integrity sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=
- dependencies:
- inflight "^1.0.4"
- inherits "2"
- minimatch "2 || 3"
- once "^1.3.0"
- path-is-absolute "^1.0.0"
-
-glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@~7.1.1:
- version "7.1.2"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
- integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==
- dependencies:
- fs.realpath "^1.0.0"
- inflight "^1.0.4"
- inherits "2"
- minimatch "^3.0.4"
- once "^1.3.0"
- path-is-absolute "^1.0.0"
-
-glob@^7.1.3:
- version "7.1.3"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
- integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
+glob@^7.0.0, glob@^7.0.3, glob@^7.1.2, glob@^7.1.3, glob@~7.1.1:
+ version "7.1.4"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255"
+ integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
@@ -3051,9 +2923,9 @@ global-prefix@^1.0.1:
which "^1.2.14"
globals@^11.1.0:
- version "11.11.0"
- resolved "https://registry.yarnpkg.com/globals/-/globals-11.11.0.tgz#dcf93757fa2de5486fbeed7118538adf789e9c2e"
- integrity sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==
+ version "11.12.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
+ integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
globby@^6.1.0:
version "6.1.0"
@@ -3067,20 +2939,15 @@ globby@^6.1.0:
pinkie-promise "^2.0.0"
globule@^1.0.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.0.tgz#1dc49c6822dd9e8a2fa00ba2a295006e8664bd09"
- integrity sha1-HcScaCLdnoovoAuiopUAboZkvQk=
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d"
+ integrity sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==
dependencies:
glob "~7.1.1"
- lodash "~4.17.4"
+ lodash "~4.17.10"
minimatch "~3.0.2"
-graceful-fs@^4.1.11, graceful-fs@^4.1.2:
- version "4.1.11"
- resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
- integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=
-
-graceful-fs@^4.1.15:
+graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2:
version "4.1.15"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
@@ -3090,24 +2957,11 @@ handle-thing@^2.0.0:
resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754"
integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==
-har-schema@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
- integrity sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=
-
har-schema@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
-har-validator@~4.2.1:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a"
- integrity sha1-M0gdDxu/9gDdID11gSpqX7oALio=
- dependencies:
- ajv "^4.9.1"
- har-schema "^1.0.5"
-
har-validator@~5.1.0:
version "5.1.3"
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
@@ -3169,27 +3023,13 @@ has-values@^1.0.0:
is-number "^3.0.0"
kind-of "^4.0.0"
-has@^1.0.0, has@^1.0.3:
+has@^1.0.0, has@^1.0.1, has@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
dependencies:
function-bind "^1.1.1"
-has@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28"
- integrity sha1-hGFzP1OLCDfJNh45qauelwTcLyg=
- dependencies:
- function-bind "^1.0.2"
-
-hash-base@^2.0.0:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1"
- integrity sha1-ZuodhW206KVHDK32/OI65SRO8uE=
- dependencies:
- inherits "^2.0.1"
-
hash-base@^3.0.0:
version "3.0.4"
resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918"
@@ -3199,22 +3039,12 @@ hash-base@^3.0.0:
safe-buffer "^5.0.1"
hash.js@^1.0.0, hash.js@^1.0.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846"
- integrity sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==
+ version "1.1.7"
+ resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42"
+ integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==
dependencies:
inherits "^2.0.3"
- minimalistic-assert "^1.0.0"
-
-hawk@3.1.3, hawk@~3.1.3:
- version "3.1.3"
- resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
- integrity sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=
- dependencies:
- boom "2.x.x"
- cryptiles "2.x.x"
- hoek "2.x.x"
- sntp "1.x.x"
+ minimalistic-assert "^1.0.1"
hex-color-regex@^1.1.0:
version "1.1.0"
@@ -3230,11 +3060,6 @@ hmac-drbg@^1.0.0:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1"
-hoek@2.x.x:
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
- integrity sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=
-
homedir-polyfill@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"
@@ -3243,9 +3068,9 @@ homedir-polyfill@^1.0.1:
parse-passwd "^1.0.0"
hosted-git-info@^2.1.4:
- version "2.5.0"
- resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c"
- integrity sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==
+ version "2.7.1"
+ resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047"
+ integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==
hpack.js@^2.1.6:
version "2.1.6"
@@ -3268,11 +3093,11 @@ hsla-regex@^1.0.0:
integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg=
html-comment-regex@^1.1.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e"
- integrity sha1-ZouTd26q5V696POtRkswekljYl4=
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7"
+ integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==
-html-entities@^1.2.0:
+html-entities@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f"
integrity sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=
@@ -3282,20 +3107,20 @@ http-deceiver@^1.2.7:
resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87"
integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=
-http-errors@1.6.2, http-errors@~1.6.2:
- version "1.6.2"
- resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736"
- integrity sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=
+http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3:
+ version "1.6.3"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
+ integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=
dependencies:
- depd "1.1.1"
+ depd "~1.1.2"
inherits "2.0.3"
- setprototypeof "1.0.3"
- statuses ">= 1.3.1 < 2"
+ setprototypeof "1.1.0"
+ statuses ">= 1.4.0 < 2"
http-parser-js@>=0.4.0:
- version "0.4.10"
- resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.10.tgz#92c9c1374c35085f75db359ec56cc257cbb93fa4"
- integrity sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.0.tgz#d65edbede84349d0dc30320815a15d39cc3cbbd8"
+ integrity sha512-cZdEF7r4gfRIq7ezX9J0T+kQmJNOub71dWbgAXVHDct80TKP4MCETtZQ31xyv38UwgzkWPYF/Xc0ge55dW9Z9w==
http-proxy-middleware@^0.19.1:
version "0.19.1"
@@ -3316,15 +3141,6 @@ http-proxy@^1.17.0:
follow-redirects "^1.0.0"
requires-port "^1.0.0"
-http-signature@~1.1.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
- integrity sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=
- dependencies:
- assert-plus "^0.2.0"
- jsprim "^1.2.2"
- sshpk "^1.7.0"
-
http-signature@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
@@ -3339,10 +3155,12 @@ https-browserify@^1.0.0:
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
-iconv-lite@0.4.19:
- version "0.4.19"
- resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"
- integrity sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==
+iconv-lite@0.4.23:
+ version "0.4.23"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
+ integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==
+ dependencies:
+ safer-buffer ">= 2.1.2 < 3"
iconv-lite@^0.4.4:
version "0.4.24"
@@ -3364,9 +3182,9 @@ icss-utils@^4.1.0:
postcss "^7.0.14"
ieee754@^1.1.4:
- version "1.1.8"
- resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
- integrity sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=
+ version "1.1.13"
+ resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
+ integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==
iferr@^0.1.5:
version "0.1.5"
@@ -3461,11 +3279,11 @@ ini@^1.3.4, ini@~1.3.0:
integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
internal-ip@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.2.0.tgz#46e81b638d84c338e5c67e42b1a17db67d0814fa"
- integrity sha512-ZY8Rk+hlvFeuMmG5uH1MXhhdeMntmIaxaInvAmzMq/SHV8rv4Kh+6GiQNNDQd0wZFrcO+FiTBo8lui/osKOyJw==
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907"
+ integrity sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==
dependencies:
- default-gateway "^4.0.1"
+ default-gateway "^4.2.0"
ipaddr.js "^1.9.0"
interpret@^1.1.0:
@@ -3474,9 +3292,9 @@ interpret@^1.1.0:
integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==
invariant@^2.2.2:
- version "2.2.2"
- resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360"
- integrity sha1-nh9WrArNtr8wMwbzOL47IErmA2A=
+ version "2.2.4"
+ resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
+ integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
dependencies:
loose-envify "^1.0.0"
@@ -3500,12 +3318,7 @@ ip@^1.1.0, ip@^1.1.5:
resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=
-ipaddr.js@1.5.2:
- version "1.5.2"
- resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.5.2.tgz#d4b505bde9946987ccf0fc58d9010ff9607e3fa0"
- integrity sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A=
-
-ipaddr.js@^1.9.0:
+ipaddr.js@1.9.0, ipaddr.js@^1.9.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65"
integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==
@@ -3535,9 +3348,9 @@ is-arrayish@^0.2.1:
integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
is-arrayish@^0.3.1:
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.1.tgz#c2dfc386abaa0c3e33c48db3fe87059e69065efd"
- integrity sha1-wt/DhquqDD4zxI2z/ocFnmkGXv0=
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
+ integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
is-binary-path@^1.0.0:
version "1.0.1"
@@ -3551,13 +3364,6 @@ is-buffer@^1.1.5:
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
-is-builtin-module@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe"
- integrity sha1-VAVy0096wxGfj3bDDLwbHgN6/74=
- dependencies:
- builtin-modules "^1.0.0"
-
is-callable@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75"
@@ -3661,9 +3467,9 @@ is-glob@^3.1.0:
is-extglob "^2.1.0"
is-glob@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0"
- integrity sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
+ integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
dependencies:
is-extglob "^2.1.1"
@@ -3679,31 +3485,24 @@ is-obj@^1.0.0:
resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8=
-is-odd@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-1.0.0.tgz#3b8a932eb028b3775c39bb09e91767accdb69088"
- integrity sha1-O4qTLrAos3dcObsJ6RdnrM22kIg=
- dependencies:
- is-number "^3.0.0"
-
-is-path-cwd@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
- integrity sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=
+is-path-cwd@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.1.0.tgz#2e0c7e463ff5b7a0eb60852d851a6809347a124c"
+ integrity sha512-Sc5j3/YnM8tDeyCsVeKlm/0p95075DyLmDEIkSgQ7mXkrOX+uTCtmQFm0CYzVyJwcCCmO3k8qfJt17SxQwB5Zw==
-is-path-in-cwd@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc"
- integrity sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=
+is-path-in-cwd@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz#bfe2dca26c69f397265a4009963602935a053acb"
+ integrity sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==
dependencies:
- is-path-inside "^1.0.0"
+ is-path-inside "^2.1.0"
-is-path-inside@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036"
- integrity sha1-jvW33lBDej/cprToZe96pVy0gDY=
+is-path-inside@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2"
+ integrity sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==
dependencies:
- path-is-inside "^1.0.1"
+ path-is-inside "^1.0.2"
is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4:
version "2.0.4"
@@ -3791,29 +3590,24 @@ isstream@~0.1.2:
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
js-base64@^2.1.8:
- version "2.4.3"
- resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.3.tgz#2e545ec2b0f2957f41356510205214e98fad6582"
- integrity sha512-H7ErYLM34CvDMto3GbD6xD0JLUGYXR3QTcH6B/tr4Hi/QpSThnCsIp+Sy5FRTw3B0d6py4HcNkW7nO/wdtGWEw==
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.1.tgz#1efa39ef2c5f7980bb1784ade4a8af2de3291121"
+ integrity sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==
js-levenshtein@^1.1.3:
version "1.1.6"
resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d"
integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==
-js-tokens@^3.0.0:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
- integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls=
-
-js-tokens@^4.0.0:
+"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
-js-yaml@^3.12.0, js-yaml@^3.12.2, js-yaml@^3.9.0:
- version "3.12.2"
- resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.2.tgz#ef1d067c5a9d9cb65bd72f285b5d8105c77f14fc"
- integrity sha512-QHn/Lh/7HhZ/Twc7vJYQTkjuCa0kaCcDcjK5Zlk2rvnUpy7DxMJ23+Jc2dcyvltwQVg1nygAVlB2oRDFHoRS5Q==
+js-yaml@^3.12.2, js-yaml@^3.13.0, js-yaml@^3.13.1, js-yaml@^3.9.0:
+ version "3.13.1"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
+ integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
dependencies:
argparse "^1.0.7"
esprima "^4.0.0"
@@ -3838,11 +3632,6 @@ json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2:
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
-json-schema-traverse@^0.3.0:
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
- integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=
-
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
@@ -3853,13 +3642,6 @@ json-schema@0.2.3:
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
-json-stable-stringify@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
- integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=
- dependencies:
- jsonify "~0.0.0"
-
json-stringify-safe@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
@@ -3870,11 +3652,6 @@ json3@^3.3.2:
resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1"
integrity sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=
-json5@^0.5.0:
- version "0.5.1"
- resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
- integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=
-
json5@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
@@ -3889,11 +3666,6 @@ json5@^2.1.0:
dependencies:
minimist "^1.2.0"
-jsonify@~0.0.0:
- version "0.0.0"
- resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
- integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=
-
jsprim@^1.2.2:
version "1.4.1"
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
@@ -3904,10 +3676,10 @@ jsprim@^1.2.2:
json-schema "0.2.3"
verror "1.10.0"
-killable@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.0.tgz#da8b84bd47de5395878f95d64d02f2449fe05e6b"
- integrity sha1-2ouEvUfeU5WHj5XWTQLyRJ/gXms=
+killable@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"
+ integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==
kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
version "3.2.2"
@@ -3923,7 +3695,7 @@ kind-of@^4.0.0:
dependencies:
is-buffer "^1.1.5"
-kind-of@^5.0.0, kind-of@^5.0.2:
+kind-of@^5.0.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
@@ -3941,13 +3713,6 @@ last-call-webpack-plugin@^3.0.0:
lodash "^4.17.5"
webpack-sources "^1.1.0"
-lazy-cache@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-2.0.2.tgz#b9190a4f913354694840859f8a8f7084d8822264"
- integrity sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=
- dependencies:
- set-getter "^0.1.0"
-
lcid@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
@@ -3974,20 +3739,11 @@ load-json-file@^1.0.0:
strip-bom "^2.0.0"
loader-runner@^2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2"
- integrity sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI=
-
-loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd"
- integrity sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=
- dependencies:
- big.js "^3.1.3"
- emojis-list "^2.0.0"
- json5 "^0.5.0"
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357"
+ integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==
-loader-utils@^1.2.3:
+loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3:
version "1.2.3"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7"
integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==
@@ -4009,17 +3765,7 @@ lodash._reinterpolate@~3.0.0:
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=
-lodash.assign@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7"
- integrity sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=
-
-lodash.clonedeep@^4.3.2:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
- integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
-
-lodash.get@^4.0, lodash.get@^4.4.2:
+lodash.get@^4.0:
version "4.4.2"
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
@@ -4034,11 +3780,6 @@ lodash.memoize@^4.1.2:
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
-lodash.mergewith@^4.6.0:
- version "4.6.1"
- resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927"
- integrity sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==
-
lodash.tail@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664"
@@ -4064,32 +3805,22 @@ lodash.uniq@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
-lodash@3.x:
- version "3.10.1"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
- integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=
-
-lodash@^4.0.0, lodash@~4.17.4:
- version "4.17.5"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511"
- integrity sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==
-
-lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.5:
+lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.5, lodash@~4.17.10:
version "4.17.11"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
-loglevel@^1.4.1:
+loglevel@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa"
integrity sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=
loose-envify@^1.0.0:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
- integrity sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
+ integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
dependencies:
- js-tokens "^3.0.0"
+ js-tokens "^3.0.0 || ^4.0.0"
loud-rejection@^1.0.0:
version "1.6.0"
@@ -4100,9 +3831,9 @@ loud-rejection@^1.0.0:
signal-exit "^3.0.0"
lru-cache@^4.0.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55"
- integrity sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==
+ version "4.1.5"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
+ integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
dependencies:
pseudomap "^1.0.2"
yallist "^2.1.2"
@@ -4114,12 +3845,13 @@ lru-cache@^5.1.1:
dependencies:
yallist "^3.0.2"
-make-dir@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.1.0.tgz#19b4369fe48c116f53c2af95ad102c0e39e85d51"
- integrity sha512-0Pkui4wLJ7rxvmfUvs87skoEaxmu0hCUApF8nonzpl7q//FWp9zu8W61Scz4sd/kUiqDxvUhtoam2efDyiBzcA==
+make-dir@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5"
+ integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==
dependencies:
- pify "^3.0.0"
+ pify "^4.0.1"
+ semver "^5.6.0"
mamacro@^0.0.3:
version "0.0.3"
@@ -4151,12 +3883,13 @@ map-visit@^1.0.0:
object-visit "^1.0.0"
md5.js@^1.3.4:
- version "1.3.4"
- resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d"
- integrity sha1-6b296UogpawYsENA/Fdk1bCdkB0=
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
+ integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==
dependencies:
hash-base "^3.0.0"
inherits "^2.0.1"
+ safe-buffer "^5.1.2"
mdn-data@~1.1.0:
version "1.1.4"
@@ -4169,12 +3902,12 @@ media-typer@0.3.0:
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
mem@^4.0.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/mem/-/mem-4.1.0.tgz#aeb9be2d21f47e78af29e4ac5978e8afa2ca5b8a"
- integrity sha512-I5u6Q1x7wxO0kdOpYBB28xueHADYps5uty/zg936CiG8NTe5sJL8EjrCuLneuDW3PlMdZBGDIn8BirEVdovZvg==
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178"
+ integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==
dependencies:
map-age-cleaner "^0.1.1"
- mimic-fn "^1.0.0"
+ mimic-fn "^2.0.0"
p-is-promise "^2.0.0"
memory-fs@^0.4.0, memory-fs@^0.4.1, memory-fs@~0.4.1:
@@ -4211,7 +3944,7 @@ methods@~1.1.2:
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
-micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.8:
+micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8:
version "3.1.10"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==
@@ -4230,25 +3963,6 @@ micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.8:
snapdragon "^0.8.1"
to-regex "^3.0.2"
-micromatch@^3.1.4:
- version "3.1.5"
- resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.5.tgz#d05e168c206472dfbca985bfef4f57797b4cd4ba"
- integrity sha512-ykttrLPQrz1PUJcXjwsTUjGoPJ64StIGNE2lGVD1c9CuguJ+L7/navsE8IcDNndOoCMvYV0qc/exfVbMHkUhvA==
- dependencies:
- arr-diff "^4.0.0"
- array-unique "^0.3.2"
- braces "^2.3.0"
- define-property "^1.0.0"
- extend-shallow "^2.0.1"
- extglob "^2.0.2"
- fragment-cache "^0.2.1"
- kind-of "^6.0.0"
- nanomatch "^1.2.5"
- object.pick "^1.3.0"
- regex-not "^1.0.0"
- snapdragon "^0.8.1"
- to-regex "^3.0.1"
-
miller-rabin@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d"
@@ -4257,34 +3971,17 @@ miller-rabin@^4.0.0:
bn.js "^4.0.0"
brorand "^1.0.1"
-"mime-db@>= 1.30.0 < 2":
- version "1.32.0"
- resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.32.0.tgz#485b3848b01a3cda5f968b4882c0771e58e09414"
- integrity sha512-+ZWo/xZN40Tt6S+HyakUxnSOgff+JEdaneLWIm0Z6LmpCn5DMcZntLyUY5c/rTDog28LhXLKOUZKoTxTCAdBVw==
-
-mime-db@~1.30.0:
- version "1.30.0"
- resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01"
- integrity sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=
-
-mime-db@~1.38.0:
- version "1.38.0"
- resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.38.0.tgz#1a2aab16da9eb167b49c6e4df2d9c68d63d8e2ad"
- integrity sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==
-
-mime-types@^2.1.12, mime-types@~2.1.15, mime-types@~2.1.16, mime-types@~2.1.17, mime-types@~2.1.7:
- version "2.1.17"
- resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a"
- integrity sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=
- dependencies:
- mime-db "~1.30.0"
+mime-db@1.40.0, "mime-db@>= 1.40.0 < 2":
+ version "1.40.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32"
+ integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==
-mime-types@~2.1.19:
- version "2.1.22"
- resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.22.tgz#fe6b355a190926ab7698c9a0556a11199b2199bd"
- integrity sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==
+mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24:
+ version "2.1.24"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81"
+ integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==
dependencies:
- mime-db "~1.38.0"
+ mime-db "1.40.0"
mime@1.4.1:
version "1.4.1"
@@ -4292,14 +3989,14 @@ mime@1.4.1:
integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==
mime@^2.3.1:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.0.tgz#e051fd881358585f3279df333fe694da0bcffdd6"
- integrity sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w==
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.2.tgz#ce5229a5e99ffc313abac806b482c10e7ba6ac78"
+ integrity sha512-zJBfZDkwRu+j3Pdd2aHsR5GfH2jIWhmL1ZzBoc+X+3JEti2hbArWcyJ+1laC1D2/U/W1a/+Cegj0/OnEU2ybjg==
-mimic-fn@^1.0.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
- integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
+mimic-fn@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
+ integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
mini-css-extract-plugin@^0.5.0:
version "0.5.0"
@@ -4310,17 +4007,17 @@ mini-css-extract-plugin@^0.5.0:
schema-utils "^1.0.0"
webpack-sources "^1.1.0"
-minimalistic-assert@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3"
- integrity sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=
+minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
+ integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=
-"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.2:
+minimatch@^3.0.4, minimatch@~3.0.2:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@@ -4426,32 +4123,10 @@ multicast-dns@^6.0.1:
dns-packet "^1.3.1"
thunky "^1.0.2"
-nan@^2.10.0, nan@^2.9.2:
- version "2.12.1"
- resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552"
- integrity sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==
-
-nan@^2.3.0:
- version "2.8.0"
- resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a"
- integrity sha1-7XFfP+neArV6XmJS2QqWZ14fCFo=
-
-nanomatch@^1.2.5:
- version "1.2.7"
- resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.7.tgz#53cd4aa109ff68b7f869591fdc9d10daeeea3e79"
- integrity sha512-/5ldsnyurvEw7wNpxLFgjVvBLMta43niEYOy0CJ4ntcYSbx6bugRUTQeFb4BR/WanEL1o3aQgHuVLHQaB6tOqg==
- dependencies:
- arr-diff "^4.0.0"
- array-unique "^0.3.2"
- define-property "^1.0.0"
- extend-shallow "^2.0.1"
- fragment-cache "^0.2.1"
- is-odd "^1.0.0"
- kind-of "^5.0.2"
- object.pick "^1.3.0"
- regex-not "^1.0.0"
- snapdragon "^0.8.1"
- to-regex "^3.0.1"
+nan@^2.12.1, nan@^2.13.2:
+ version "2.13.2"
+ resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7"
+ integrity sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==
nanomatch@^1.2.9:
version "1.2.13"
@@ -4471,18 +4146,18 @@ nanomatch@^1.2.9:
to-regex "^3.0.1"
needle@^2.2.1:
- version "2.2.4"
- resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.4.tgz#51931bff82533b1928b7d1d69e01f1b00ffd2a4e"
- integrity sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/needle/-/needle-2.3.1.tgz#d272f2f4034afb9c4c9ab1379aabc17fc85c9388"
+ integrity sha512-CaLXV3W8Vnbps8ZANqDGz7j4x7Yj1LW4TWF/TQuDfj7Cfx4nAPTvw98qgTevtto1oHDrh3pQkaODbqupXlsWTg==
dependencies:
- debug "^2.1.2"
+ debug "^4.1.0"
iconv-lite "^0.4.4"
sax "^1.2.4"
-negotiator@0.6.1:
- version "0.6.1"
- resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
- integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=
+negotiator@0.6.2:
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
+ integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
neo-async@^2.5.0:
version "2.6.0"
@@ -4494,10 +4169,10 @@ nice-try@^1.0.4:
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
-node-forge@0.7.1:
- version "0.7.1"
- resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.1.tgz#9da611ea08982f4b94206b3beb4cc9665f20c300"
- integrity sha1-naYR6giYL0uUIGs760zJZl8gwwA=
+node-forge@0.7.5:
+ version "0.7.5"
+ resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df"
+ integrity sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ==
node-gyp@^3.8.0:
version "3.8.0"
@@ -4518,9 +4193,9 @@ node-gyp@^3.8.0:
which "1"
node-libs-browser@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df"
- integrity sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg==
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.0.tgz#c72f60d9d46de08a940dedbb25f3ffa2f9bbaa77"
+ integrity sha512-5MQunG/oyOaBdttrL40dA7bUfPORLRWMUJLQtMg7nluxUvk5XwnLdL9twQHFAjRx/y7mIMkLKT9++qPbbk6BZA==
dependencies:
assert "^1.1.1"
browserify-zlib "^0.2.0"
@@ -4529,7 +4204,7 @@ node-libs-browser@^2.0.0:
constants-browserify "^1.0.0"
crypto-browserify "^3.11.0"
domain-browser "^1.1.1"
- events "^1.0.0"
+ events "^3.0.0"
https-browserify "^1.0.0"
os-browserify "^0.3.0"
path-browserify "0.0.0"
@@ -4543,13 +4218,13 @@ node-libs-browser@^2.0.0:
timers-browserify "^2.0.4"
tty-browserify "0.0.0"
url "^0.11.0"
- util "^0.10.3"
+ util "^0.11.0"
vm-browserify "0.0.4"
-node-pre-gyp@^0.10.0:
- version "0.10.3"
- resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc"
- integrity sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A==
+node-pre-gyp@^0.12.0:
+ version "0.12.0"
+ resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149"
+ integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==
dependencies:
detect-libc "^1.0.2"
mkdirp "^0.5.1"
@@ -4562,34 +4237,17 @@ node-pre-gyp@^0.10.0:
semver "^5.3.0"
tar "^4"
-node-pre-gyp@^0.6.39:
- version "0.6.39"
- resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649"
- integrity sha512-OsJV74qxnvz/AMGgcfZoDaeDXKD3oY3QVIbBmwszTFkRisTSXbMQyn4UWzUMOtA5SVhrBZOTp0wcoSBgfMfMmQ==
- dependencies:
- detect-libc "^1.0.2"
- hawk "3.1.3"
- mkdirp "^0.5.1"
- nopt "^4.0.1"
- npmlog "^4.0.2"
- rc "^1.1.7"
- request "2.81.0"
- rimraf "^2.6.1"
- semver "^5.3.0"
- tar "^2.2.1"
- tar-pack "^3.4.0"
-
-node-releases@^1.1.8:
- version "1.1.9"
- resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.9.tgz#70d0985ec4bf7de9f08fc481f5dae111889ca482"
- integrity sha512-oic3GT4OtbWWKfRolz5Syw0Xus0KRFxeorLNj0s93ofX6PWyuzKjsiGxsCtWktBwwmTF6DdRRf2KreGqeOk5KA==
+node-releases@^1.1.17:
+ version "1.1.18"
+ resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.18.tgz#cc98fd75598a324a77188ebddf6650e9cbd8b1d5"
+ integrity sha512-/mnVgm6u/8OwlIsoyRXtTI0RfQcxZoAZbdwyXap0EeWwcOpDDymyCHM2/aR9XKmHXrvizHoPAOs0pcbiJ6RUaA==
dependencies:
semver "^5.3.0"
node-sass@^4.11.0:
- version "4.11.0"
- resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.11.0.tgz#183faec398e9cbe93ba43362e2768ca988a6369a"
- integrity sha512-bHUdHTphgQJZaF1LASx0kAviPH7sGlcyNhWade4eVIpFp6tsn7SV8xNMTbsQFpEV9VXpnwTTnNYlfsZXgGgmkA==
+ version "4.12.0"
+ resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.12.0.tgz#0914f531932380114a30cc5fa4fa63233a25f017"
+ integrity sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ==
dependencies:
async-foreach "^0.1.3"
chalk "^1.1.1"
@@ -4598,12 +4256,10 @@ node-sass@^4.11.0:
get-stdin "^4.0.1"
glob "^7.0.3"
in-publish "^2.0.0"
- lodash.assign "^4.2.0"
- lodash.clonedeep "^4.3.2"
- lodash.mergewith "^4.6.0"
+ lodash "^4.17.11"
meow "^3.7.0"
mkdirp "^0.5.1"
- nan "^2.10.0"
+ nan "^2.13.2"
node-gyp "^3.8.0"
npmlog "^4.0.0"
request "^2.88.0"
@@ -4627,12 +4283,12 @@ nopt@^4.0.1:
osenv "^0.1.4"
normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f"
- integrity sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
+ integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
dependencies:
hosted-git-info "^2.1.4"
- is-builtin-module "^1.0.0"
+ resolve "^1.10.0"
semver "2 || 3 || 4 || 5"
validate-npm-package-license "^3.0.1"
@@ -4705,17 +4361,12 @@ number-is-nan@^1.0.0:
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
-oauth-sign@~0.8.1:
- version "0.8.2"
- resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
- integrity sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=
-
oauth-sign@~0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
-object-assign@^4.0.1, object-assign@^4.1.0:
+object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
@@ -4730,14 +4381,9 @@ object-copy@^0.1.0:
kind-of "^3.0.3"
object-keys@^1.0.11, object-keys@^1.0.12:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.0.tgz#11bd22348dd2e096a045ab06f6c85bcc340fa032"
- integrity sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==
-
-object-keys@^1.0.8:
- version "1.0.11"
- resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d"
- integrity sha1-xUYBd4rVYPEULODgG8yotW0TQm0=
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
+ integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
object-visit@^1.0.0:
version "1.0.1"
@@ -4781,12 +4427,7 @@ object.values@^1.1.0:
function-bind "^1.1.1"
has "^1.0.3"
-obuf@^1.0.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.1.tgz#104124b6c602c6796881a042541d36db43a5264e"
- integrity sha1-EEEktsYCxnlogaBCVB0220OlJk4=
-
-obuf@^1.1.2:
+obuf@^1.0.0, obuf@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==
@@ -4798,22 +4439,22 @@ on-finished@~2.3.0:
dependencies:
ee-first "1.1.1"
-on-headers@~1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7"
- integrity sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=
+on-headers@~1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
+ integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
-once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0:
+once@^1.3.0, once@^1.3.1, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
dependencies:
wrappy "1"
-opn@^5.1.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/opn/-/opn-5.2.0.tgz#71fdf934d6827d676cecbea1531f95d354641225"
- integrity sha512-Jd/GpzPyHF4P2/aNOVmS3lfMSWV9J7cOhCG1s08XCEAsPkB7lp6ddiU0J7XzyQRDUh8BqJ7PchfINjR8jyofRQ==
+opn@^5.5.0:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc"
+ integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==
dependencies:
is-wsl "^1.1.0"
@@ -4864,9 +4505,9 @@ os-tmpdir@^1.0.0:
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
osenv@0, osenv@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644"
- integrity sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
+ integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
dependencies:
os-homedir "^1.0.0"
os-tmpdir "^1.0.0"
@@ -4882,9 +4523,9 @@ p-finally@^1.0.0:
integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
p-is-promise@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.0.0.tgz#7554e3d572109a87e1f3f53f6a7d85d1b194f4c5"
- integrity sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg==
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e"
+ integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==
p-limit@^2.0.0:
version "2.2.0"
@@ -4900,20 +4541,20 @@ p-locate@^3.0.0:
dependencies:
p-limit "^2.0.0"
-p-map@^1.1.1:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b"
- integrity sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==
+p-map@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175"
+ integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==
p-try@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1"
- integrity sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
+ integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
pako@~1.0.5:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258"
- integrity sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732"
+ integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==
parallel-transform@^1.1.0:
version "1.1.0"
@@ -4925,15 +4566,16 @@ parallel-transform@^1.1.0:
readable-stream "^2.1.5"
parse-asn1@^5.0.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712"
- integrity sha1-N8T5t+06tlx0gXtfJICTf7+XxxI=
+ version "5.1.4"
+ resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.4.tgz#37f6628f823fbdeb2273b4d540434a22f3ef1fcc"
+ integrity sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==
dependencies:
asn1.js "^4.0.0"
browserify-aes "^1.0.0"
create-hash "^1.1.0"
evp_bytestokey "^1.0.0"
pbkdf2 "^3.0.3"
+ safe-buffer "^5.1.1"
parse-json@^2.2.0:
version "2.2.0"
@@ -4956,9 +4598,9 @@ parse-passwd@^1.0.0:
integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=
parseurl@~1.3.2:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3"
- integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
+ integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
pascalcase@^0.1.1:
version "0.1.1"
@@ -4997,7 +4639,7 @@ path-is-absolute@^1.0.0:
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
-path-is-inside@^1.0.1:
+path-is-inside@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
@@ -5007,11 +4649,6 @@ path-key@^2.0.0, path-key@^2.0.1:
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
-path-parse@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
- integrity sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=
-
path-parse@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
@@ -5032,9 +4669,9 @@ path-type@^1.0.0:
pinkie-promise "^2.0.0"
pbkdf2@^3.0.3:
- version "3.0.14"
- resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.14.tgz#a35e13c64799b06ce15320f459c230e68e73bade"
- integrity sha512-gjsZW9O34fm0R7PaLHRJmLLVfSoesxztjPjE9o6R+qtVJij90ltg1joIovN9GKrRW3t1PzhDDG3UMEMFfZ+1wA==
+ version "3.0.17"
+ resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6"
+ integrity sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==
dependencies:
create-hash "^1.1.2"
create-hmac "^1.1.4"
@@ -5042,11 +4679,6 @@ pbkdf2@^3.0.3:
safe-buffer "^5.0.1"
sha.js "^2.4.8"
-performance-now@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
- integrity sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=
-
performance-now@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
@@ -5062,6 +4694,11 @@ pify@^3.0.0:
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
+pify@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
+ integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
+
pinkie-promise@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
@@ -5082,16 +4719,16 @@ pkg-dir@^3.0.0:
find-up "^3.0.0"
pnp-webpack-plugin@^1.3.1:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.4.1.tgz#e8f8c683b496a71c0d200e664c4bb399a9c9585e"
- integrity sha512-S4kz+5rvWvD0w1O63eTJeXIxW4JHK0wPRMO7GmPhbZXJnTePcfrWZlni4BoglIf7pLSY18xtqo3MSnVkoAFXKg==
+ version "1.4.3"
+ resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.4.3.tgz#0a100b63f4a1d09cee6ee55a87393b69f03ab5c7"
+ integrity sha512-ExrNwuFH3DudHwWY2uRMqyiCOBEDdhQYHIAsqW/CM6hIZlSgXC/ma/p08FoNOUhVyh9hl1NGnMpR94T5i3SHaQ==
dependencies:
- ts-pnp "^1.0.0"
+ ts-pnp "^1.1.2"
-portfinder@^1.0.9:
- version "1.0.13"
- resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9"
- integrity sha1-uzLs2HwnEErm7kS1o8y/Drsa7ek=
+portfinder@^1.0.20:
+ version "1.0.20"
+ resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.20.tgz#bea68632e54b2e13ab7b0c4775e9b41bf270e44a"
+ integrity sha512-Yxe4mTyDzTd59PZJY4ojZR8F+E5e97iq2ZOHPz3HDgSvYC5siNad2tLooQ5y5QHyQhc3xVqvyk/eNA3wuoa7Sw==
dependencies:
async "^1.5.2"
debug "^2.2.0"
@@ -5138,12 +4775,12 @@ postcss-color-gray@^5.0.0:
postcss-values-parser "^2.0.0"
postcss-color-hex-alpha@^5.0.2:
- version "5.0.2"
- resolved "https://registry.yarnpkg.com/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.2.tgz#e9b1886bb038daed33f6394168c210b40bb4fdb6"
- integrity sha512-8bIOzQMGdZVifoBQUJdw+yIY00omBd2EwkJXepQo9cjp1UOHHHoeRDeSzTP6vakEpaRc6GAIOfvcQR7jBYaG5Q==
+ version "5.0.3"
+ resolved "https://registry.yarnpkg.com/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.3.tgz#a8d9ca4c39d497c9661e374b9c51899ef0f87388"
+ integrity sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw==
dependencies:
- postcss "^7.0.2"
- postcss-values-parser "^2.0.0"
+ postcss "^7.0.14"
+ postcss-values-parser "^2.0.1"
postcss-color-mod-function@^3.0.3:
version "3.0.3"
@@ -5182,19 +4819,19 @@ postcss-convert-values@^4.0.1:
postcss-value-parser "^3.0.0"
postcss-custom-media@^7.0.7:
- version "7.0.7"
- resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-7.0.7.tgz#bbc698ed3089ded61aad0f5bfb1fb48bf6969e73"
- integrity sha512-bWPCdZKdH60wKOTG4HKEgxWnZVjAIVNOJDvi3lkuTa90xo/K0YHa2ZnlKLC5e2qF8qCcMQXt0yzQITBp8d0OFA==
+ version "7.0.8"
+ resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-7.0.8.tgz#fffd13ffeffad73621be5f387076a28b00294e0c"
+ integrity sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg==
dependencies:
- postcss "^7.0.5"
+ postcss "^7.0.14"
postcss-custom-properties@^8.0.9:
- version "8.0.9"
- resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-8.0.9.tgz#8943870528a6eae4c8e8d285b6ccc9fd1f97e69c"
- integrity sha512-/Lbn5GP2JkKhgUO2elMs4NnbUJcvHX4AaF5nuJDaNkd2chYW1KA5qtOGGgdkBEWcXtKSQfHXzT7C6grEVyb13w==
+ version "8.0.10"
+ resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-8.0.10.tgz#e8dc969e1e15c555f0b836b7f278ef47e3cdeaff"
+ integrity sha512-GDL0dyd7++goDR4SSasYdRNNvp4Gqy1XMzcCnTijiph7VB27XXpJ8bW/AI0i2VSBZ55TpdGhMr37kMSpRfYD0Q==
dependencies:
- postcss "^7.0.5"
- postcss-values-parser "^2.0.0"
+ postcss "^7.0.14"
+ postcss-values-parser "^2.0.1"
postcss-custom-selectors@^5.1.2:
version "5.1.2"
@@ -5718,17 +5355,12 @@ postcss-unique-selectors@^4.0.1:
postcss "^7.0.0"
uniqs "^2.0.0"
-postcss-value-parser@^3.0.0, postcss-value-parser@^3.3.1:
+postcss-value-parser@^3.0.0, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0, postcss-value-parser@^3.3.1:
version "3.3.1"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281"
integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==
-postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15"
- integrity sha1-h/OPnxj3dKSrTIojL1xc6IcqnRU=
-
-postcss-values-parser@^2.0.0:
+postcss-values-parser@^2.0.0, postcss-values-parser@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz#da8b472d901da1e205b47bdc98637b9e9e550e5f"
integrity sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg==
@@ -5738,9 +5370,9 @@ postcss-values-parser@^2.0.0:
uniq "^1.0.1"
postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.2, postcss@^7.0.5, postcss@^7.0.6:
- version "7.0.14"
- resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.14.tgz#4527ed6b1ca0d82c53ce5ec1a2041c2346bbd6e5"
- integrity sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==
+ version "7.0.16"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.16.tgz#48f64f1b4b558cb8b52c88987724359acb010da2"
+ integrity sha512-MOo8zNSlIqh22Uaa3drkdIAgUGEL+AD1ESiSdmElLUmE2uVDo1QloiT/IfW9qRw8Gw+Y/w69UVMGwbufMSftxA==
dependencies:
chalk "^2.4.2"
source-map "^0.6.1"
@@ -5766,13 +5398,13 @@ promise-inflight@^1.0.1:
resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
-proxy-addr@~2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.2.tgz#6571504f47bb988ec8180253f85dd7e14952bdec"
- integrity sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=
+proxy-addr@~2.0.4:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34"
+ integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==
dependencies:
forwarded "~0.1.2"
- ipaddr.js "1.5.2"
+ ipaddr.js "1.9.0"
prr@~1.0.1:
version "1.0.1"
@@ -5790,15 +5422,16 @@ psl@^1.1.24:
integrity sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==
public-encrypt@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6"
- integrity sha1-OfaZ86RlYN1eusvKaTyvfGXBjMY=
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0"
+ integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==
dependencies:
bn.js "^4.1.0"
browserify-rsa "^4.0.0"
create-hash "^1.1.0"
parse-asn1 "^5.0.0"
randombytes "^2.0.1"
+ safe-buffer "^5.1.2"
pump@^2.0.0:
version "2.0.1"
@@ -5817,11 +5450,11 @@ pump@^3.0.0:
once "^1.3.1"
pumpify@^1.3.3:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.4.0.tgz#80b7c5df7e24153d03f0e7ac8a05a5d068bd07fb"
- integrity sha512-2kmNR9ry+Pf45opRVirpNuIFotsxUGLaYqxIwuR77AYrYRMuFCz9eryHBS52L360O+NcR383CL4QYlMKPq4zYA==
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce"
+ integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==
dependencies:
- duplexify "^3.5.3"
+ duplexify "^3.6.0"
inherits "^2.0.3"
pump "^2.0.0"
@@ -5845,17 +5478,7 @@ q@^1.1.2:
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
-qs@6.5.1:
- version "6.5.1"
- resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
- integrity sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==
-
-qs@~6.4.0:
- version "6.4.0"
- resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
- integrity sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=
-
-qs@~6.5.2:
+qs@6.5.2, qs@~6.5.2:
version "6.5.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
@@ -5870,51 +5493,41 @@ querystring@0.2.0:
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
-querystringify@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.0.tgz#7ded8dfbf7879dcc60d0a644ac6754b283ad17ef"
- integrity sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg==
+querystringify@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e"
+ integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80"
- integrity sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
+ integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
dependencies:
safe-buffer "^5.1.0"
randomfill@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.3.tgz#b96b7df587f01dd91726c418f30553b1418e3d62"
- integrity sha512-YL6GrhrWoic0Eq8rXVbMptH7dAxCs0J+mh5Y0euNekPPYaxEmdVGim6GdoxoRzKW2yJoU8tueifS7mYxvcFDEQ==
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458"
+ integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==
dependencies:
randombytes "^2.0.5"
safe-buffer "^5.1.0"
range-parser@^1.0.3, range-parser@~1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
- integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
+ integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
-raw-body@2.3.2:
- version "2.3.2"
- resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89"
- integrity sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=
+raw-body@2.3.3:
+ version "2.3.3"
+ resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3"
+ integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==
dependencies:
bytes "3.0.0"
- http-errors "1.6.2"
- iconv-lite "0.4.19"
+ http-errors "1.6.3"
+ iconv-lite "0.4.23"
unpipe "1.0.0"
-rc@^1.1.7:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.5.tgz#275cd687f6e3b36cc756baa26dfee80a790301fd"
- integrity sha1-J1zWh/bjs2zHVrqibf7oCnkDAf0=
- dependencies:
- deep-extend "~0.4.0"
- ini "~1.3.0"
- minimist "^1.2.0"
- strip-json-comments "~2.0.1"
-
rc@^1.2.7:
version "1.2.8"
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
@@ -5949,38 +5562,28 @@ read-pkg@^1.0.0:
normalize-package-data "^2.3.2"
path-type "^1.0.0"
-"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3:
- version "2.3.4"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.4.tgz#c946c3f47fa7d8eabc0b6150f4a12f69a4574071"
- integrity sha512-vuYxeWYM+fde14+rajzqgeohAI7YoJcHE7kXDAc4Nk0EbuKnJfqtY9YtRkLo/tqkuF7MsBQRhPnPeyjYITp3ZQ==
+"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
+ version "2.3.6"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
+ integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.3"
isarray "~1.0.0"
process-nextick-args "~2.0.0"
safe-buffer "~5.1.1"
- string_decoder "~1.0.3"
+ string_decoder "~1.1.1"
util-deprecate "~1.0.1"
readable-stream@^3.0.6:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.2.0.tgz#de17f229864c120a9f56945756e4f32c4045245d"
- integrity sha512-RV20kLjdmpZuTF1INEb9IA3L68Nmi+Ri7ppZqo78wj//Pn62fCoJyV9zalccNzDD/OuJpMG4f+pfMl8+L6QdGw==
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.3.0.tgz#cb8011aad002eb717bf040291feba8569c986fb9"
+ integrity sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw==
dependencies:
inherits "^2.0.3"
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
-readdirp@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
- integrity sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=
- dependencies:
- graceful-fs "^4.1.2"
- minimatch "^3.0.2"
- readable-stream "^2.0.2"
- set-immediate-shim "^1.0.1"
-
readdirp@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525"
@@ -5998,10 +5601,10 @@ redent@^1.0.0:
indent-string "^2.1.0"
strip-indent "^1.0.1"
-regenerate-unicode-properties@^8.0.1:
- version "8.0.1"
- resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.0.1.tgz#58a4a74e736380a7ab3c5f7e03f303a941b31289"
- integrity sha512-HTjMafphaH5d5QDHuwW8Me6Hbc/GhXg8luNqTkPVwZ/oCZhnoifjWhGYsu2BzepMELTlbnoVcXvV0f+2uDDvoQ==
+regenerate-unicode-properties@^8.0.2:
+ version "8.0.2"
+ resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.0.2.tgz#7b38faa296252376d363558cfbda90c9ce709662"
+ integrity sha512-SbA/iNrBUf6Pv2zU8Ekv1Qbhv92yxL4hiDa2siuxs4KKn4oOoMDHXjAf7+Nz9qinUQ46B1LcWEi/PhJfPWpZWQ==
dependencies:
regenerate "^1.4.0"
@@ -6010,10 +5613,10 @@ regenerate@^1.4.0:
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
-regenerator-runtime@^0.12.0:
- version "0.12.1"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de"
- integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==
+regenerator-runtime@^0.13.2:
+ version "0.13.2"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447"
+ integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==
regenerator-transform@^0.13.4:
version "0.13.4"
@@ -6022,14 +5625,7 @@ regenerator-transform@^0.13.4:
dependencies:
private "^0.1.6"
-regex-not@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.0.tgz#42f83e39771622df826b02af176525d6a5f157f9"
- integrity sha1-Qvg+OXcWIt+CawKvF2Ul1qXxV/k=
- dependencies:
- extend-shallow "^2.0.1"
-
-regex-not@^1.0.2:
+regex-not@^1.0.0, regex-not@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==
@@ -6038,17 +5634,17 @@ regex-not@^1.0.2:
safe-regex "^1.1.0"
regexp-tree@^0.1.0:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.5.tgz#7cd71fca17198d04b4176efd79713f2998009397"
- integrity sha512-nUmxvfJyAODw+0B13hj8CFVAxhe7fDEAgJgaotBu3nnR+IgGgZq59YedJP5VYTlkEfqjuK6TuRpnymKdatLZfQ==
+ version "0.1.6"
+ resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.6.tgz#84900fa12fdf428a2ac25f04300382a7c0148479"
+ integrity sha512-LFrA98Dw/heXqDojz7qKFdygZmFoiVlvE1Zp7Cq2cvF+ZA+03Gmhy0k0PQlsC1jvHPiTUSs+pDHEuSWv6+6D7w==
-regexpu-core@^4.1.3, regexpu-core@^4.2.0:
- version "4.5.3"
- resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.5.3.tgz#72f572e03bb8b9f4f4d895a0ccc57e707f4af2e4"
- integrity sha512-LON8666bTAlViVEPXMv65ZqiaR3rMNLz36PIaQ7D+er5snu93k0peR7FSvO0QteYbZ3GOkvfHKbGr/B1xDu9FA==
+regexpu-core@^4.5.4:
+ version "4.5.4"
+ resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.5.4.tgz#080d9d02289aa87fe1667a4f5136bc98a6aebaae"
+ integrity sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ==
dependencies:
regenerate "^1.4.0"
- regenerate-unicode-properties "^8.0.1"
+ regenerate-unicode-properties "^8.0.2"
regjsgen "^0.5.0"
regjsparser "^0.6.0"
unicode-match-property-ecmascript "^1.0.4"
@@ -6072,9 +5668,9 @@ remove-trailing-separator@^1.0.1:
integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8=
repeat-element@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a"
- integrity sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
+ integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==
repeat-string@^1.6.1:
version "1.6.1"
@@ -6088,34 +5684,6 @@ repeating@^2.0.0:
dependencies:
is-finite "^1.0.0"
-request@2.81.0:
- version "2.81.0"
- resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
- integrity sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=
- dependencies:
- aws-sign2 "~0.6.0"
- aws4 "^1.2.1"
- caseless "~0.12.0"
- combined-stream "~1.0.5"
- extend "~3.0.0"
- forever-agent "~0.6.1"
- form-data "~2.1.1"
- har-validator "~4.2.1"
- hawk "~3.1.3"
- http-signature "~1.1.0"
- is-typedarray "~1.0.0"
- isstream "~0.1.2"
- json-stringify-safe "~5.0.1"
- mime-types "~2.1.7"
- oauth-sign "~0.8.1"
- performance-now "^0.2.0"
- qs "~6.4.0"
- safe-buffer "^5.0.1"
- stringstream "~0.0.4"
- tough-cookie "~2.3.0"
- tunnel-agent "^0.6.0"
- uuid "^3.0.0"
-
request@^2.87.0, request@^2.88.0:
version "2.88.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
@@ -6187,17 +5755,10 @@ resolve-url@^0.2.1:
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
-resolve@^1.1.7:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36"
- integrity sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==
- dependencies:
- path-parse "^1.0.5"
-
-resolve@^1.3.2, resolve@^1.8.1:
- version "1.10.0"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba"
- integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==
+resolve@^1.1.7, resolve@^1.10.0, resolve@^1.3.2, resolve@^1.8.1:
+ version "1.10.1"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.1.tgz#664842ac960795bbe758221cdccda61fb64b5f18"
+ integrity sha512-KuIe4mf++td/eFb6wkaPbMDnP6kObCaEtIDuHOUED6MNUo4K670KZUHuuvYPZDxNF0WVLw49n06M2m2dXphEzA==
dependencies:
path-parse "^1.0.6"
@@ -6216,14 +5777,7 @@ rgba-regex@^1.0.0:
resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3"
integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=
-rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.5.4, rimraf@^2.6.1:
- version "2.6.2"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
- integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==
- dependencies:
- glob "^7.0.5"
-
-rimraf@^2.6.2:
+rimraf@2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3:
version "2.6.3"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
@@ -6231,11 +5785,11 @@ rimraf@^2.6.2:
glob "^7.1.3"
ripemd160@^2.0.0, ripemd160@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7"
- integrity sha1-D0WEKVxTo2KK9+bXmsohzlfRxuc=
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
+ integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==
dependencies:
- hash-base "^2.0.0"
+ hash-base "^3.0.0"
inherits "^2.0.1"
run-queue@^1.0.0, run-queue@^1.0.3:
@@ -6245,12 +5799,7 @@ run-queue@^1.0.0, run-queue@^1.0.3:
dependencies:
aproba "^1.1.1"
-safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
- integrity sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==
-
-safe-buffer@^5.1.2:
+safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
@@ -6262,7 +5811,7 @@ safe-regex@^1.1.0:
dependencies:
ret "~0.1.10"
-"safer-buffer@>= 2.1.2 < 3":
+"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
@@ -6316,37 +5865,37 @@ select-hose@^2.0.0:
resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=
-selfsigned@^1.9.1:
- version "1.10.2"
- resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.2.tgz#b4449580d99929b65b10a48389301a6592088758"
- integrity sha1-tESVgNmZKbZbEKSDiTAaZZIIh1g=
+selfsigned@^1.10.4:
+ version "1.10.4"
+ resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.4.tgz#cdd7eccfca4ed7635d47a08bf2d5d3074092e2cd"
+ integrity sha512-9AukTiDmHXGXWtWjembZ5NDmVvP2695EtpgbCsxCa68w3c88B+alqbmZ4O3hZ4VWGXeGWzEVdvqgAJD8DQPCDw==
dependencies:
- node-forge "0.7.1"
+ node-forge "0.7.5"
-"semver@2 || 3 || 4 || 5", semver@^5.3.0:
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
- integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==
+"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0:
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b"
+ integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==
-semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0:
- version "5.6.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
- integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
+semver@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-6.0.0.tgz#05e359ee571e5ad7ed641a6eec1e547ba52dea65"
+ integrity sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ==
semver@~5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8=
-send@0.16.1:
- version "0.16.1"
- resolved "https://registry.yarnpkg.com/send/-/send-0.16.1.tgz#a70e1ca21d1382c11d0d9f6231deb281080d7ab3"
- integrity sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==
+send@0.16.2:
+ version "0.16.2"
+ resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1"
+ integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==
dependencies:
debug "2.6.9"
- depd "~1.1.1"
+ depd "~1.1.2"
destroy "~1.0.4"
- encodeurl "~1.0.1"
+ encodeurl "~1.0.2"
escape-html "~1.0.3"
etag "~1.8.1"
fresh "0.5.2"
@@ -6355,14 +5904,14 @@ send@0.16.1:
ms "2.0.0"
on-finished "~2.3.0"
range-parser "~1.2.0"
- statuses "~1.3.1"
+ statuses "~1.4.0"
serialize-javascript@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.4.0.tgz#7c958514db6ac2443a8abc062dc9f7886a7f6005"
- integrity sha1-fJWFFNtqwkQ6irwGLcn3iGp/YAU=
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.7.0.tgz#d6e0dfb2a3832a8c94468e6eb1db97e55a192a65"
+ integrity sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA==
-serve-index@^1.7.2:
+serve-index@^1.9.1:
version "1.9.1"
resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239"
integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=
@@ -6375,33 +5924,21 @@ serve-index@^1.7.2:
mime-types "~2.1.17"
parseurl "~1.3.2"
-serve-static@1.13.1:
- version "1.13.1"
- resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.1.tgz#4c57d53404a761d8f2e7c1e8a18a47dbf278a719"
- integrity sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==
+serve-static@1.13.2:
+ version "1.13.2"
+ resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1"
+ integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==
dependencies:
- encodeurl "~1.0.1"
+ encodeurl "~1.0.2"
escape-html "~1.0.3"
parseurl "~1.3.2"
- send "0.16.1"
+ send "0.16.2"
set-blocking@^2.0.0, set-blocking@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
-set-getter@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/set-getter/-/set-getter-0.1.0.tgz#d769c182c9d5a51f409145f2fba82e5e86e80376"
- integrity sha1-12nBgsnVpR9AkUXy+6guXoboA3Y=
- dependencies:
- to-object-path "^0.3.0"
-
-set-immediate-shim@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
- integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=
-
set-value@^0.4.3:
version "0.4.3"
resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1"
@@ -6427,20 +5964,15 @@ setimmediate@^1.0.4:
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=
-setprototypeof@1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04"
- integrity sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=
-
setprototypeof@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==
sha.js@^2.4.0, sha.js@^2.4.8:
- version "2.4.10"
- resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.10.tgz#b1fde5cd7d11a5626638a07c604ab909cfa31f9b"
- integrity sha512-vnwmrFDlOExK4Nm16J2KMWHLrp14lBrjxMxBJpu++EnsuBmpiYaM/MEs46Vxxm/4FvdP5yTwuCTO9it5FSjrqA==
+ version "2.4.11"
+ resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7"
+ integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==
dependencies:
inherits "^2.0.1"
safe-buffer "^5.0.1"
@@ -6495,9 +6027,9 @@ snapdragon-util@^3.0.1:
kind-of "^3.2.0"
snapdragon@^0.8.1:
- version "0.8.1"
- resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.1.tgz#e12b5487faded3e3dea0ac91e9400bf75b401370"
- integrity sha1-4StUh/re0+PeoKyR6UAL91tAE3A=
+ version "0.8.2"
+ resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d"
+ integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==
dependencies:
base "^0.11.1"
debug "^2.2.0"
@@ -6506,14 +6038,7 @@ snapdragon@^0.8.1:
map-cache "^0.2.2"
source-map "^0.5.6"
source-map-resolve "^0.5.0"
- use "^2.0.0"
-
-sntp@1.x.x:
- version "1.0.9"
- resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
- integrity sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=
- dependencies:
- hoek "2.x.x"
+ use "^3.1.0"
sockjs-client@1.3.0:
version "1.3.0"
@@ -6536,25 +6061,25 @@ sockjs@0.3.19:
uuid "^3.0.1"
source-list-map@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085"
- integrity sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
+ integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
source-map-resolve@^0.5.0:
- version "0.5.1"
- resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.1.tgz#7ad0f593f2281598e854df80f19aae4b92d7a11a"
- integrity sha512-0KW2wvzfxm8NCTb30z0LMNyPqWCdDGE2viwzUaucqJdkTRXtZiSY3I+2A6nVAjmdOy0I4gU8DwnVVGsk9jvP2A==
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259"
+ integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==
dependencies:
- atob "^2.0.0"
+ atob "^2.1.1"
decode-uri-component "^0.2.0"
resolve-url "^0.2.1"
source-map-url "^0.4.0"
urix "^0.1.0"
-source-map-support@~0.5.9:
- version "0.5.10"
- resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.10.tgz#2214080bc9d51832511ee2bab96e3c2f9353120c"
- integrity sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==
+source-map-support@~0.5.10:
+ version "0.5.12"
+ resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599"
+ integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
@@ -6586,22 +6111,31 @@ spark-md5@^3.0.0:
resolved "https://registry.yarnpkg.com/spark-md5/-/spark-md5-3.0.0.tgz#3722227c54e2faf24b1dc6d933cc144e6f71bfef"
integrity sha1-NyIifFTi+vJLHcbZM8wUTm9xv+8=
-spdx-correct@~1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40"
- integrity sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=
+spdx-correct@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4"
+ integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==
dependencies:
- spdx-license-ids "^1.0.2"
+ spdx-expression-parse "^3.0.0"
+ spdx-license-ids "^3.0.0"
-spdx-expression-parse@~1.0.0:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c"
- integrity sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=
+spdx-exceptions@^2.1.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977"
+ integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==
-spdx-license-ids@^1.0.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57"
- integrity sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=
+spdx-expression-parse@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0"
+ integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==
+ dependencies:
+ spdx-exceptions "^2.1.0"
+ spdx-license-ids "^3.0.0"
+
+spdx-license-ids@^3.0.0:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz#75ecd1a88de8c184ef015eafb51b5b48bfd11bb1"
+ integrity sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==
spdy-transport@^3.0.0:
version "3.0.0"
@@ -6639,18 +6173,18 @@ sprintf-js@~1.0.2:
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
sshpk@^1.7.0:
- version "1.13.1"
- resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3"
- integrity sha1-US322mKHFEMW3EwY/hzx2UBzm+M=
+ version "1.16.1"
+ resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
+ integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
dependencies:
asn1 "~0.2.3"
assert-plus "^1.0.0"
- dashdash "^1.12.0"
- getpass "^0.1.1"
- optionalDependencies:
bcrypt-pbkdf "^1.0.0"
+ dashdash "^1.12.0"
ecc-jsbn "~0.1.1"
+ getpass "^0.1.1"
jsbn "~0.1.0"
+ safer-buffer "^2.0.2"
tweetnacl "~0.14.0"
ssri@^6.0.1:
@@ -6673,47 +6207,47 @@ static-extend@^0.1.1:
define-property "^0.2.5"
object-copy "^0.1.0"
-"statuses@>= 1.3.1 < 2":
+"statuses@>= 1.4.0 < 2":
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
+ integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
+
+statuses@~1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==
-statuses@~1.3.1:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e"
- integrity sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=
-
stdout-stream@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.0.tgz#a2c7c8587e54d9427ea9edb3ac3f2cd522df378b"
- integrity sha1-osfIWH5U2UJ+qe2zrD8s1SLfN4s=
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.1.tgz#5ac174cdd5cd726104aa0c0b2bd83815d8d535de"
+ integrity sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==
dependencies:
readable-stream "^2.0.1"
stream-browserify@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"
- integrity sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b"
+ integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==
dependencies:
inherits "~2.0.1"
readable-stream "^2.0.2"
stream-each@^1.1.0:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.2.tgz#8e8c463f91da8991778765873fe4d960d8f616bd"
- integrity sha512-mc1dbFhGBxvTM3bIWmAAINbqiuAk9TATcfIQC8P+/+HJefgaiTlMn2dHvkX8qlI12KeYKSQ1Ua9RrIqrn1VPoA==
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae"
+ integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==
dependencies:
end-of-stream "^1.1.0"
stream-shift "^1.0.0"
stream-http@^2.7.2:
- version "2.8.0"
- resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.0.tgz#fd86546dac9b1c91aff8fc5d287b98fafb41bc10"
- integrity sha512-sZOFxI/5xw058XIRHl4dU3dZ+TTOIGJR78Dvo0oEAejIt4ou27k+3ne1zYmCV+v7UucbxIFQuOgnkTVHh8YPnw==
+ version "2.8.3"
+ resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc"
+ integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==
dependencies:
builtin-status-codes "^3.0.0"
inherits "^2.0.1"
- readable-stream "^2.3.3"
+ readable-stream "^2.3.6"
to-arraybuffer "^1.0.0"
xtend "^4.0.0"
@@ -6731,7 +6265,7 @@ string-width@^1.0.1, string-width@^1.0.2:
is-fullwidth-code-point "^1.0.0"
strip-ansi "^3.0.0"
-string-width@^2.0.0, string-width@^2.1.1:
+"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
@@ -6739,24 +6273,19 @@ string-width@^2.0.0, string-width@^2.1.1:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^4.0.0"
-string_decoder@^1.0.0, string_decoder@~1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab"
- integrity sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==
- dependencies:
- safe-buffer "~5.1.0"
-
-string_decoder@^1.1.1:
+string_decoder@^1.0.0, string_decoder@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d"
integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==
dependencies:
safe-buffer "~5.1.0"
-stringstream@~0.0.4:
- version "0.0.5"
- resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
- integrity sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=
+string_decoder@~1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
+ integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
+ dependencies:
+ safe-buffer "~5.1.0"
strip-ansi@^3.0.0, strip-ansi@^3.0.1:
version "3.0.1"
@@ -6833,9 +6362,9 @@ supports-color@^6.1.0:
has-flag "^3.0.0"
svgo@^1.0.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.2.0.tgz#305a8fc0f4f9710828c65039bb93d5793225ffc3"
- integrity sha512-xBfxJxfk4UeVN8asec9jNxHiv3UAMv/ujwBWGYvQhhMb2u3YTGKkiybPcLFDLq7GLLWE9wa73e0/m8L5nTzQbw==
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.2.2.tgz#0253d34eccf2aed4ad4f283e11ee75198f9d7316"
+ integrity sha512-rAfulcwp2D9jjdGu+0CuqlrAUin6bBWrpoqXWwKDZZZJfXcUXQSxLJOFJCQCSA0x0pP2U0TxSlJu2ROq5Bq6qA==
dependencies:
chalk "^2.4.1"
coa "^2.0.2"
@@ -6844,7 +6373,7 @@ svgo@^1.0.0:
css-tree "1.0.0-alpha.28"
css-url-regex "^1.1.0"
csso "^3.5.1"
- js-yaml "^3.12.0"
+ js-yaml "^3.13.1"
mkdirp "~0.5.1"
object.values "^1.1.0"
sax "~1.2.4"
@@ -6853,25 +6382,11 @@ svgo@^1.0.0:
util.promisify "~1.0.0"
tapable@^1.0.0, tapable@^1.1.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.1.tgz#4d297923c5a72a42360de2ab52dadfaaec00018e"
- integrity sha512-9I2ydhj8Z9veORCw5PRm4u9uebCn0mcCa6scWoNcbZ6dAtoo2618u9UUzxgmsCOreJpqDDuv61LvwofW7hLcBA==
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
+ integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
-tar-pack@^3.4.0:
- version "3.4.1"
- resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f"
- integrity sha512-PPRybI9+jM5tjtCbN2cxmmRU7YmqT3Zv/UDy48tAh2XRkLa9bAORtSWLkVc13+GJF+cdTh1yEnHEk3cpTaL5Kg==
- dependencies:
- debug "^2.2.0"
- fstream "^1.0.10"
- fstream-ignore "^1.0.5"
- once "^1.3.3"
- readable-stream "^2.1.4"
- rimraf "^2.5.1"
- tar "^2.2.1"
- uid-number "^0.0.6"
-
-tar@^2.0.0, tar@^2.2.1:
+tar@^2.0.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
integrity sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=
@@ -6908,31 +6423,31 @@ terser-webpack-plugin@^1.1.0, terser-webpack-plugin@^1.2.3:
worker-farm "^1.5.2"
terser@^3.16.1:
- version "3.16.1"
- resolved "https://registry.yarnpkg.com/terser/-/terser-3.16.1.tgz#5b0dd4fa1ffd0b0b43c2493b2c364fd179160493"
- integrity sha512-JDJjgleBROeek2iBcSNzOHLKsB/MdDf+E/BOAJ0Tk9r7p9/fVobfv7LMJ/g/k3v9SXdmjZnIlFd5nfn/Rt0Xow==
+ version "3.17.0"
+ resolved "https://registry.yarnpkg.com/terser/-/terser-3.17.0.tgz#f88ffbeda0deb5637f9d24b0da66f4e15ab10cb2"
+ integrity sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ==
dependencies:
- commander "~2.17.1"
+ commander "^2.19.0"
source-map "~0.6.1"
- source-map-support "~0.5.9"
+ source-map-support "~0.5.10"
through2@^2.0.0:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be"
- integrity sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
+ integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
dependencies:
- readable-stream "^2.1.5"
+ readable-stream "~2.3.6"
xtend "~4.0.1"
thunky@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.2.tgz#a862e018e3fb1ea2ec3fce5d55605cf57f247371"
- integrity sha1-qGLgGOP7HqLsP85dVWBc9X8kc3E=
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.3.tgz#f5df732453407b09191dae73e2a8cc73f381a826"
+ integrity sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow==
timers-browserify@^2.0.4:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.6.tgz#241e76927d9ca05f4d959819022f5b3664b64bae"
- integrity sha512-HQ3nbYRAowdVd0ckGFvmJPPCOH/CHleFN/Y0YQCX1DVaB7t+KFvisuyN09fuP8Jtp1CpfSh8O8bMkHbdbPe6Pw==
+ version "2.0.10"
+ resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae"
+ integrity sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==
dependencies:
setimmediate "^1.0.4"
@@ -6966,16 +6481,7 @@ to-regex-range@^2.1.0:
is-number "^3.0.0"
repeat-string "^1.6.1"
-to-regex@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.1.tgz#15358bee4a2c83bd76377ba1dc049d0f18837aae"
- integrity sha1-FTWL7kosg712N3uh3ASdDxiDeq4=
- dependencies:
- define-property "^0.2.5"
- extend-shallow "^2.0.1"
- regex-not "^1.0.0"
-
-to-regex@^3.0.2:
+to-regex@^3.0.1, to-regex@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==
@@ -6985,13 +6491,6 @@ to-regex@^3.0.2:
regex-not "^1.0.2"
safe-regex "^1.1.0"
-tough-cookie@~2.3.0:
- version "2.3.3"
- resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561"
- integrity sha1-C2GKVWW23qkL80JdBNVe3EdadWE=
- dependencies:
- punycode "^1.4.1"
-
tough-cookie@~2.4.3:
version "2.4.3"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
@@ -7010,17 +6509,22 @@ trim-right@^1.0.1:
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=
+trix@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/trix/-/trix-1.1.1.tgz#ca8a3fab4d23d960a17e88441d601cb22a86f5d5"
+ integrity sha512-dNHTcryRK0EmwCyJDOBrG6OznL8HNEVVlecq/xzxLj3M9Eht5DV4yl+eCYX8RKyfrtBcNki+mpKIxESgXaGGZA==
+
"true-case-path@^1.0.2":
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.2.tgz#7ec91130924766c7f573be3020c34f8fdfd00d62"
- integrity sha1-fskRMJJHZsf1c74wIMNPj9/QDWI=
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.3.tgz#f813b5a8c86b40da59606722b144e3225799f47d"
+ integrity sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==
dependencies:
- glob "^6.0.4"
+ glob "^7.1.2"
-ts-pnp@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.0.1.tgz#fde74a6371676a167abaeda1ffc0fdb423520098"
- integrity sha512-Zzg9XH0anaqhNSlDRibNC8Kp+B9KNM0uRIpLpGkGyrgRIttA7zZBhotTSEoEyuDrz3QW2LGtu2dxuk34HzIGnQ==
+ts-pnp@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.1.2.tgz#be8e4bfce5d00f0f58e0666a82260c34a57af552"
+ integrity sha512-f5Knjh7XCyRIzoC/z1Su1yLLRrPrFCgtUAh/9fCSP6NKbATwpOL1+idQVXQokK9GRFURn/jYPGPfegIctwunoA==
tslib@^1.9.0:
version "1.9.3"
@@ -7044,29 +6548,19 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0:
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
-type-is@~1.6.15:
- version "1.6.15"
- resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410"
- integrity sha1-yrEPtJCeRByChC6v4a1kbIGARBA=
+type-is@~1.6.16:
+ version "1.6.18"
+ resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
+ integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
dependencies:
media-typer "0.3.0"
- mime-types "~2.1.15"
+ mime-types "~2.1.24"
typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
-uid-number@^0.0.6:
- version "0.0.6"
- resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
- integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=
-
-underscore.string@2.3.x:
- version "2.3.3"
- resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.3.3.tgz#71c08bf6b428b1133f37e78fa3a21c82f7329b0d"
- integrity sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=
-
unicode-canonical-property-names-ecmascript@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818"
@@ -7118,9 +6612,9 @@ unique-filename@^1.1.1:
unique-slug "^2.0.0"
unique-slug@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab"
- integrity sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.1.tgz#5e9edc6d1ce8fb264db18a507ef9bd8544451ca6"
+ integrity sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg==
dependencies:
imurmurhash "^0.1.4"
@@ -7142,18 +6636,10 @@ unset-value@^1.0.0:
has-value "^0.3.1"
isobject "^3.0.0"
-upath@1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/upath/-/upath-1.0.0.tgz#b4706b9461ca8473adf89133d235689ca17f3656"
- integrity sha1-tHBrlGHKhHOt+JEz0jVonKF/NlY=
- dependencies:
- lodash "3.x"
- underscore.string "2.3.x"
-
-upath@^1.1.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.1.tgz#497f7c1090b0818f310bbfb06783586a68d28014"
- integrity sha512-D0yetkpIOKiZQquxjM2Syvy48Y1DbZ0SWxgsZiwd9GCWRpc75vN8ytzem14WDSg+oiX6+Qt31FpiS/ExODCrLg==
+upath@^1.1.1:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068"
+ integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==
uri-js@^4.2.2:
version "4.2.2"
@@ -7168,11 +6654,11 @@ urix@^0.1.0:
integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
url-parse@^1.4.3:
- version "1.4.4"
- resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.4.tgz#cac1556e95faa0303691fec5cf9d5a1bc34648f8"
- integrity sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==
+ version "1.4.7"
+ resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278"
+ integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==
dependencies:
- querystringify "^2.0.0"
+ querystringify "^2.1.1"
requires-port "^1.0.0"
url@^0.11.0:
@@ -7183,14 +6669,10 @@ url@^0.11.0:
punycode "1.3.2"
querystring "0.2.0"
-use@^2.0.0:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/use/-/use-2.0.2.tgz#ae28a0d72f93bf22422a18a2e379993112dec8e8"
- integrity sha1-riig1y+TvyJCKhii43mZMRLeyOg=
- dependencies:
- define-property "^0.2.5"
- isobject "^3.0.0"
- lazy-cache "^2.0.2"
+use@^3.1.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
+ integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
util-deprecate@^1.0.1, util-deprecate@~1.0.1:
version "1.0.2"
@@ -7205,40 +6687,42 @@ util.promisify@^1.0.0, util.promisify@~1.0.0:
define-properties "^1.1.2"
object.getownpropertydescriptors "^2.0.3"
-util@0.10.3, util@^0.10.3:
+util@0.10.3:
version "0.10.3"
resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk=
dependencies:
inherits "2.0.1"
+util@^0.11.0:
+ version "0.11.1"
+ resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61"
+ integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==
+ dependencies:
+ inherits "2.0.3"
+
utils-merge@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
-uuid@^3.0.0, uuid@^3.0.1:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14"
- integrity sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==
-
-uuid@^3.3.2:
+uuid@^3.0.1, uuid@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
v8-compile-cache@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz#a428b28bb26790734c4fc8bc9fa106fccebf6a6c"
- integrity sha512-1wFuMUIM16MDJRCrpbpuEPTUGmM5QMUg0cr3KFwra2XgOgFcPGDQHDh3CszSCD2Zewc/dh/pamNEW8CbfDebUw==
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe"
+ integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==
validate-npm-package-license@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc"
- integrity sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
+ integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
dependencies:
- spdx-correct "~1.0.0"
- spdx-expression-parse "~1.0.0"
+ spdx-correct "^3.0.0"
+ spdx-expression-parse "^3.0.0"
vary@~1.1.2:
version "1.1.2"
@@ -7246,9 +6730,9 @@ vary@~1.1.2:
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
vendors@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.1.tgz#37ad73c8ee417fb3d580e785312307d274847f22"
- integrity sha1-N61zyO5Bf7PVgOeFMSMH0nSEfyI=
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.3.tgz#a6467781abd366217c050f8202e7e50cc9eef8c0"
+ integrity sha512-fOi47nsJP5Wqefa43kyWSg80qF+Q3XA6MUkgi7Hp1HQaKDQW4cQrK2D0P7mmbFtsV1N89am55Yru/nyEwRubcw==
verror@1.10.0:
version "1.10.0"
@@ -7275,14 +6759,7 @@ watchpack@^1.5.0:
graceful-fs "^4.1.2"
neo-async "^2.5.0"
-wbuf@^1.1.0:
- version "1.7.2"
- resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.2.tgz#d697b99f1f59512df2751be42769c1580b5801fe"
- integrity sha1-1pe5nx9ZUS3ydRvkJ2nBWAtYAf4=
- dependencies:
- minimalistic-assert "^1.0.0"
-
-wbuf@^1.7.3:
+wbuf@^1.1.0, wbuf@^1.7.3:
version "1.7.3"
resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df"
integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==
@@ -7303,9 +6780,9 @@ webpack-assets-manifest@^3.1.1:
webpack-sources "^1.0.0"
webpack-cli@^3.2.3:
- version "3.2.3"
- resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.2.3.tgz#13653549adfd8ccd920ad7be1ef868bacc22e346"
- integrity sha512-Ik3SjV6uJtWIAN5jp5ZuBMWEAaP5E4V78XJ2nI+paFPh8v4HPSwo/myN0r29Xc/6ZKnd2IdrAlpSgNOu2CDQ6Q==
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.2.tgz#aed2437b0db0a7faa2ad28484e166a5360014a91"
+ integrity sha512-FLkobnaJJ+03j5eplxlI0TUxhGCOdfewspIGuvDVtpOlrAuKMFC57K42Ukxqs1tn8947/PM6tP95gQc0DCzRYA==
dependencies:
chalk "^2.4.1"
cross-spawn "^6.0.5"
@@ -7317,53 +6794,53 @@ webpack-cli@^3.2.3:
loader-utils "^1.1.0"
supports-color "^5.5.0"
v8-compile-cache "^2.0.2"
- yargs "^12.0.4"
+ yargs "^12.0.5"
-webpack-dev-middleware@^3.5.1:
- version "3.6.1"
- resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.6.1.tgz#91f2531218a633a99189f7de36045a331a4b9cd4"
- integrity sha512-XQmemun8QJexMEvNFbD2BIg4eSKrmSIMrTfnl2nql2Sc6OGAYFyb8rwuYrCjl/IiEYYuyTEiimMscu7EXji/Dw==
+webpack-dev-middleware@^3.6.2:
+ version "3.6.2"
+ resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.6.2.tgz#f37a27ad7c09cd7dc67cd97655413abaa1f55942"
+ integrity sha512-A47I5SX60IkHrMmZUlB0ZKSWi29TZTcPz7cha1Z75yYOsgWh/1AcPmQEbC8ZIbU3A1ytSv1PMU0PyPz2Lmz2jg==
dependencies:
memory-fs "^0.4.1"
mime "^2.3.1"
range-parser "^1.0.3"
webpack-log "^2.0.0"
-webpack-dev-server@^3.2.1:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.2.1.tgz#1b45ce3ecfc55b6ebe5e36dab2777c02bc508c4e"
- integrity sha512-sjuE4mnmx6JOh9kvSbPYw3u/6uxCLHNWfhWaIPwcXWsvWOPN+nc5baq4i9jui3oOBRXGonK9+OI0jVkaz6/rCw==
+webpack-dev-server@^3.3.1:
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.3.1.tgz#7046e49ded5c1255a82c5d942bcdda552b72a62d"
+ integrity sha512-jY09LikOyGZrxVTXK0mgIq9y2IhCoJ05848dKZqX1gAGLU1YDqgpOT71+W53JH/wI4v6ky4hm+KvSyW14JEs5A==
dependencies:
ansi-html "0.0.7"
bonjour "^3.5.0"
- chokidar "^2.0.0"
- compression "^1.5.2"
- connect-history-api-fallback "^1.3.0"
+ chokidar "^2.1.5"
+ compression "^1.7.4"
+ connect-history-api-fallback "^1.6.0"
debug "^4.1.1"
- del "^3.0.0"
- express "^4.16.2"
- html-entities "^1.2.0"
+ del "^4.1.0"
+ express "^4.16.4"
+ html-entities "^1.2.1"
http-proxy-middleware "^0.19.1"
import-local "^2.0.0"
internal-ip "^4.2.0"
ip "^1.1.5"
- killable "^1.0.0"
- loglevel "^1.4.1"
- opn "^5.1.0"
- portfinder "^1.0.9"
+ killable "^1.0.1"
+ loglevel "^1.6.1"
+ opn "^5.5.0"
+ portfinder "^1.0.20"
schema-utils "^1.0.0"
- selfsigned "^1.9.1"
- semver "^5.6.0"
- serve-index "^1.7.2"
+ selfsigned "^1.10.4"
+ semver "^6.0.0"
+ serve-index "^1.9.1"
sockjs "0.3.19"
sockjs-client "1.3.0"
spdy "^4.0.0"
- strip-ansi "^3.0.0"
+ strip-ansi "^3.0.1"
supports-color "^6.1.0"
url "^0.11.0"
- webpack-dev-middleware "^3.5.1"
+ webpack-dev-middleware "^3.6.2"
webpack-log "^2.0.0"
- yargs "12.0.2"
+ yargs "12.0.5"
webpack-log@^2.0.0:
version "2.0.0"
@@ -7373,7 +6850,7 @@ webpack-log@^2.0.0:
ansi-colors "^3.0.0"
uuid "^3.3.2"
-webpack-sources@^1.0.0, webpack-sources@^1.3.0:
+webpack-sources@^1.0.0, webpack-sources@^1.0.1, webpack-sources@^1.1.0, webpack-sources@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85"
integrity sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==
@@ -7381,18 +6858,10 @@ webpack-sources@^1.0.0, webpack-sources@^1.3.0:
source-list-map "^2.0.0"
source-map "~0.6.1"
-webpack-sources@^1.0.1, webpack-sources@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54"
- integrity sha512-aqYp18kPphgoO5c/+NaUvEeACtZjMESmDChuD3NBciVpah3XpMEU9VAAtIaB1BsfJWWTSdv8Vv1m3T0aRk2dUw==
- dependencies:
- source-list-map "^2.0.0"
- source-map "~0.6.1"
-
webpack@^4.29.6:
- version "4.29.6"
- resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.29.6.tgz#66bf0ec8beee4d469f8b598d3988ff9d8d90e955"
- integrity sha512-MwBwpiE1BQpMDkbnUUaW6K8RFZjljJHArC6tWQJoFm0oQtfoSebtg4Y7/QHnJ/SddtjYLHaKGX64CFjG5rehJw==
+ version "4.31.0"
+ resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.31.0.tgz#ae201d45f0571336e42d1c2b5c8ab56c4d3b0c63"
+ integrity sha512-n6RVO3X0LbbipoE62akME9K/JI7qYrwwufs20VvgNNpqUoH4860KkaxJTbGq5bgkVZF9FqyyTG/0WPLH3PVNJA==
dependencies:
"@webassemblyjs/ast" "1.8.5"
"@webassemblyjs/helper-module-context" "1.8.5"
@@ -7442,14 +6911,7 @@ which-module@^2.0.0:
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
-which@1, which@^1.2.9:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a"
- integrity sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==
- dependencies:
- isexe "^2.0.0"
-
-which@^1.2.14:
+which@1, which@^1.2.14, which@^1.2.9:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
@@ -7457,19 +6919,18 @@ which@^1.2.14:
isexe "^2.0.0"
wide-align@^1.1.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710"
- integrity sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
+ integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==
dependencies:
- string-width "^1.0.2"
+ string-width "^1.0.2 || 2"
worker-farm@^1.5.2:
- version "1.5.2"
- resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.5.2.tgz#32b312e5dc3d5d45d79ef44acc2587491cd729ae"
- integrity sha512-XxiQ9kZN5n6mmnW+mFJ+wXjNNI/Nx4DIdaAKLX1Bn6LYBWlN/zaBhu34DQYPZ1AJobQuu67S2OfDdNSVULvXkQ==
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8"
+ integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==
dependencies:
- errno "^0.1.4"
- xtend "^4.0.1"
+ errno "~0.1.7"
wrap-ansi@^2.0.0:
version "2.1.0"
@@ -7484,12 +6945,7 @@ wrappy@1:
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
-xregexp@4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020"
- integrity sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg==
-
-xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
+xtend@^4.0.0, xtend@~4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68=
@@ -7514,13 +6970,6 @@ yallist@^3.0.0, yallist@^3.0.2:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==
-yargs-parser@^10.1.0:
- version "10.1.0"
- resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8"
- integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==
- dependencies:
- camelcase "^4.1.0"
-
yargs-parser@^11.1.1:
version "11.1.1"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4"
@@ -7536,25 +6985,7 @@ yargs-parser@^5.0.0:
dependencies:
camelcase "^3.0.0"
-yargs@12.0.2:
- version "12.0.2"
- resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.2.tgz#fe58234369392af33ecbef53819171eff0f5aadc"
- integrity sha512-e7SkEx6N6SIZ5c5H22RTZae61qtn3PYUE8JYbBFlK9sYmh3DMQ6E5ygtaG/2BW0JZi4WGgTR2IV5ChqlqrDGVQ==
- dependencies:
- cliui "^4.0.0"
- decamelize "^2.0.0"
- find-up "^3.0.0"
- get-caller-file "^1.0.1"
- os-locale "^3.0.0"
- require-directory "^2.1.1"
- require-main-filename "^1.0.1"
- set-blocking "^2.0.0"
- string-width "^2.0.0"
- which-module "^2.0.0"
- y18n "^3.2.1 || ^4.0.0"
- yargs-parser "^10.1.0"
-
-yargs@^12.0.4:
+yargs@12.0.5, yargs@^12.0.5:
version "12.0.5"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13"
integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==
diff --git a/actiontext/test/system/system_test_helper_test.rb b/actiontext/test/system/system_test_helper_test.rb
new file mode 100644
index 0000000000..2a57fa8d88
--- /dev/null
+++ b/actiontext/test/system/system_test_helper_test.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require "application_system_test_case"
+
+class ActionText::SystemTestHelperTest < ApplicationSystemTestCase
+ test "filling in a rich-text area by ID" do
+ visit new_message_url
+ assert_selector "trix-editor#message_content"
+ fill_in_rich_text_area "message_content", with: "Hello world!"
+ assert_selector :field, "message[content]", with: /Hello world!/, type: "hidden"
+ end
+
+ test "filling in a rich-text area by placeholder" do
+ visit new_message_url
+ assert_selector "trix-editor[placeholder='Your message here']"
+ fill_in_rich_text_area "Your message here", with: "Hello world!"
+ assert_selector :field, "message[content]", with: /Hello world!/, type: "hidden"
+ end
+
+ test "filling in a rich-text area by aria-label" do
+ visit new_message_url
+ assert_selector "trix-editor[aria-label='Message content']"
+ fill_in_rich_text_area "Message content", with: "Hello world!"
+ assert_selector :field, "message[content]", with: /Hello world!/, type: "hidden"
+ end
+
+ test "filling in a rich-text area by input name" do
+ visit new_message_url
+ assert_selector "trix-editor[input]"
+ fill_in_rich_text_area "message[content]", with: "Hello world!"
+ assert_selector :field, "message[content]", with: /Hello world!/, type: "hidden"
+ end
+
+ test "filling in the only rich-text area" do
+ visit new_message_url
+ fill_in_rich_text_area with: "Hello world!"
+ assert_selector :field, "message[content]", with: /Hello world!/, type: "hidden"
+ end
+end
diff --git a/actiontext/test/unit/attachment_test.rb b/actiontext/test/unit/attachment_test.rb
index 026078dcec..54831a0271 100644
--- a/actiontext/test/unit/attachment_test.rb
+++ b/actiontext/test/unit/attachment_test.rb
@@ -50,6 +50,11 @@ class ActionText::AttachmentTest < ActiveSupport::TestCase
assert_not_nil trix_attachment.attributes["content"]
end
+ test "converts to plain text" do
+ assert_equal "[Vroom vroom]", ActionText::Attachment.from_attachable(attachable, caption: "Vroom vroom").to_plain_text
+ assert_equal "[racecar.jpg]", ActionText::Attachment.from_attachable(attachable).to_plain_text
+ end
+
test "defaults trix partial to model partial" do
attachable = Page.create! title: "Homepage"
assert_equal "pages/page", attachable.to_trix_content_attachment_partial_path
diff --git a/actiontext/test/unit/model_test.rb b/actiontext/test/unit/model_test.rb
index af53f88caa..c2c3ccaaec 100644
--- a/actiontext/test/unit/model_test.rb
+++ b/actiontext/test/unit/model_test.rb
@@ -44,6 +44,15 @@ class ActionText::ModelTest < ActiveSupport::TestCase
assert_equal [ActiveStorage::Attachment], message.content.embeds.map(&:class)
end
+ test "embed extraction deduplicates file attachments" do
+ blob = create_file_blob(filename: "racecar.jpg", content_type: "image/jpg")
+ content = ActionText::Content.new("Hello world").append_attachables([ blob, blob ])
+
+ assert_nothing_raised do
+ Message.create!(subject: "Greetings", content: content)
+ end
+ end
+
test "saving content" do
message = Message.create!(subject: "Greetings", content: "<h1>Hello world</h1>")
assert_equal "Hello world", message.content.to_plain_text
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index dcd3e33c46..504b1d3e98 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -1,3 +1,19 @@
+* annotated_source_code returns an empty array so TemplateErrors without a
+ template in the backtrace are surfaced properly by DebugExceptions.
+
+ *Guilherme Mansur*, *Kasper Timm Hansen*
+
+* Add autoload for SyntaxErrorInTemplate so syntax errors are correctly raised by DebugExceptions.
+
+ *Guilherme Mansur*, *Gannon McGibbon*
+
+* `RenderingHelper` supports rendering objects that `respond_to?` `:render_in`
+
+ *Joel Hawksley*, *Natasha Umer*, *Aaron Patterson*, *Shawn Allen*, *Emily Plummer*, *Diana Mounter*, *John Hawthorn*, *Nathan Herald*, *Zaid Zawaideh*, *Zach Ahn*
+
+* Fix `select_tag` so that it doesn't change `options` when `include_blank` is present.
+
+ *Younes SERRAJ*
Please check [6-0-stable](https://github.com/rails/rails/blob/6-0-stable/actionview/CHANGELOG.md) for previous changes.
diff --git a/actionview/app/assets/javascripts/README.md b/actionview/app/assets/javascripts/README.md
index aa167004b6..c9282ba76f 100644
--- a/actionview/app/assets/javascripts/README.md
+++ b/actionview/app/assets/javascripts/README.md
@@ -15,7 +15,7 @@ Note that the `data` attributes this library adds are a feature of HTML5. If you
## Installation
-### NPM
+### npm
npm install @rails/ujs --save
diff --git a/actionview/app/assets/javascripts/rails-ujs/features/remote.coffee b/actionview/app/assets/javascripts/rails-ujs/features/remote.coffee
index a5b61220bb..d1aeef56c7 100644
--- a/actionview/app/assets/javascripts/rails-ujs/features/remote.coffee
+++ b/actionview/app/assets/javascripts/rails-ujs/features/remote.coffee
@@ -88,6 +88,6 @@ Rails.preventInsignificantClick = (e) ->
data = link.getAttribute('data-params')
metaClick = e.metaKey or e.ctrlKey
insignificantMetaClick = metaClick and method is 'GET' and not data
- primaryMouseKey = e.button is 0
- e.stopImmediatePropagation() if not primaryMouseKey or insignificantMetaClick
+ nonPrimaryMouseClick = e.button? and e.button isnt 0
+ e.stopImmediatePropagation() if nonPrimaryMouseClick or insignificantMetaClick
diff --git a/actionview/lib/action_view.rb b/actionview/lib/action_view.rb
index 7f85bf2a5e..11b4563548 100644
--- a/actionview/lib/action_view.rb
+++ b/actionview/lib/action_view.rb
@@ -77,6 +77,7 @@ module ActionView
autoload :ActionViewError
autoload :EncodingError
autoload :TemplateError
+ autoload :SyntaxErrorInTemplate
autoload :WrongEncodingError
end
end
diff --git a/actionview/lib/action_view/base.rb b/actionview/lib/action_view/base.rb
index 5253ef7b0c..40d5ed36a1 100644
--- a/actionview/lib/action_view/base.rb
+++ b/actionview/lib/action_view/base.rb
@@ -3,7 +3,6 @@
require "active_support/core_ext/module/attr_internal"
require "active_support/core_ext/module/attribute_accessors"
require "active_support/ordered_options"
-require "active_support/deprecation"
require "action_view/log_subscriber"
require "action_view/helpers"
require "action_view/context"
diff --git a/actionview/lib/action_view/cache_expiry.rb b/actionview/lib/action_view/cache_expiry.rb
index 820afc093d..27690561b7 100644
--- a/actionview/lib/action_view/cache_expiry.rb
+++ b/actionview/lib/action_view/cache_expiry.rb
@@ -16,18 +16,23 @@ module ActionView
@watched_dirs = nil
@watcher_class = watcher
@watcher = nil
+ @mutex = Mutex.new
end
def clear_cache_if_necessary
- watched_dirs = dirs_to_watch
- if watched_dirs != @watched_dirs
- @watched_dirs = watched_dirs
- @watcher = @watcher_class.new([], watched_dirs) do
- clear_cache
+ @mutex.synchronize do
+ watched_dirs = dirs_to_watch
+ return if watched_dirs.empty?
+
+ if watched_dirs != @watched_dirs
+ @watched_dirs = watched_dirs
+ @watcher = @watcher_class.new([], watched_dirs) do
+ clear_cache
+ end
+ @watcher.execute
+ else
+ @watcher.execute_if_updated
end
- @watcher.execute
- else
- @watcher.execute_if_updated
end
end
@@ -36,7 +41,6 @@ module ActionView
end
private
-
def dirs_to_watch
fs_paths = all_view_paths.grep(FileSystemResolver)
fs_paths.map(&:path).sort.uniq
diff --git a/actionview/lib/action_view/flows.rb b/actionview/lib/action_view/flows.rb
index ff44fa6619..1609777182 100644
--- a/actionview/lib/action_view/flows.rb
+++ b/actionview/lib/action_view/flows.rb
@@ -68,7 +68,6 @@ module ActionView
end
private
-
def inside_fiber?
Fiber.current.object_id != @root
end
diff --git a/actionview/lib/action_view/helpers/active_model_helper.rb b/actionview/lib/action_view/helpers/active_model_helper.rb
index e41a95d2ce..e8f1d4fee5 100644
--- a/actionview/lib/action_view/helpers/active_model_helper.rb
+++ b/actionview/lib/action_view/helpers/active_model_helper.rb
@@ -38,7 +38,6 @@ module ActionView
end
private
-
def object_has_errors?
object.respond_to?(:errors) && object.errors.respond_to?(:[]) && error_message.present?
end
diff --git a/actionview/lib/action_view/helpers/asset_tag_helper.rb b/actionview/lib/action_view/helpers/asset_tag_helper.rb
index 59d70a1dc4..1e1d97fe75 100644
--- a/actionview/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionview/lib/action_view/helpers/asset_tag_helper.rb
@@ -3,7 +3,6 @@
require "active_support/core_ext/array/extract_options"
require "active_support/core_ext/hash/keys"
require "active_support/core_ext/object/inclusion"
-require "active_support/core_ext/object/try"
require "action_view/helpers/asset_url_helper"
require "action_view/helpers/tag_helper"
@@ -268,7 +267,7 @@ module ActionView
def preload_link_tag(source, options = {})
href = asset_path(source, skip_pipeline: options.delete(:skip_pipeline))
extname = File.extname(source).downcase.delete(".")
- mime_type = options.delete(:type) || Template::Types[extname].try(:to_s)
+ mime_type = options.delete(:type) || Template::Types[extname]&.to_s
as_type = options.delete(:as) || resolve_link_as(extname, mime_type)
crossorigin = options.delete(:crossorigin)
crossorigin = "anonymous" if crossorigin == true || (crossorigin.blank? && as_type == "font")
diff --git a/actionview/lib/action_view/helpers/asset_url_helper.rb b/actionview/lib/action_view/helpers/asset_url_helper.rb
index cc62783d60..295f945325 100644
--- a/actionview/lib/action_view/helpers/asset_url_helper.rb
+++ b/actionview/lib/action_view/helpers/asset_url_helper.rb
@@ -133,6 +133,8 @@ module ActionView
# which is implemented by sprockets-rails.
#
# asset_path("application.js") # => "/assets/application-60aa4fdc5cea14baf5400fba1abf4f2a46a5166bad4772b1effe341570f07de9.js"
+ # asset_path('application.js', host: 'example.com') # => "//example.com/assets/application.js"
+ # asset_path("application.js", host: 'example.com', protocol: 'https') # => "https://example.com/assets/application.js"
#
# === Without the asset pipeline (<tt>skip_pipeline: true</tt>)
#
diff --git a/actionview/lib/action_view/helpers/cache_helper.rb b/actionview/lib/action_view/helpers/cache_helper.rb
index 020aebeea3..5a05f8706a 100644
--- a/actionview/lib/action_view/helpers/cache_helper.rb
+++ b/actionview/lib/action_view/helpers/cache_helper.rb
@@ -227,7 +227,6 @@ module ActionView
end
private
-
def fragment_name_with_digest(name, virtual_path, digest_path)
virtual_path ||= @virtual_path
diff --git a/actionview/lib/action_view/helpers/date_helper.rb b/actionview/lib/action_view/helpers/date_helper.rb
index 9d5e5eaba3..f1d9fdc678 100644
--- a/actionview/lib/action_view/helpers/date_helper.rb
+++ b/actionview/lib/action_view/helpers/date_helper.rb
@@ -688,7 +688,6 @@ module ActionView
end
private
-
def normalize_distance_of_time_argument_to_time(value)
if value.is_a?(Numeric)
Time.at(value)
diff --git a/actionview/lib/action_view/helpers/form_tag_helper.rb b/actionview/lib/action_view/helpers/form_tag_helper.rb
index 5d4ff36425..c93ead9653 100644
--- a/actionview/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionview/lib/action_view/helpers/form_tag_helper.rb
@@ -137,7 +137,8 @@ module ActionView
html_name = (options[:multiple] == true && !name.to_s.ends_with?("[]")) ? "#{name}[]" : name
if options.include?(:include_blank)
- include_blank = options.delete(:include_blank)
+ include_blank = options[:include_blank]
+ options = options.except(:include_blank)
options_for_blank_options_tag = { value: "" }
if include_blank == true
diff --git a/actionview/lib/action_view/helpers/number_helper.rb b/actionview/lib/action_view/helpers/number_helper.rb
index 35206b7e48..827e0bd02c 100644
--- a/actionview/lib/action_view/helpers/number_helper.rb
+++ b/actionview/lib/action_view/helpers/number_helper.rb
@@ -251,7 +251,7 @@ module ActionView
end
# Formats the bytes in +number+ into a more understandable
- # representation (e.g., giving it 1500 yields 1.5 KB). This
+ # representation (e.g., giving it 1500 yields 1.46 KB). This
# method is useful for reporting file sizes to users. You can
# customize the format in the +options+ hash.
#
@@ -403,7 +403,6 @@ module ActionView
end
private
-
def delegate_number_helper_method(method, number, options)
return unless number
options = escape_unsafe_options(options.symbolize_keys)
diff --git a/actionview/lib/action_view/helpers/rendering_helper.rb b/actionview/lib/action_view/helpers/rendering_helper.rb
index 7ead691113..4be23b68f3 100644
--- a/actionview/lib/action_view/helpers/rendering_helper.rb
+++ b/actionview/lib/action_view/helpers/rendering_helper.rb
@@ -35,7 +35,11 @@ module ActionView
end
end
else
- view_renderer.render_partial(self, partial: options, locals: locals, &block)
+ if options.respond_to?(:render_in)
+ options.render_in(self, &block)
+ else
+ view_renderer.render_partial(self, partial: options, locals: locals, &block)
+ end
end
end
diff --git a/actionview/lib/action_view/helpers/tags/base.rb b/actionview/lib/action_view/helpers/tags/base.rb
index 39c01f3334..4ce1f507f3 100644
--- a/actionview/lib/action_view/helpers/tags/base.rb
+++ b/actionview/lib/action_view/helpers/tags/base.rb
@@ -34,7 +34,6 @@ module ActionView
end
private
-
def value
if @allow_method_names_outside_object
object.public_send @method_name if object && object.respond_to?(@method_name)
diff --git a/actionview/lib/action_view/helpers/tags/check_box.rb b/actionview/lib/action_view/helpers/tags/check_box.rb
index 4327e07cae..dbf020e514 100644
--- a/actionview/lib/action_view/helpers/tags/check_box.rb
+++ b/actionview/lib/action_view/helpers/tags/check_box.rb
@@ -39,7 +39,6 @@ module ActionView
end
private
-
def checked?(value)
case value
when TrueClass, FalseClass
diff --git a/actionview/lib/action_view/helpers/tags/collection_check_boxes.rb b/actionview/lib/action_view/helpers/tags/collection_check_boxes.rb
index 455442178e..d058eb2c72 100644
--- a/actionview/lib/action_view/helpers/tags/collection_check_boxes.rb
+++ b/actionview/lib/action_view/helpers/tags/collection_check_boxes.rb
@@ -22,7 +22,6 @@ module ActionView
end
private
-
def render_component(builder)
builder.check_box + builder.label
end
diff --git a/actionview/lib/action_view/helpers/tags/collection_helpers.rb b/actionview/lib/action_view/helpers/tags/collection_helpers.rb
index e1ad11bff8..62060547de 100644
--- a/actionview/lib/action_view/helpers/tags/collection_helpers.rb
+++ b/actionview/lib/action_view/helpers/tags/collection_helpers.rb
@@ -37,7 +37,6 @@ module ActionView
end
private
-
def instantiate_builder(builder_class, item, value, text, html_options)
builder_class.new(@template_object, @object_name, @method_name, item,
sanitize_attribute_name(value), text, value, html_options)
diff --git a/actionview/lib/action_view/helpers/tags/collection_radio_buttons.rb b/actionview/lib/action_view/helpers/tags/collection_radio_buttons.rb
index 16d37134e5..0c3b899f53 100644
--- a/actionview/lib/action_view/helpers/tags/collection_radio_buttons.rb
+++ b/actionview/lib/action_view/helpers/tags/collection_radio_buttons.rb
@@ -21,7 +21,6 @@ module ActionView
end
private
-
def render_component(builder)
builder.radio_button + builder.label
end
diff --git a/actionview/lib/action_view/helpers/tags/color_field.rb b/actionview/lib/action_view/helpers/tags/color_field.rb
index 39ab1285c3..69b190809f 100644
--- a/actionview/lib/action_view/helpers/tags/color_field.rb
+++ b/actionview/lib/action_view/helpers/tags/color_field.rb
@@ -12,7 +12,6 @@ module ActionView
end
private
-
def validate_color_string(string)
regex = /#[0-9a-fA-F]{6}/
if regex.match?(string)
diff --git a/actionview/lib/action_view/helpers/tags/date_field.rb b/actionview/lib/action_view/helpers/tags/date_field.rb
index b17a907651..ceaabfa99c 100644
--- a/actionview/lib/action_view/helpers/tags/date_field.rb
+++ b/actionview/lib/action_view/helpers/tags/date_field.rb
@@ -5,7 +5,6 @@ module ActionView
module Tags # :nodoc:
class DateField < DatetimeField # :nodoc:
private
-
def format_date(value)
value.try(:strftime, "%Y-%m-%d")
end
diff --git a/actionview/lib/action_view/helpers/tags/date_select.rb b/actionview/lib/action_view/helpers/tags/date_select.rb
index fe4e3914d7..f222bf2075 100644
--- a/actionview/lib/action_view/helpers/tags/date_select.rb
+++ b/actionview/lib/action_view/helpers/tags/date_select.rb
@@ -23,7 +23,6 @@ module ActionView
end
private
-
def select_type
self.class.select_type
end
diff --git a/actionview/lib/action_view/helpers/tags/datetime_field.rb b/actionview/lib/action_view/helpers/tags/datetime_field.rb
index 5d9b639b1b..e2dbf408c8 100644
--- a/actionview/lib/action_view/helpers/tags/datetime_field.rb
+++ b/actionview/lib/action_view/helpers/tags/datetime_field.rb
@@ -14,7 +14,6 @@ module ActionView
end
private
-
def format_date(value)
raise NotImplementedError
end
diff --git a/actionview/lib/action_view/helpers/tags/datetime_local_field.rb b/actionview/lib/action_view/helpers/tags/datetime_local_field.rb
index d8f8fd00d1..8908bf9948 100644
--- a/actionview/lib/action_view/helpers/tags/datetime_local_field.rb
+++ b/actionview/lib/action_view/helpers/tags/datetime_local_field.rb
@@ -11,7 +11,6 @@ module ActionView
end
private
-
def format_date(value)
value.try(:strftime, "%Y-%m-%dT%T")
end
diff --git a/actionview/lib/action_view/helpers/tags/label.rb b/actionview/lib/action_view/helpers/tags/label.rb
index 02bd099784..436c4cbda3 100644
--- a/actionview/lib/action_view/helpers/tags/label.rb
+++ b/actionview/lib/action_view/helpers/tags/label.rb
@@ -71,7 +71,6 @@ module ActionView
end
private
-
def render_component(builder)
builder.translation
end
diff --git a/actionview/lib/action_view/helpers/tags/month_field.rb b/actionview/lib/action_view/helpers/tags/month_field.rb
index 93b2bf11f0..463866a181 100644
--- a/actionview/lib/action_view/helpers/tags/month_field.rb
+++ b/actionview/lib/action_view/helpers/tags/month_field.rb
@@ -5,7 +5,6 @@ module ActionView
module Tags # :nodoc:
class MonthField < DatetimeField # :nodoc:
private
-
def format_date(value)
value.try(:strftime, "%Y-%m")
end
diff --git a/actionview/lib/action_view/helpers/tags/radio_button.rb b/actionview/lib/action_view/helpers/tags/radio_button.rb
index 621db2b1b5..4ce6c9f6bc 100644
--- a/actionview/lib/action_view/helpers/tags/radio_button.rb
+++ b/actionview/lib/action_view/helpers/tags/radio_button.rb
@@ -23,7 +23,6 @@ module ActionView
end
private
-
def checked?(value)
value.to_s == @tag_value.to_s
end
diff --git a/actionview/lib/action_view/helpers/tags/select.rb b/actionview/lib/action_view/helpers/tags/select.rb
index 790721a0b7..172e3a9226 100644
--- a/actionview/lib/action_view/helpers/tags/select.rb
+++ b/actionview/lib/action_view/helpers/tags/select.rb
@@ -29,7 +29,6 @@ module ActionView
end
private
-
# Grouped choices look like this:
#
# [nil, []]
diff --git a/actionview/lib/action_view/helpers/tags/text_field.rb b/actionview/lib/action_view/helpers/tags/text_field.rb
index d92967e212..c579e9e79f 100644
--- a/actionview/lib/action_view/helpers/tags/text_field.rb
+++ b/actionview/lib/action_view/helpers/tags/text_field.rb
@@ -24,7 +24,6 @@ module ActionView
end
private
-
def field_type
self.class.field_type
end
diff --git a/actionview/lib/action_view/helpers/tags/time_field.rb b/actionview/lib/action_view/helpers/tags/time_field.rb
index 9384a83a3e..e74c578db9 100644
--- a/actionview/lib/action_view/helpers/tags/time_field.rb
+++ b/actionview/lib/action_view/helpers/tags/time_field.rb
@@ -5,7 +5,6 @@ module ActionView
module Tags # :nodoc:
class TimeField < DatetimeField # :nodoc:
private
-
def format_date(value)
value.try(:strftime, "%T.%L")
end
diff --git a/actionview/lib/action_view/helpers/tags/week_field.rb b/actionview/lib/action_view/helpers/tags/week_field.rb
index 572535d1d6..5a403ed91d 100644
--- a/actionview/lib/action_view/helpers/tags/week_field.rb
+++ b/actionview/lib/action_view/helpers/tags/week_field.rb
@@ -5,7 +5,6 @@ module ActionView
module Tags # :nodoc:
class WeekField < DatetimeField # :nodoc:
private
-
def format_date(value)
value.try(:strftime, "%Y-W%V")
end
diff --git a/actionview/lib/action_view/helpers/text_helper.rb b/actionview/lib/action_view/helpers/text_helper.rb
index c282505e13..8203a43239 100644
--- a/actionview/lib/action_view/helpers/text_helper.rb
+++ b/actionview/lib/action_view/helpers/text_helper.rb
@@ -426,7 +426,6 @@ module ActionView
end
private
-
def next_index
step_index(1)
end
diff --git a/actionview/lib/action_view/helpers/translation_helper.rb b/actionview/lib/action_view/helpers/translation_helper.rb
index d5b0a9263f..baa337c62f 100644
--- a/actionview/lib/action_view/helpers/translation_helper.rb
+++ b/actionview/lib/action_view/helpers/translation_helper.rb
@@ -60,7 +60,7 @@ module ActionView
def translate(key, options = {})
options = options.dup
if options.has_key?(:default)
- remaining_defaults = Array(options.delete(:default)).compact
+ remaining_defaults = Array.wrap(options.delete(:default)).compact
options[:default] = remaining_defaults unless remaining_defaults.first.kind_of?(Symbol)
end
diff --git a/actionview/lib/action_view/helpers/url_helper.rb b/actionview/lib/action_view/helpers/url_helper.rb
index df83dff681..85fd549177 100644
--- a/actionview/lib/action_view/helpers/url_helper.rb
+++ b/actionview/lib/action_view/helpers/url_helper.rb
@@ -60,8 +60,8 @@ module ActionView
# Creates an anchor element of the given +name+ using a URL created by the set of +options+.
# See the valid options in the documentation for +url_for+. It's also possible to
- # pass a String instead of an options hash, which generates an anchor element that uses the
- # value of the String as the href for the link. Using a <tt>:back</tt> Symbol instead
+ # pass a \String instead of an options hash, which generates an anchor element that uses the
+ # value of the \String as the href for the link. Using a <tt>:back</tt> \Symbol instead
# of an options hash will generate a link to the referrer (a JavaScript back link
# will be used in place of a referrer if none exists). If +nil+ is passed as the name
# the value of the link itself will become the name.
@@ -226,7 +226,7 @@ module ActionView
# The +options+ hash accepts the same options as +url_for+.
#
# There are a few special +html_options+:
- # * <tt>:method</tt> - Symbol of HTTP verb. Supported verbs are <tt>:post</tt>, <tt>:get</tt>,
+ # * <tt>:method</tt> - \Symbol of HTTP verb. Supported verbs are <tt>:post</tt>, <tt>:get</tt>,
# <tt>:delete</tt>, <tt>:patch</tt>, and <tt>:put</tt>. By default it will be <tt>:post</tt>.
# * <tt>:disabled</tt> - If set to true, it will generate a disabled button.
# * <tt>:data</tt> - This option can be used to add custom data attributes.
@@ -235,7 +235,7 @@ module ActionView
# * <tt>:form</tt> - This hash will be form attributes
# * <tt>:form_class</tt> - This controls the class of the form within which the submit button will
# be placed
- # * <tt>:params</tt> - Hash of parameters to be rendered as hidden fields within the form.
+ # * <tt>:params</tt> - \Hash of parameters to be rendered as hidden fields within the form.
#
# ==== Data attributes
#
@@ -253,7 +253,7 @@ module ActionView
# # <input value="New" type="submit" />
# # </form>"
#
- # <%= button_to "New", new_articles_path %>
+ # <%= button_to "New", new_article_path %>
# # => "<form method="post" action="/articles/new" class="button_to">
# # <input value="New" type="submit" />
# # </form>"
@@ -571,6 +571,54 @@ module ActionView
end
end
+ # Creates an SMS anchor link tag to the specified +phone_number+, which is
+ # also used as the name of the link unless +name+ is specified. Additional
+ # HTML attributes for the link can be passed in +html_options+.
+ #
+ # When clicked, an SMS message is prepopulated with the passed phone number
+ # and optional +body+ value.
+ #
+ # +sms_to+ has a +body+ option for customizing the SMS message itself by
+ # passing special keys to +html_options+.
+ #
+ # ==== Options
+ # * <tt>:body</tt> - Preset the body of the message.
+ #
+ # ==== Examples
+ # sms_to "5155555785"
+ # # => <a href="sms:5155555785;">5155555785</a>
+ #
+ # sms_to "5155555785", "Text me"
+ # # => <a href="sms:5155555785;">Text me</a>
+ #
+ # sms_to "5155555785", "Text me",
+ # body: "Hello Jim I have a question about your product."
+ # # => <a href="sms:5155555785;?body=Hello%20Jim%20I%20have%20a%20question%20about%20your%20product">Text me</a>
+ #
+ # You can use a block as well if your link target is hard to fit into the name parameter. \ERB example:
+ #
+ # <%= sms_to "5155555785" do %>
+ # <strong>Text me:</strong>
+ # <% end %>
+ # # => <a href="sms:5155555785;">
+ # <strong>Text me:</strong>
+ # </a>
+ def sms_to(phone_number, name = nil, html_options = {}, &block)
+ html_options, name = name, nil if block_given?
+ html_options = (html_options || {}).stringify_keys
+
+ extras = %w{ body }.map! { |item|
+ option = html_options.delete(item).presence || next
+ "#{item.dasherize}=#{ERB::Util.url_encode(option)}"
+ }.compact
+ extras = extras.empty? ? "" : "?&" + extras.join("&")
+
+ encoded_phone_number = ERB::Util.url_encode(phone_number)
+ html_options["href"] = "sms:#{encoded_phone_number};#{extras}"
+
+ content_tag("a", name || phone_number, html_options, &block)
+ end
+
private
def convert_options_to_data_attributes(options, html_options)
if html_options
diff --git a/actionview/lib/action_view/layouts.rb b/actionview/lib/action_view/layouts.rb
index 08f66bf435..be21ff0e5d 100644
--- a/actionview/lib/action_view/layouts.rb
+++ b/actionview/lib/action_view/layouts.rb
@@ -224,7 +224,6 @@ module ActionView
# that if no layout conditions are used, this method is not used
module LayoutConditions # :nodoc:
private
-
# Determines whether the current action has a layout definition by
# checking the action name against the :only and :except conditions
# set by the <tt>layout</tt> method.
@@ -334,7 +333,6 @@ module ActionView
end
private
-
# If no layout is supplied, look for a template named the return
# value of this method.
#
@@ -372,7 +370,6 @@ module ActionView
end
private
-
def _conditional_layout?
true
end
diff --git a/actionview/lib/action_view/log_subscriber.rb b/actionview/lib/action_view/log_subscriber.rb
index 227f025385..02ac0ce477 100644
--- a/actionview/lib/action_view/log_subscriber.rb
+++ b/actionview/lib/action_view/log_subscriber.rb
@@ -54,7 +54,6 @@ module ActionView
end
private
-
EMPTY = ""
def from_rails_root(string) # :doc:
string = string.sub(rails_root, EMPTY)
diff --git a/actionview/lib/action_view/lookup_context.rb b/actionview/lib/action_view/lookup_context.rb
index b9a8cc129c..211fbc8e6c 100644
--- a/actionview/lib/action_view/lookup_context.rb
+++ b/actionview/lib/action_view/lookup_context.rb
@@ -3,7 +3,6 @@
require "concurrent/map"
require "active_support/core_ext/module/remove_method"
require "active_support/core_ext/module/attribute_accessors"
-require "active_support/deprecation"
require "action_view/template/resolver"
module ActionView
@@ -112,7 +111,6 @@ module ActionView
end
private
-
def _set_detail(key, value) # :doc:
@details = @details.dup if @digest_cache || @details_key
@digest_cache = nil
@@ -171,7 +169,6 @@ module ActionView
end
private
-
# Whenever setting view paths, makes a copy so that we can manipulate them in
# instance objects as we wish.
def build_view_paths(paths)
diff --git a/actionview/lib/action_view/path_set.rb b/actionview/lib/action_view/path_set.rb
index d54749d8e3..a6401323db 100644
--- a/actionview/lib/action_view/path_set.rb
+++ b/actionview/lib/action_view/path_set.rb
@@ -69,7 +69,6 @@ module ActionView #:nodoc:
end
private
-
def _find_all(path, prefixes, args)
prefixes = [prefixes] if String === prefixes
prefixes.each do |prefix|
diff --git a/actionview/lib/action_view/record_identifier.rb b/actionview/lib/action_view/record_identifier.rb
index ee39b6050d..7491dbe15a 100644
--- a/actionview/lib/action_view/record_identifier.rb
+++ b/actionview/lib/action_view/record_identifier.rb
@@ -95,7 +95,6 @@ module ActionView
end
private
-
# Returns a string representation of the key attribute(s) that is suitable for use in an HTML DOM id.
# This can be overwritten to customize the default generated string representation if desired.
# If you need to read back a key from a dom_id in order to query for the underlying database record,
diff --git a/actionview/lib/action_view/renderer/abstract_renderer.rb b/actionview/lib/action_view/renderer/abstract_renderer.rb
index b397c02cde..a52e5d3aca 100644
--- a/actionview/lib/action_view/renderer/abstract_renderer.rb
+++ b/actionview/lib/action_view/renderer/abstract_renderer.rb
@@ -74,7 +74,6 @@ module ActionView
end
private
-
def extract_details(options) # :doc:
@lookup_context.registered_details.each_with_object({}) do |key, details|
value = options[key]
diff --git a/actionview/lib/action_view/renderer/partial_renderer.rb b/actionview/lib/action_view/renderer/partial_renderer.rb
index dc85750a22..46bc4c9d5f 100644
--- a/actionview/lib/action_view/renderer/partial_renderer.rb
+++ b/actionview/lib/action_view/renderer/partial_renderer.rb
@@ -305,7 +305,7 @@ module ActionView
else
@template_keys = @locals.keys
end
- template = find_partial(@path, @template_keys)
+ template = find_template(@path, @template_keys)
@variable ||= template.variable
else
if options[:cached]
@@ -322,7 +322,6 @@ module ActionView
end
private
-
def render_collection(view, template)
identifier = (template && template.identifier) || @path
instrument(:collection, identifier: identifier, count: @collection.size) do |payload|
@@ -428,10 +427,6 @@ module ActionView
@object.to_ary if @object.respond_to?(:to_ary)
end
- def find_partial(path, template_keys)
- find_template(path, template_keys)
- end
-
def find_template(path, locals)
prefixes = path.include?(?/) ? [] : @lookup_context.prefixes
@lookup_context.find_template(path, prefixes, true, locals, @details)
diff --git a/actionview/lib/action_view/renderer/streaming_template_renderer.rb b/actionview/lib/action_view/renderer/streaming_template_renderer.rb
index 19fa399e2c..08a280c7ee 100644
--- a/actionview/lib/action_view/renderer/streaming_template_renderer.rb
+++ b/actionview/lib/action_view/renderer/streaming_template_renderer.rb
@@ -27,7 +27,6 @@ module ActionView
end
private
-
# This is the same logging logic as in ShowExceptions middleware.
def log_error(exception)
logger = ActionView::Base.logger
@@ -55,7 +54,6 @@ module ActionView
end
private
-
def delayed_render(buffer, template, layout, view, locals)
# Wrap the given buffer in the StreamingBuffer and pass it to the
# underlying template handler. Now, every time something is concatenated
diff --git a/actionview/lib/action_view/renderer/template_renderer.rb b/actionview/lib/action_view/renderer/template_renderer.rb
index 4cd8fc5bb2..b2d7332572 100644
--- a/actionview/lib/action_view/renderer/template_renderer.rb
+++ b/actionview/lib/action_view/renderer/template_renderer.rb
@@ -14,7 +14,6 @@ module ActionView
end
private
-
# Determine the template to be rendered using the given options.
def determine_template(options)
keys = options.has_key?(:locals) ? options[:locals].keys : []
diff --git a/actionview/lib/action_view/rendering.rb b/actionview/lib/action_view/rendering.rb
index 5a06bd9da6..7247598ac2 100644
--- a/actionview/lib/action_view/rendering.rb
+++ b/actionview/lib/action_view/rendering.rb
@@ -104,7 +104,6 @@ module ActionView
end
private
-
# Find and render a template based on the options given.
def _render_template(options)
variant = options.delete(:variant)
diff --git a/actionview/lib/action_view/template.rb b/actionview/lib/action_view/template.rb
index b80bf56c1b..3877108fef 100644
--- a/actionview/lib/action_view/template.rb
+++ b/actionview/lib/action_view/template.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require "active_support/core_ext/object/try"
require "active_support/core_ext/kernel/singleton_class"
-require "active_support/deprecation"
require "thread"
require "delegate"
@@ -264,7 +262,6 @@ module ActionView
end
private
-
# Compile a template. This method ensures a template is compiled
# just once and removes the source after it is compiled.
def compile!(view)
diff --git a/actionview/lib/action_view/template/error.rb b/actionview/lib/action_view/template/error.rb
index d0ea03e228..7fc74a5502 100644
--- a/actionview/lib/action_view/template/error.rb
+++ b/actionview/lib/action_view/template/error.rb
@@ -81,8 +81,8 @@ module ActionView
end
end
- def source_extract(indentation = 0, output = :console)
- return unless num = line_number
+ def source_extract(indentation = 0)
+ return [] unless num = line_number
num = num.to_i
source_code = @template.source.split("\n")
@@ -91,9 +91,9 @@ module ActionView
end_on_line = [ num + SOURCE_CODE_RADIUS - 1, source_code.length].min
indent = end_on_line.to_s.size + indentation
- return unless source_code = source_code[start_on_line..end_on_line]
+ return [] unless source_code = source_code[start_on_line..end_on_line]
- formatted_code_for(source_code, start_on_line, indent, output)
+ formatted_code_for(source_code, start_on_line, indent)
end
def sub_template_of(template_path)
@@ -114,7 +114,6 @@ module ActionView
end
private
-
def source_location
if line_number
"on line ##{line_number} of "
@@ -123,15 +122,11 @@ module ActionView
end + file_name
end
- def formatted_code_for(source_code, line_counter, indent, output)
- start_value = (output == :html) ? {} : []
- source_code.inject(start_value) do |result, line|
+ def formatted_code_for(source_code, line_counter, indent)
+ indent_template = "%#{indent}s: %s"
+ source_code.map do |line|
line_counter += 1
- if output == :html
- result.update(line_counter.to_s => "%#{indent}s %s\n" % ["", line])
- else
- result << "%#{indent}s: %s" % [line_counter, line]
- end
+ indent_template % [line_counter, line]
end
end
end
diff --git a/actionview/lib/action_view/template/handlers.rb b/actionview/lib/action_view/template/handlers.rb
index 6450513003..c7ef456125 100644
--- a/actionview/lib/action_view/template/handlers.rb
+++ b/actionview/lib/action_view/template/handlers.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require "active_support/deprecation"
-
module ActionView #:nodoc:
# = Action View Template Handlers
class Template #:nodoc:
diff --git a/actionview/lib/action_view/template/handlers/erb.rb b/actionview/lib/action_view/template/handlers/erb.rb
index b6314a5bc3..69a5a0b1b9 100644
--- a/actionview/lib/action_view/template/handlers/erb.rb
+++ b/actionview/lib/action_view/template/handlers/erb.rb
@@ -63,7 +63,6 @@ module ActionView
end
private
-
def valid_encoding(string, encoding)
# If a magic encoding comment was found, tag the
# String with this encoding. This is for a case
diff --git a/actionview/lib/action_view/template/html.rb b/actionview/lib/action_view/template/html.rb
index ecd1c31e79..563bffd333 100644
--- a/actionview/lib/action_view/template/html.rb
+++ b/actionview/lib/action_view/template/html.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require "active_support/deprecation"
-
module ActionView #:nodoc:
# = Action View HTML Template
class Template #:nodoc:
diff --git a/actionview/lib/action_view/template/resolver.rb b/actionview/lib/action_view/template/resolver.rb
index ce53eb046d..bfac4c08a0 100644
--- a/actionview/lib/action_view/template/resolver.rb
+++ b/actionview/lib/action_view/template/resolver.rb
@@ -93,7 +93,6 @@ module ActionView
end
private
-
def canonical_no_templates(templates)
templates.empty? ? NO_TEMPLATES : templates
end
@@ -130,7 +129,6 @@ module ActionView
end
private
-
def _find_all(name, prefix, partial, details, key, locals)
find_templates(name, prefix, partial, details, locals)
end
@@ -183,7 +181,6 @@ module ActionView
end
private
-
def _find_all(name, prefix, partial, details, key, locals)
path = Path.build(name, prefix, partial)
query(path, details, details[:formats], locals, cache: !!key)
@@ -282,12 +279,8 @@ module ActionView
format, variant = pieces.last.split(EXTENSIONS[:variants], 2) if pieces.last
format = if format
Template::Types[format]&.ref
- else
- if handler.respond_to?(:default_format) # default_format can return nil
- handler.default_format
- else
- nil
- end
+ elsif handler.respond_to?(:default_format) # default_format can return nil
+ handler.default_format
end
# Template::Types[format] and handler.default_format can return nil
@@ -323,7 +316,6 @@ module ActionView
end
private
-
def find_template_paths_from_details(path, details)
# Instead of checking for every possible path, as our other globs would
# do, scan the directory for files with the right prefix.
diff --git a/actionview/lib/action_view/test_case.rb b/actionview/lib/action_view/test_case.rb
index 3a75633743..b08f8b2dfb 100644
--- a/actionview/lib/action_view/test_case.rb
+++ b/actionview/lib/action_view/test_case.rb
@@ -93,7 +93,6 @@ module ActionView
end
private
-
def include_helper_modules!
helper(helper_class) if helper_class
include _helpers
@@ -163,7 +162,6 @@ module ActionView
end
private
-
# Need to experiment if this priority is the best one: rendered => output_buffer
def document_root_element
Nokogiri::HTML::Document.parse(@rendered.blank? ? @output_buffer : @rendered).root
diff --git a/actionview/lib/action_view/testing/resolvers.rb b/actionview/lib/action_view/testing/resolvers.rb
index 1bedf44934..03eac29bb4 100644
--- a/actionview/lib/action_view/testing/resolvers.rb
+++ b/actionview/lib/action_view/testing/resolvers.rb
@@ -7,10 +7,15 @@ module ActionView #:nodoc:
# file system. This is used internally by Rails' own test suite, and is
# useful for testing extensions that have no way of knowing what the file
# system will look like at runtime.
- class FixtureResolver < PathResolver
+ class FixtureResolver < OptimizedFileSystemResolver
def initialize(hash = {}, pattern = nil)
- super(pattern)
+ super("")
+ if pattern
+ ActiveSupport::Deprecation.warn "Specifying a custom path for #{self.class} is deprecated. Implement a custom Resolver subclass instead."
+ @pattern = pattern
+ end
@hash = hash
+ @path = ""
end
def data
@@ -22,27 +27,33 @@ module ActionView #:nodoc:
end
private
-
def query(path, exts, _, locals, cache:)
- query = +""
- EXTENSIONS.each do |ext, prefix|
- query << "(" << exts[ext].map { |e| e && Regexp.escape("#{prefix}#{e}") }.join("|") << "|)"
- end
- query = /^(#{Regexp.escape(path)})#{query}$/
+ regex = build_regex(path, exts)
- templates = []
- @hash.each do |_path, source|
- next unless query.match?(_path)
+ @hash.select do |_path, _|
+ ("/" + _path).match?(regex)
+ end.map do |_path, source|
handler, format, variant = extract_handler_and_format_and_variant(_path)
- templates << Template.new(source, _path, handler,
+
+ Template.new(source, _path, handler,
virtual_path: path.virtual,
format: format,
variant: variant,
locals: locals
)
+ end.sort_by do |t|
+ match = ("/" + t.identifier).match(regex)
+ EXTENSIONS.keys.reverse.map do |ext|
+ if ext == :variants && exts[ext] == :any
+ match[ext].nil? ? 0 : 1
+ elsif match[ext].nil?
+ exts[ext].length
+ else
+ found = match[ext].to_sym
+ exts[ext].index(found)
+ end
+ end
end
-
- templates.sort_by { |t| -t.identifier.match(/^#{query}$/).captures.reject(&:blank?).size }
end
end
diff --git a/actionview/lib/action_view/unbound_template.rb b/actionview/lib/action_view/unbound_template.rb
index db69b6d016..3d4434b2e9 100644
--- a/actionview/lib/action_view/unbound_template.rb
+++ b/actionview/lib/action_view/unbound_template.rb
@@ -4,9 +4,9 @@ require "concurrent/map"
module ActionView
class UnboundTemplate
- def initialize(source, identifer, handler, options)
+ def initialize(source, identifier, handler, options)
@source = source
- @identifer = identifer
+ @identifier = identifier
@handler = handler
@options = options
@@ -18,12 +18,11 @@ module ActionView
end
private
-
def build_template(locals)
options = @options.merge(locals: locals)
Template.new(
@source,
- @identifer,
+ @identifier,
@handler,
options
)
diff --git a/actionview/lib/action_view/view_paths.rb b/actionview/lib/action_view/view_paths.rb
index 3ca5aedc14..7e05f15648 100644
--- a/actionview/lib/action_view/view_paths.rb
+++ b/actionview/lib/action_view/view_paths.rb
@@ -29,7 +29,6 @@ module ActionView
end
private
-
# Override this method in your controller if you want to change paths prefixes for finding views.
# Prefixes defined here will still be added to parents' <tt>._prefixes</tt>.
def local_prefixes
diff --git a/actionview/test/abstract_unit.rb b/actionview/test/abstract_unit.rb
index 2c1b277b41..b652f2e6cb 100644
--- a/actionview/test/abstract_unit.rb
+++ b/actionview/test/abstract_unit.rb
@@ -192,6 +192,8 @@ module ActionDispatch
end
class ActiveSupport::TestCase
+ parallelize
+
include ActiveSupport::Testing::MethodCallAssertions
private
diff --git a/actionview/test/actionpack/abstract/abstract_controller_test.rb b/actionview/test/actionpack/abstract/abstract_controller_test.rb
index eecc19d413..2de81596b5 100644
--- a/actionview/test/actionpack/abstract/abstract_controller_test.rb
+++ b/actionview/test/actionpack/abstract/abstract_controller_test.rb
@@ -230,6 +230,7 @@ module AbstractController
class ActionMissingRespondToActionController < AbstractController::Base
# No actions
+
private
def action_missing(action_name)
self.response_body = "success"
@@ -242,7 +243,6 @@ module AbstractController
def fail() self.response_body = "fail" end
private
-
def method_for_action(action_name)
action_name.to_s != "fail" && action_name
end
diff --git a/actionview/test/actionpack/abstract/layouts_test.rb b/actionview/test/actionpack/abstract/layouts_test.rb
index 1146e6f64b..15643c161d 100644
--- a/actionview/test/actionpack/abstract/layouts_test.rb
+++ b/actionview/test/actionpack/abstract/layouts_test.rb
@@ -140,6 +140,7 @@ module AbstractControllerTests
def index
render template: ActionView::Template::Text.new("Hello symbol!")
end
+
private
def hello
"overwrite"
@@ -295,7 +296,7 @@ module AbstractControllerTests
10.times do |x|
controller = WithString.new
controller.define_singleton_method :index do
- render template: ActionView::Template::Text.new("Hello string!"), locals: { :"x#{x}" => :omg }
+ render template: ActionView::Template::Text.new("Hello string!"), locals: { "x#{x}": :omg }
end
controller.process(:index)
end
diff --git a/actionview/test/actionpack/controller/render_test.rb b/actionview/test/actionpack/controller/render_test.rb
index c8ce7366d1..64070a9542 100644
--- a/actionview/test/actionpack/controller/render_test.rb
+++ b/actionview/test/actionpack/controller/render_test.rb
@@ -607,7 +607,6 @@ class TestController < ActionController::Base
end
private
-
def set_variable_for_layout
@variable_for_layout = nil
end
@@ -1003,14 +1002,14 @@ class RenderTest < ActionController::TestCase
def test_render_xml
get :render_xml_hello
assert_equal "<html>\n <p>Hello David</p>\n<p>This is grand!</p>\n</html>\n", @response.body
- assert_equal "application/xml", @response.content_type
+ assert_equal "application/xml", @response.media_type
end
# :ported:
def test_render_xml_as_string_template
get :render_xml_hello_as_string_template
assert_equal "<html>\n <p>Hello David</p>\n<p>This is grand!</p>\n</html>\n", @response.body
- assert_equal "application/xml", @response.content_type
+ assert_equal "application/xml", @response.media_type
end
# :ported:
@@ -1039,7 +1038,7 @@ class RenderTest < ActionController::TestCase
def test_rendered_format_without_format
get :inline_rendered_format_without_format
assert_equal "test", @response.body
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
end
def test_partials_list
@@ -1077,7 +1076,7 @@ class RenderTest < ActionController::TestCase
def test_accessing_local_assigns_in_inline_template
get :accessing_local_assigns_in_inline_template, params: { local_name: "Local David" }
assert_equal "Goodbye, Local David", @response.body
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
end
def test_should_implicitly_render_html_template_from_xhr_request
@@ -1264,13 +1263,13 @@ class RenderTest < ActionController::TestCase
def test_partial_only
get :partial_only
assert_equal "only partial", @response.body
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
end
def test_should_render_html_formatted_partial
get :partial
assert_equal "partial html", @response.body
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
end
def test_render_html_formatted_partial_even_with_other_mime_time_in_accept
@@ -1279,20 +1278,20 @@ class RenderTest < ActionController::TestCase
get :partial_html_erb
assert_equal "partial.html.erb", @response.body.strip
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
end
def test_should_render_html_partial_with_formats
get :partial_formats_html
assert_equal "partial html", @response.body
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
end
def test_render_to_string_partial
get :render_to_string_with_partial
assert_equal "only partial", @controller.instance_variable_get(:@partial_only)
assert_equal "Hello: david", @controller.instance_variable_get(:@partial_with_locals)
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
end
def test_render_to_string_with_template_and_html_partial
@@ -1300,21 +1299,21 @@ class RenderTest < ActionController::TestCase
assert_equal "**only partial**\n", @controller.instance_variable_get(:@text)
assert_equal "<strong>only partial</strong>\n", @controller.instance_variable_get(:@html)
assert_equal "<strong>only html partial</strong>\n", @response.body
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
end
def test_render_to_string_and_render_with_different_formats
get :render_to_string_and_render_with_different_formats
assert_equal "<strong>only partial</strong>\n", @controller.instance_variable_get(:@html)
assert_equal "**only partial**\n", @response.body
- assert_equal "text/plain", @response.content_type
+ assert_equal "text/plain", @response.media_type
end
def test_render_template_within_a_template_with_other_format
get :render_template_within_a_template_with_other_format
expected = "only html partial<p>This is grand!</p>"
assert_equal expected, @response.body.strip
- assert_equal "text/html", @response.content_type
+ assert_equal "text/html", @response.media_type
end
def test_partial_with_counter
diff --git a/actionview/test/active_record_unit.rb b/actionview/test/active_record_unit.rb
index e4ea6a426d..4efb31a360 100644
--- a/actionview/test/active_record_unit.rb
+++ b/actionview/test/active_record_unit.rb
@@ -42,6 +42,12 @@ class ActiveRecordTestConnector
self.able_to_connect = false
end
+ def reconnect
+ return unless able_to_connect
+ ActiveRecord::Base.connection.reconnect!
+ load_schema
+ end
+
private
def setup_connection
if Object.const_defined?(:ActiveRecord)
@@ -102,3 +108,7 @@ class ActiveRecordTestCase < ActionController::TestCase
end
ActiveRecordTestConnector.setup
+
+ActiveSupport::Testing::Parallelization.after_fork_hook do
+ ActiveRecordTestConnector.reconnect
+end
diff --git a/actionview/test/activerecord/form_helper_activerecord_test.rb b/actionview/test/activerecord/form_helper_activerecord_test.rb
index 34655bfe23..1b196ade6d 100644
--- a/actionview/test/activerecord/form_helper_activerecord_test.rb
+++ b/actionview/test/activerecord/form_helper_activerecord_test.rb
@@ -58,7 +58,6 @@ class FormHelperActiveRecordTest < ActionView::TestCase
end
private
-
def hidden_fields(method = nil)
txt = +%{<input name="utf8" type="hidden" value="&#x2713;" />}
diff --git a/actionview/test/lib/test_component.rb b/actionview/test/lib/test_component.rb
new file mode 100644
index 0000000000..0d45d6e25f
--- /dev/null
+++ b/actionview/test/lib/test_component.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+class TestComponent < ActionView::Base
+ include ActiveModel::Validations
+
+ validates :content, :title, presence: true
+ delegate :render, to: :view_context
+
+ def initialize(title:)
+ @title = title
+ end
+
+ # Entrypoint for rendering. Called by ActionView::RenderingHelper#render.
+ #
+ # Returns ActionView::OutputBuffer.
+ def render_in(view_context, &block)
+ self.class.compile
+ @view_context = view_context
+ @content = view_context.capture(&block) if block_given?
+ validate!
+ rendered_template
+ end
+
+ def self.template
+ <<~'erb'
+ <span title="<%= title %>"><%= content %> (<%= render(plain: "Inline render") %>)</span>
+ erb
+ end
+
+ def self.compile
+ @compiled ||= nil
+ return if @compiled
+
+ class_eval(
+ "def rendered_template; @output_buffer = ActionView::OutputBuffer.new; " +
+ ActionView::Template::Handlers::ERB.erb_implementation.new(template, trim: true).src +
+ "; end"
+ )
+
+ @compiled = true
+ end
+
+private
+ attr_reader :content, :title, :view_context
+end
diff --git a/actionview/test/template/compiled_templates_test.rb b/actionview/test/template/compiled_templates_test.rb
index d7f2e8ee07..59fa058bed 100644
--- a/actionview/test/template/compiled_templates_test.rb
+++ b/actionview/test/template/compiled_templates_test.rb
@@ -60,46 +60,8 @@ class CompiledTemplatesTest < ActiveSupport::TestCase
assert_equal "two", render(template: "test/render_file_with_locals_and_default", locals: { secret: "two" })
end
- def test_template_changes_are_not_reflected_with_cached_templates
- assert_equal "Hello world!", render(template: "test/hello_world")
- modify_template "test/hello_world.erb", "Goodbye world!" do
- assert_equal "Hello world!", render(template: "test/hello_world")
- end
- assert_equal "Hello world!", render(template: "test/hello_world")
- end
-
- def test_template_changes_are_reflected_with_uncached_templates
- assert_equal "Hello world!", render_without_cache(template: "test/hello_world")
- modify_template "test/hello_world.erb", "Goodbye world!" do
- assert_equal "Goodbye world!", render_without_cache(template: "test/hello_world")
- end
- assert_equal "Hello world!", render_without_cache(template: "test/hello_world")
- end
-
private
def render(*args)
- render_with_cache(*args)
- end
-
- def render_with_cache(*args)
- view_paths = ActionController::Base.view_paths
- view_class.with_view_paths(view_paths, {}).render(*args)
- end
-
- def render_without_cache(*args)
- path = ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH)
- view_paths = ActionView::PathSet.new([path])
- view_class.with_view_paths(view_paths, {}).render(*args)
- end
-
- def modify_template(template, content)
- filename = "#{FIXTURE_LOAD_PATH}/#{template}"
- old_content = File.read(filename)
- begin
- File.open(filename, "wb+") { |f| f.write(content) }
- yield
- ensure
- File.open(filename, "wb+") { |f| f.write(old_content) }
- end
+ ActionController::Base.render(*args)
end
end
diff --git a/actionview/test/template/form_helper_test.rb b/actionview/test/template/form_helper_test.rb
index 91052e5ae2..83b089397c 100644
--- a/actionview/test/template/form_helper_test.rb
+++ b/actionview/test/template/form_helper_test.rb
@@ -1897,7 +1897,6 @@ class FormHelperTest < ActionView::TestCase
def test_form_tags_do_not_call_private_properties_on_form_object
obj = Class.new do
private
-
def private_property
raise "This method should not be called."
end
diff --git a/actionview/test/template/form_options_helper_test.rb b/actionview/test/template/form_options_helper_test.rb
index c9c36917d6..d7a7b95ab3 100644
--- a/actionview/test/template/form_options_helper_test.rb
+++ b/actionview/test/template/form_options_helper_test.rb
@@ -1472,7 +1472,6 @@ class FormOptionsHelperTest < ActionView::TestCase
end
private
-
def dummy_posts
[ Post.new("<Abe> went home", "<Abe>", "To a little house", "shh!"),
Post.new("Babe went home", "Babe", "To a little house", "shh!"),
diff --git a/actionview/test/template/form_tag_helper_test.rb b/actionview/test/template/form_tag_helper_test.rb
index 9ece9f3ad1..80afed96e5 100644
--- a/actionview/test/template/form_tag_helper_test.rb
+++ b/actionview/test/template/form_tag_helper_test.rb
@@ -301,6 +301,13 @@ class FormTagHelperTest < ActionView::TestCase
assert_dom_equal expected, actual
end
+ def test_select_tag_with_include_blank_doesnt_change_options
+ options = { include_blank: true, prompt: "string" }
+ expected_options = options.dup
+ select_tag "places", raw("<option>Home</option><option>Work</option><option>Pub</option>"), options
+ expected_options.each { |k, v| assert_equal v, options[k] }
+ end
+
def test_select_tag_with_include_blank_false
actual = select_tag "places", raw("<option>Home</option><option>Work</option><option>Pub</option>"), include_blank: false
expected = %(<select id="places" name="places"><option>Home</option><option>Work</option><option>Pub</option></select>)
@@ -796,7 +803,6 @@ class FormTagHelperTest < ActionView::TestCase
end
private
-
def root_elem(rendered_content)
Nokogiri::HTML::DocumentFragment.parse(rendered_content).children.first # extract from nodeset
end
diff --git a/actionview/test/template/render_test.rb b/actionview/test/template/render_test.rb
index f0b5d7d95e..c82264a170 100644
--- a/actionview/test/template/render_test.rb
+++ b/actionview/test/template/render_test.rb
@@ -2,6 +2,8 @@
require "abstract_unit"
require "controller/fake_models"
+require "test_component"
+require "active_model/validations"
class TestController < ActionController::Base
end
@@ -33,6 +35,11 @@ module RenderTestCases
assert_equal ORIGINAL_LOCALES, I18n.available_locales.map(&:to_s).sort
end
+ def teardown
+ I18n.reload!
+ ActionController::Base.view_paths.map(&:clear_cache)
+ end
+
def test_implicit_format_comes_from_parent_template
rendered_templates = JSON.parse(@controller_view.render(template: "test/mixing_formats"))
assert_equal({ "format" => "HTML",
@@ -665,6 +672,21 @@ module RenderTestCases
def test_render_throws_exception_when_no_extensions_passed_to_register_template_handler_function_call
assert_raises(ArgumentError) { ActionView::Template.register_template_handler CustomHandler }
end
+
+ def test_render_component
+ assert_equal(
+ %(<span title="my title">Hello, World! (Inline render)</span>),
+ @view.render(TestComponent.new(title: "my title")) { "Hello, World!" }.strip
+ )
+ end
+
+ def test_render_component_with_validation_error
+ error = assert_raises(ActiveModel::ValidationError) do
+ @view.render(TestComponent.new(title: "my title")).strip
+ end
+
+ assert_match "Content can't be blank", error.message
+ end
end
class CachedViewRenderTest < ActiveSupport::TestCase
@@ -677,11 +699,6 @@ class CachedViewRenderTest < ActiveSupport::TestCase
assert_equal ActionView::OptimizedFileSystemResolver, view_paths.first.class
setup_view(view_paths)
end
-
- def teardown
- GC.start
- I18n.reload!
- end
end
class LazyViewRenderTest < ActiveSupport::TestCase
@@ -697,11 +714,6 @@ class LazyViewRenderTest < ActiveSupport::TestCase
setup_view(view_paths)
end
- def teardown
- GC.start
- I18n.reload!
- end
-
def test_render_utf8_template_with_magic_comment
with_external_encoding Encoding::ASCII_8BIT do
result = @view.render(template: "test/utf8_magic", formats: [:html], layouts: "layouts/yield")
@@ -758,10 +770,6 @@ class CachedCollectionViewRenderTest < ActiveSupport::TestCase
setup_view(view_paths)
end
- teardown do
- I18n.reload!
- end
-
test "template body written to cache" do
customer = Customer.new("david", 1)
key = cache_key(customer, "test/_customer")
diff --git a/actionview/test/template/template_error_test.rb b/actionview/test/template/template_error_test.rb
index c4dc88e4aa..643c29602b 100644
--- a/actionview/test/template/template_error_test.rb
+++ b/actionview/test/template/template_error_test.rb
@@ -34,4 +34,20 @@ class TemplateErrorTest < ActiveSupport::TestCase
assert_equal "#<ActionView::Template::Error: original>", error.inspect
end
+
+ def test_annotated_source_code_returns_empty_array_if_source_cant_be_found
+ template = Class.new do
+ def identifier
+ "something"
+ end
+ end.new
+
+ error = begin
+ raise
+ rescue
+ raise ActionView::Template::Error.new(template) rescue $!
+ end
+
+ assert_equal [], error.annotated_source_code
+ end
end
diff --git a/actionview/test/template/testing/fixture_resolver_test.rb b/actionview/test/template/testing/fixture_resolver_test.rb
index 6d0317e0c9..a6066e94c6 100644
--- a/actionview/test/template/testing/fixture_resolver_test.rb
+++ b/actionview/test/template/testing/fixture_resolver_test.rb
@@ -27,4 +27,26 @@ class FixtureResolverTest < ActiveSupport::TestCase
assert_equal :html, templates.first.format
assert_equal "variant", templates.first.variant
end
+
+ def test_should_match_locales
+ resolver = ActionView::FixtureResolver.new("arbitrary/path.erb" => "this text", "arbitrary/path.fr.erb" => "ce texte")
+ en = resolver.find_all("path", "arbitrary", false, locale: [:en], formats: [:html], variants: [], handlers: [:erb])
+ fr = resolver.find_all("path", "arbitrary", false, locale: [:fr], formats: [:html], variants: [], handlers: [:erb])
+
+ assert_equal 1, en.size
+ assert_equal 2, fr.size
+
+ assert_equal "this text", en[0].source
+ assert_equal "ce texte", fr[0].source
+ assert_equal "this text", fr[1].source
+ end
+
+ def test_should_return_all_variants_for_any
+ resolver = ActionView::FixtureResolver.new("arbitrary/path.html.erb" => "this html", "arbitrary/path.html+varient.erb" => "this text")
+ templates = resolver.find_all("path", "arbitrary", false, locale: [], formats: [:html], variants: [], handlers: [:erb])
+ assert_equal 1, templates.size, "expected one template"
+ assert_equal "this html", templates.first.source
+ templates = resolver.find_all("path", "arbitrary", false, locale: [], formats: [:html], variants: :any, handlers: [:erb])
+ assert_equal 2, templates.size, "expected all templates"
+ end
end
diff --git a/actionview/test/template/translation_helper_test.rb b/actionview/test/template/translation_helper_test.rb
index 9afdc3c68f..3475a1dada 100644
--- a/actionview/test/template/translation_helper_test.rb
+++ b/actionview/test/template/translation_helper_test.rb
@@ -121,6 +121,11 @@ class TranslationHelperTest < ActiveSupport::TestCase
I18n.exception_handler = old_exception_handler
end
+ def test_hash_default
+ default = { separator: ".", delimiter: "," }
+ assert_equal default, translate(:'special.number.format', default: default)
+ end
+
def test_translation_returning_an_array
expected = %w(foo bar)
assert_equal expected, translate(:"translations.array")
diff --git a/actionview/test/template/url_helper_test.rb b/actionview/test/template/url_helper_test.rb
index 632b32f09f..bce6e7f370 100644
--- a/actionview/test/template/url_helper_test.rb
+++ b/actionview/test/template/url_helper_test.rb
@@ -708,6 +708,68 @@ class UrlHelperTest < ActiveSupport::TestCase
assert_equal({ class: "special" }, options)
end
+ def test_sms_to
+ assert_dom_equal %{<a href="sms:15155555785;">15155555785</a>}, sms_to("15155555785")
+ assert_dom_equal %{<a href="sms:15155555785;">Jim Jones</a>}, sms_to("15155555785", "Jim Jones")
+ assert_dom_equal(
+ %{<a class="admin" href="sms:15155555785;">Jim Jones</a>},
+ sms_to("15155555785", "Jim Jones", "class" => "admin")
+ )
+ assert_equal sms_to("15155555785", "Jim Jones", "class" => "admin"),
+ sms_to("15155555785", "Jim Jones", class: "admin")
+ end
+
+ def test_sms_to_with_options
+ assert_dom_equal(
+ %{<a class="simple-class" href="sms:15155555785;?&body=Hello%20from%20Jim">Text me</a>},
+ sms_to("15155555785", "Text me", class: "simple-class", body: "Hello from Jim")
+ )
+
+ assert_dom_equal(
+ %{<a href="sms:15155555785;?&body=This%20is%20the%20body%20of%20the%20message.">Text me</a>},
+ sms_to("15155555785", "Text me", body: "This is the body of the message.")
+ )
+ end
+
+ def test_sms_with_img
+ assert_dom_equal %{<a href="sms:15155555785;"><img src="/feedback.png" /></a>},
+ sms_to("15155555785", raw('<img src="/feedback.png" />'))
+ end
+
+ def test_sms_with_html_safe_string
+ assert_dom_equal(
+ %{<a href="sms:1%2B5155555785;">1+5155555785</a>},
+ sms_to(raw("1+5155555785"))
+ )
+ end
+
+ def test_sms_with_nil
+ assert_dom_equal(
+ %{<a href="sms:;"></a>},
+ sms_to(nil)
+ )
+ end
+
+ def test_sms_returns_html_safe_string
+ assert_predicate sms_to("15155555785"), :html_safe?
+ end
+
+ def test_sms_with_block
+ assert_dom_equal %{<a href="sms:15155555785;"><span>Text me</span></a>},
+ sms_to("15155555785") { content_tag(:span, "Text me") }
+ end
+
+ def test_sms_with_block_and_options
+ assert_dom_equal %{<a class="special" href="sms:15155555785;?&body=Hello%20from%20Jim"><span>Text me</span></a>},
+ sms_to("15155555785", body: "Hello from Jim", class: "special") { content_tag(:span, "Text me") }
+ end
+
+ def test_sms_does_not_modify_html_options_hash
+ options = { class: "special" }
+ sms_to "15155555785", "ME!", options
+ assert_equal({ class: "special" }, options)
+ end
+
def protect_against_forgery?
request_forgery
end
diff --git a/actionview/test/ujs/public/test/data-remote.js b/actionview/test/ujs/public/test/data-remote.js
index 9e41067549..16ea114f3b 100644
--- a/actionview/test/ujs/public/test/data-remote.js
+++ b/actionview/test/ujs/public/test/data-remote.js
@@ -82,6 +82,20 @@ asyncTest('right/mouse-wheel-clicking on a link does not fire ajaxyness', 0, fun
setTimeout(function() { start() }, 13)
})
+asyncTest('clicking on a link via a non-mouse Event (such as from js) works', 1, function() {
+ var link = $('a[data-remote]')
+
+ link
+ .removeAttr('data-params')
+ .bindNative('ajax:beforeSend', function() {
+ ok(true, 'ajax should be triggered')
+ })
+
+ Rails.fire(link[0], 'click')
+
+ setTimeout(function() { start() }, 13)
+})
+
asyncTest('ctrl-clicking on a link still fires ajax for non-GET links and for links with "data-params"', 2, function() {
var link = $('a[data-remote]')
diff --git a/activejob/CHANGELOG.md b/activejob/CHANGELOG.md
index 2f0d72ccb9..542a4eb2db 100644
--- a/activejob/CHANGELOG.md
+++ b/activejob/CHANGELOG.md
@@ -1,3 +1,6 @@
+* `assert_enqueued_with` and `assert_performed_with` can now test jobs with relative delay.
+
+ *Vlado Cingel*
Please check [6-0-stable](https://github.com/rails/rails/blob/6-0-stable/activejob/CHANGELOG.md) for previous changes.
diff --git a/activejob/lib/active_job/arguments.rb b/activejob/lib/active_job/arguments.rb
index 92eb58aaaf..e08e30040b 100644
--- a/activejob/lib/active_job/arguments.rb
+++ b/activejob/lib/active_job/arguments.rb
@@ -45,7 +45,6 @@ module ActiveJob
end
private
-
# :nodoc:
PERMITTED_TYPES = [ NilClass, String, Integer, Float, BigDecimal, TrueClass, FalseClass ]
# :nodoc:
diff --git a/activejob/lib/active_job/serializers/date_serializer.rb b/activejob/lib/active_job/serializers/date_serializer.rb
index e995d30faa..3ec587bc54 100644
--- a/activejob/lib/active_job/serializers/date_serializer.rb
+++ b/activejob/lib/active_job/serializers/date_serializer.rb
@@ -12,7 +12,6 @@ module ActiveJob
end
private
-
def klass
Date
end
diff --git a/activejob/lib/active_job/serializers/date_time_serializer.rb b/activejob/lib/active_job/serializers/date_time_serializer.rb
index fe780a1978..42df338b73 100644
--- a/activejob/lib/active_job/serializers/date_time_serializer.rb
+++ b/activejob/lib/active_job/serializers/date_time_serializer.rb
@@ -12,7 +12,6 @@ module ActiveJob
end
private
-
def klass
DateTime
end
diff --git a/activejob/lib/active_job/serializers/duration_serializer.rb b/activejob/lib/active_job/serializers/duration_serializer.rb
index 715fe27a5c..b35eaf5f60 100644
--- a/activejob/lib/active_job/serializers/duration_serializer.rb
+++ b/activejob/lib/active_job/serializers/duration_serializer.rb
@@ -15,7 +15,6 @@ module ActiveJob
end
private
-
def klass
ActiveSupport::Duration
end
diff --git a/activejob/lib/active_job/serializers/object_serializer.rb b/activejob/lib/active_job/serializers/object_serializer.rb
index 6d280969be..be69ddf90c 100644
--- a/activejob/lib/active_job/serializers/object_serializer.rb
+++ b/activejob/lib/active_job/serializers/object_serializer.rb
@@ -44,7 +44,6 @@ module ActiveJob
end
private
-
# The class of the object that will be serialized.
def klass # :doc:
raise NotImplementedError
diff --git a/activejob/lib/active_job/serializers/symbol_serializer.rb b/activejob/lib/active_job/serializers/symbol_serializer.rb
index 7e1f9553a2..3f6ee9101f 100644
--- a/activejob/lib/active_job/serializers/symbol_serializer.rb
+++ b/activejob/lib/active_job/serializers/symbol_serializer.rb
@@ -12,7 +12,6 @@ module ActiveJob
end
private
-
def klass
Symbol
end
diff --git a/activejob/lib/active_job/serializers/time_serializer.rb b/activejob/lib/active_job/serializers/time_serializer.rb
index fe20772f35..d385cca6bb 100644
--- a/activejob/lib/active_job/serializers/time_serializer.rb
+++ b/activejob/lib/active_job/serializers/time_serializer.rb
@@ -12,7 +12,6 @@ module ActiveJob
end
private
-
def klass
Time
end
diff --git a/activejob/lib/active_job/serializers/time_with_zone_serializer.rb b/activejob/lib/active_job/serializers/time_with_zone_serializer.rb
index 43017fc75b..0b29012072 100644
--- a/activejob/lib/active_job/serializers/time_with_zone_serializer.rb
+++ b/activejob/lib/active_job/serializers/time_with_zone_serializer.rb
@@ -12,7 +12,6 @@ module ActiveJob
end
private
-
def klass
ActiveSupport::TimeWithZone
end
diff --git a/activejob/lib/active_job/test_helper.rb b/activejob/lib/active_job/test_helper.rb
index 463020a332..5b1af7da22 100644
--- a/activejob/lib/active_job/test_helper.rb
+++ b/activejob/lib/active_job/test_helper.rb
@@ -630,7 +630,7 @@ module ActiveJob
def prepare_args_for_assertion(args)
args.dup.tap do |arguments|
- arguments[:at] = arguments[:at].to_f if arguments[:at]
+ arguments[:at] = round_time_arguments(arguments[:at]) if arguments[:at]
arguments[:args] = round_time_arguments(arguments[:args]) if arguments[:args]
end
end
@@ -650,6 +650,7 @@ module ActiveJob
def deserialize_args_for_assertion(job)
job.dup.tap do |new_job|
+ new_job[:at] = round_time_arguments(Time.at(new_job[:at])) if new_job[:at]
new_job[:args] = ActiveJob::Arguments.deserialize(new_job[:args]) if new_job[:args]
end
end
diff --git a/activejob/test/cases/serializers_test.rb b/activejob/test/cases/serializers_test.rb
index bee0c061bd..2b9ba75ae0 100644
--- a/activejob/test/cases/serializers_test.rb
+++ b/activejob/test/cases/serializers_test.rb
@@ -26,7 +26,6 @@ class SerializersTest < ActiveSupport::TestCase
end
private
-
def klass
DummyValueObject
end
diff --git a/activejob/test/cases/test_helper_test.rb b/activejob/test/cases/test_helper_test.rb
index 32471cfacc..34dfd8eb56 100644
--- a/activejob/test/cases/test_helper_test.rb
+++ b/activejob/test/cases/test_helper_test.rb
@@ -621,6 +621,12 @@ class EnqueuedJobsTest < ActiveJob::TestCase
end
end
+ def test_assert_enqueued_with_with_relative_at_option
+ assert_enqueued_with(job: HelloJob, at: 5.minutes.from_now) do
+ HelloJob.set(wait: 5.minutes).perform_later
+ end
+ end
+
def test_assert_enqueued_with_with_no_block_with_at_option
HelloJob.set(wait_until: Date.tomorrow.noon).perform_later
assert_enqueued_with(job: HelloJob, at: Date.tomorrow.noon)
@@ -1663,6 +1669,18 @@ class PerformedJobsTest < ActiveJob::TestCase
end
end
+ def test_assert_performed_with_with_relative_at_option
+ assert_performed_with(job: HelloJob, at: 5.minutes.from_now) do
+ HelloJob.set(wait: 5.minutes).perform_later
+ end
+
+ assert_raise ActiveSupport::TestCase::Assertion do
+ assert_performed_with(job: HelloJob, at: 2.minutes.from_now) do
+ HelloJob.set(wait: 1.minute).perform_later
+ end
+ end
+ end
+
def test_assert_performed_with_without_block_with_at_option
HelloJob.set(wait_until: Date.tomorrow.noon).perform_later
diff --git a/activejob/test/jobs/timezone_dependent_job.rb b/activejob/test/jobs/timezone_dependent_job.rb
index 41f473d533..f63ff95b95 100644
--- a/activejob/test/jobs/timezone_dependent_job.rb
+++ b/activejob/test/jobs/timezone_dependent_job.rb
@@ -15,7 +15,6 @@ class TimezoneDependentJob < ActiveJob::Base
end
private
-
def localtime(*args)
Time.zone ? Time.zone.local(*args) : Time.utc(*args)
end
diff --git a/activejob/test/support/integration/test_case_helpers.rb b/activejob/test/support/integration/test_case_helpers.rb
index 973ee07764..d8931a74ed 100644
--- a/activejob/test/support/integration/test_case_helpers.rb
+++ b/activejob/test/support/integration/test_case_helpers.rb
@@ -19,7 +19,6 @@ module TestCaseHelpers
end
private
-
def jobs_manager
JobsManager.current_manager
end
diff --git a/activemodel/lib/active_model.rb b/activemodel/lib/active_model.rb
index c9140dc582..756473e38d 100644
--- a/activemodel/lib/active_model.rb
+++ b/activemodel/lib/active_model.rb
@@ -53,6 +53,7 @@ module ActiveModel
eager_autoload do
autoload :Errors
+ autoload :Error
autoload :RangeError, "active_model/errors"
autoload :StrictValidationFailed, "active_model/errors"
autoload :UnknownAttributeError, "active_model/errors"
diff --git a/activemodel/lib/active_model/attribute_assignment.rb b/activemodel/lib/active_model/attribute_assignment.rb
index f0e3458f51..9bdec0dfda 100644
--- a/activemodel/lib/active_model/attribute_assignment.rb
+++ b/activemodel/lib/active_model/attribute_assignment.rb
@@ -38,7 +38,6 @@ module ActiveModel
alias attributes= assign_attributes
private
-
def _assign_attributes(attributes)
attributes.each do |k, v|
_assign_attribute(k, v)
diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb
index 415f1f679b..1a4e0b8e59 100644
--- a/activemodel/lib/active_model/attribute_methods.rb
+++ b/activemodel/lib/active_model/attribute_methods.rb
@@ -352,11 +352,7 @@ module ActiveModel
def attribute_method_matchers_matching(method_name)
attribute_method_matchers_cache.compute_if_absent(method_name) do
- # Bump plain matcher to last place so that only methods that do not
- # match any other pattern match the actual attribute name.
- # This is currently only needed to support legacy usage.
- matchers = attribute_method_matchers.partition(&:plain?).reverse.flatten(1)
- matchers.map { |matcher| matcher.match(method_name) }.compact
+ attribute_method_matchers.map { |matcher| matcher.match(method_name) }.compact
end
end
@@ -406,10 +402,6 @@ module ActiveModel
def method_name(attr_name)
@method_name % attr_name
end
-
- def plain?
- prefix.empty? && suffix.empty?
- end
end
end
diff --git a/activemodel/lib/active_model/attribute_set.rb b/activemodel/lib/active_model/attribute_set.rb
index 4679b33852..2f5437ceda 100644
--- a/activemodel/lib/active_model/attribute_set.rb
+++ b/activemodel/lib/active_model/attribute_set.rb
@@ -94,11 +94,9 @@ module ActiveModel
end
protected
-
attr_reader :attributes
private
-
def initialized_attributes
attributes.select { |_, attr| attr.initialized? }
end
diff --git a/activemodel/lib/active_model/attributes.rb b/activemodel/lib/active_model/attributes.rb
index d176ea88d0..c586f52b78 100644
--- a/activemodel/lib/active_model/attributes.rb
+++ b/activemodel/lib/active_model/attributes.rb
@@ -42,7 +42,6 @@ module ActiveModel
end
private
-
def define_method_attribute=(name)
ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
generated_attribute_methods, name, writer: true,
@@ -114,7 +113,6 @@ module ActiveModel
end
private
-
def write_attribute(attr_name, value)
name = attr_name.to_s
name = self.class.attribute_aliases[name] || name
diff --git a/activemodel/lib/active_model/callbacks.rb b/activemodel/lib/active_model/callbacks.rb
index ea2ed7dff7..7a544395cb 100644
--- a/activemodel/lib/active_model/callbacks.rb
+++ b/activemodel/lib/active_model/callbacks.rb
@@ -126,7 +126,6 @@ module ActiveModel
end
private
-
def _define_before_model_callback(klass, callback)
klass.define_singleton_method("before_#{callback}") do |*args, **options, &block|
options.assert_valid_keys(:if, :unless, :prepend)
diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb
index 35a587658c..aaefe00c83 100644
--- a/activemodel/lib/active_model/dirty.rb
+++ b/activemodel/lib/active_model/dirty.rb
@@ -136,7 +136,7 @@ module ActiveModel
@mutations_from_database = nil
end
- # Clears dirty data and moves +changes+ to +previously_changed+ and
+ # Clears dirty data and moves +changes+ to +previous_changes+ and
# +mutations_from_database+ to +mutations_before_last_save+ respectively.
def changes_applied
unless defined?(@attributes)
diff --git a/activemodel/lib/active_model/error.rb b/activemodel/lib/active_model/error.rb
index 5a1298e27f..6deab3578d 100644
--- a/activemodel/lib/active_model/error.rb
+++ b/activemodel/lib/active_model/error.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require "active_support/core_ext/class/attribute"
+
module ActiveModel
# == Active \Model \Error
#
@@ -8,6 +10,89 @@ module ActiveModel
CALLBACKS_OPTIONS = [:if, :unless, :on, :allow_nil, :allow_blank, :strict]
MESSAGE_OPTIONS = [:message]
+ class_attribute :i18n_customize_full_message, default: false
+
+ def self.full_message(attribute, message, base_class) # :nodoc:
+ return message if attribute == :base
+ attribute = attribute.to_s
+
+ if i18n_customize_full_message && base_class.respond_to?(:i18n_scope)
+ attribute = attribute.remove(/\[\d\]/)
+ parts = attribute.split(".")
+ attribute_name = parts.pop
+ namespace = parts.join("/") unless parts.empty?
+ attributes_scope = "#{base_class.i18n_scope}.errors.models"
+
+ if namespace
+ defaults = base_class.lookup_ancestors.map do |klass|
+ [
+ :"#{attributes_scope}.#{klass.model_name.i18n_key}/#{namespace}.attributes.#{attribute_name}.format",
+ :"#{attributes_scope}.#{klass.model_name.i18n_key}/#{namespace}.format",
+ ]
+ end
+ else
+ defaults = base_class.lookup_ancestors.map do |klass|
+ [
+ :"#{attributes_scope}.#{klass.model_name.i18n_key}.attributes.#{attribute_name}.format",
+ :"#{attributes_scope}.#{klass.model_name.i18n_key}.format",
+ ]
+ end
+ end
+
+ defaults.flatten!
+ else
+ defaults = []
+ end
+
+ defaults << :"errors.format"
+ defaults << "%{attribute} %{message}"
+
+ attr_name = attribute.tr(".", "_").humanize
+ attr_name = base_class.human_attribute_name(attribute, default: attr_name)
+
+ I18n.t(defaults.shift,
+ default: defaults,
+ attribute: attr_name,
+ message: message)
+ end
+
+ def self.generate_message(attribute, type, base, options) # :nodoc:
+ type = options.delete(:message) if options[:message].is_a?(Symbol)
+ value = (attribute != :base ? base.send(:read_attribute_for_validation, attribute) : nil)
+
+ options = {
+ model: base.model_name.human,
+ attribute: base.class.human_attribute_name(attribute),
+ value: value,
+ object: base
+ }.merge!(options)
+
+ if base.class.respond_to?(:i18n_scope)
+ i18n_scope = base.class.i18n_scope.to_s
+ defaults = base.class.lookup_ancestors.flat_map do |klass|
+ [ :"#{i18n_scope}.errors.models.#{klass.model_name.i18n_key}.attributes.#{attribute}.#{type}",
+ :"#{i18n_scope}.errors.models.#{klass.model_name.i18n_key}.#{type}" ]
+ end
+ defaults << :"#{i18n_scope}.errors.messages.#{type}"
+
+ catch(:exception) do
+ translation = I18n.translate(defaults.first, options.merge(default: defaults.drop(1), throw: true))
+ return translation unless translation.nil?
+ end unless options[:message]
+ else
+ defaults = []
+ end
+
+ defaults << :"errors.attributes.#{attribute}.#{type}"
+ defaults << :"errors.messages.#{type}"
+
+ key = defaults.shift
+ defaults = options.delete(:message) if options[:message]
+ options[:default] = defaults
+
+ I18n.translate(key, options)
+ end
+
def initialize(base, attribute, type = :invalid, **options)
@base = base
@attribute = attribute
@@ -28,7 +113,7 @@ module ActiveModel
def message
case raw_type
when Symbol
- base.errors.generate_message(attribute, raw_type, options.except(*CALLBACKS_OPTIONS))
+ self.class.generate_message(attribute, raw_type, @base, options.except(*CALLBACKS_OPTIONS))
else
raw_type
end
@@ -39,7 +124,7 @@ module ActiveModel
end
def full_message
- base.errors.full_message(attribute, message)
+ self.class.full_message(attribute, message, @base.class)
end
# See if error matches provided +attribute+, +type+ and +options+.
@@ -58,9 +143,9 @@ module ActiveModel
end
def strict_match?(attribute, type, **options)
- return false unless match?(attribute, type, **options)
+ return false unless match?(attribute, type)
- full_message == Error.new(@base, attribute, type, **options).full_message
+ options == @options.except(*CALLBACKS_OPTIONS + MESSAGE_OPTIONS)
end
def ==(other)
@@ -73,9 +158,8 @@ module ActiveModel
end
protected
-
def attributes_for_hash
- [@base, @attribute, @raw_type, @options]
+ [@base, @attribute, @raw_type, @options.except(*CALLBACKS_OPTIONS)]
end
end
end
diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index d7bcfacce3..42c004ce31 100644
--- a/activemodel/lib/active_model/errors.rb
+++ b/activemodel/lib/active_model/errors.rb
@@ -4,7 +4,6 @@ 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"
-require "active_support/deprecation"
require "active_model/error"
require "active_model/nested_error"
require "forwardable"
@@ -70,11 +69,6 @@ module ActiveModel
LEGACY_ATTRIBUTES = [:messages, :details].freeze
- class << self
- attr_accessor :i18n_customize_full_message # :nodoc:
- end
- self.i18n_customize_full_message = false
-
attr_reader :errors
alias :objects :errors
@@ -199,7 +193,7 @@ module ActiveModel
matches.each do |error|
@errors.delete(error)
end
- matches.map(&:message)
+ matches.map(&:message).presence
end
# When passed a symbol or a name of a method, returns an array of errors
@@ -226,7 +220,7 @@ module ActiveModel
# # then yield :name and "must be specified"
# end
def each(&block)
- if block.arity == 1
+ if block.arity <= 1
@errors.each(&block)
else
ActiveSupport::Deprecation.warn(<<~MSG)
@@ -309,6 +303,16 @@ module ActiveModel
hash
end
+ def to_h
+ ActiveSupport::Deprecation.warn(<<~EOM)
+ ActiveModel::Errors#to_h is deprecated and will be removed in Rails 6.2
+ Please use `ActiveModel::Errors.to_hash` instead. The values in the hash
+ returned by `ActiveModel::Errors.to_hash` is an array of error messages.
+ EOM
+
+ to_hash.transform_values { |values| values.last }
+ end
+
def messages
DeprecationHandlingMessageHash.new(self)
end
@@ -468,47 +472,7 @@ module ActiveModel
#
# person.errors.full_message(:name, 'is invalid') # => "Name is invalid"
def full_message(attribute, message)
- return message if attribute == :base
- attribute = attribute.to_s
-
- if self.class.i18n_customize_full_message && @base.class.respond_to?(:i18n_scope)
- attribute = attribute.remove(/\[\d\]/)
- parts = attribute.split(".")
- attribute_name = parts.pop
- namespace = parts.join("/") unless parts.empty?
- attributes_scope = "#{@base.class.i18n_scope}.errors.models"
-
- if namespace
- defaults = @base.class.lookup_ancestors.map do |klass|
- [
- :"#{attributes_scope}.#{klass.model_name.i18n_key}/#{namespace}.attributes.#{attribute_name}.format",
- :"#{attributes_scope}.#{klass.model_name.i18n_key}/#{namespace}.format",
- ]
- end
- else
- defaults = @base.class.lookup_ancestors.map do |klass|
- [
- :"#{attributes_scope}.#{klass.model_name.i18n_key}.attributes.#{attribute_name}.format",
- :"#{attributes_scope}.#{klass.model_name.i18n_key}.format",
- ]
- end
- end
-
- defaults.flatten!
- else
- defaults = []
- end
-
- defaults << :"errors.format"
- defaults << "%{attribute} %{message}"
-
- attr_name = attribute.tr(".", "_").humanize
- attr_name = @base.class.human_attribute_name(attribute, default: attr_name)
-
- I18n.t(defaults.shift,
- default: defaults,
- attribute: attr_name,
- message: message)
+ Error.full_message(attribute, message, @base.class)
end
# Translates an error message in its default scope
@@ -536,40 +500,7 @@ module ActiveModel
# * <tt>errors.attributes.title.blank</tt>
# * <tt>errors.messages.blank</tt>
def generate_message(attribute, type = :invalid, options = {})
- type = options.delete(:message) if options[:message].is_a?(Symbol)
- value = (attribute != :base ? @base.send(:read_attribute_for_validation, attribute) : nil)
-
- options = {
- model: @base.model_name.human,
- attribute: @base.class.human_attribute_name(attribute),
- value: value,
- object: @base
- }.merge!(options)
-
- if @base.class.respond_to?(:i18n_scope)
- i18n_scope = @base.class.i18n_scope.to_s
- defaults = @base.class.lookup_ancestors.flat_map do |klass|
- [ :"#{i18n_scope}.errors.models.#{klass.model_name.i18n_key}.attributes.#{attribute}.#{type}",
- :"#{i18n_scope}.errors.models.#{klass.model_name.i18n_key}.#{type}" ]
- end
- defaults << :"#{i18n_scope}.errors.messages.#{type}"
-
- catch(:exception) do
- translation = I18n.translate(defaults.first, options.merge(default: defaults.drop(1), throw: true))
- return translation unless translation.nil?
- end unless options[:message]
- else
- defaults = []
- end
-
- defaults << :"errors.attributes.#{attribute}.#{type}"
- defaults << :"errors.messages.#{type}"
-
- key = defaults.shift
- defaults = options.delete(:message) if options[:message]
- options[:default] = defaults
-
- I18n.translate(key, options)
+ Error.generate_message(attribute, type, @base, options)
end
def marshal_load(array) # :nodoc:
@@ -594,7 +525,6 @@ module ActiveModel
end
private
-
def normalize_arguments(attribute, type, **options)
# Evaluate proc first
if type.respond_to?(:call)
@@ -640,7 +570,6 @@ module ActiveModel
end
private
-
def prepare_content
content = @errors.to_hash
content.each do |attribute, value|
diff --git a/activemodel/lib/active_model/naming.rb b/activemodel/lib/active_model/naming.rb
index bf23fa3c05..6a02d5dbf7 100644
--- a/activemodel/lib/active_model/naming.rb
+++ b/activemodel/lib/active_model/naming.rb
@@ -207,7 +207,6 @@ module ActiveModel
end
private
-
def _singularize(string)
ActiveSupport::Inflector.underscore(string).tr("/", "_")
end
diff --git a/activemodel/lib/active_model/railtie.rb b/activemodel/lib/active_model/railtie.rb
index eb7901c7e9..65e20b9791 100644
--- a/activemodel/lib/active_model/railtie.rb
+++ b/activemodel/lib/active_model/railtie.rb
@@ -14,7 +14,7 @@ module ActiveModel
end
initializer "active_model.i18n_customize_full_message" do
- ActiveModel::Errors.i18n_customize_full_message = config.active_model.delete(:i18n_customize_full_message) || false
+ ActiveModel::Error.i18n_customize_full_message = config.active_model.delete(:i18n_customize_full_message) || false
end
end
end
diff --git a/activemodel/lib/active_model/serialization.rb b/activemodel/lib/active_model/serialization.rb
index c4b7b32291..168dfa0dd2 100644
--- a/activemodel/lib/active_model/serialization.rb
+++ b/activemodel/lib/active_model/serialization.rb
@@ -150,7 +150,6 @@ module ActiveModel
end
private
-
# Hook method defining how an attribute value should be retrieved for
# serialization. By default this is assumed to be an instance named after
# the attribute. Override this method in subclasses should you need to
diff --git a/activemodel/lib/active_model/serializers/json.rb b/activemodel/lib/active_model/serializers/json.rb
index f77fb98c32..09dcae889b 100644
--- a/activemodel/lib/active_model/serializers/json.rb
+++ b/activemodel/lib/active_model/serializers/json.rb
@@ -42,6 +42,13 @@ module ActiveModel
# # => { "user" => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
# # "created_at" => "2006-08-01T17:27:13.000Z", "awesome" => true } }
#
+ # If you prefer, <tt>:root</tt> may also be set to a custom string key instead as in:
+ #
+ # user = User.find(1)
+ # user.as_json(root: "author")
+ # # => { "author" => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
+ # # "created_at" => "2006-08-01T17:27:13.000Z", "awesome" => true } }
+ #
# Without any +options+, the returned Hash will include all the model's
# attributes.
#
diff --git a/activemodel/lib/active_model/type/big_integer.rb b/activemodel/lib/active_model/type/big_integer.rb
index 89e43bcc5f..b2c3ee50aa 100644
--- a/activemodel/lib/active_model/type/big_integer.rb
+++ b/activemodel/lib/active_model/type/big_integer.rb
@@ -6,7 +6,6 @@ module ActiveModel
module Type
class BigInteger < Integer # :nodoc:
private
-
def max_value
::Float::INFINITY
end
diff --git a/activemodel/lib/active_model/type/boolean.rb b/activemodel/lib/active_model/type/boolean.rb
index e64d2c793c..1214e9319b 100644
--- a/activemodel/lib/active_model/type/boolean.rb
+++ b/activemodel/lib/active_model/type/boolean.rb
@@ -34,7 +34,6 @@ module ActiveModel
end
private
-
def cast_value(value)
if value == ""
nil
diff --git a/activemodel/lib/active_model/type/date.rb b/activemodel/lib/active_model/type/date.rb
index c5fe926039..0e96d2c8a4 100644
--- a/activemodel/lib/active_model/type/date.rb
+++ b/activemodel/lib/active_model/type/date.rb
@@ -15,7 +15,6 @@ module ActiveModel
end
private
-
def cast_value(value)
if value.is_a?(::String)
return if value.empty?
diff --git a/activemodel/lib/active_model/type/date_time.rb b/activemodel/lib/active_model/type/date_time.rb
index 133410e821..ba705be9b2 100644
--- a/activemodel/lib/active_model/type/date_time.rb
+++ b/activemodel/lib/active_model/type/date_time.rb
@@ -14,7 +14,6 @@ module ActiveModel
end
private
-
def cast_value(value)
return apply_seconds_precision(value) unless value.is_a?(::String)
return if value.empty?
diff --git a/activemodel/lib/active_model/type/decimal.rb b/activemodel/lib/active_model/type/decimal.rb
index e8ee18c00e..6aa51ff2ac 100644
--- a/activemodel/lib/active_model/type/decimal.rb
+++ b/activemodel/lib/active_model/type/decimal.rb
@@ -17,7 +17,6 @@ module ActiveModel
end
private
-
def cast_value(value)
casted_value = \
case value
diff --git a/activemodel/lib/active_model/type/float.rb b/activemodel/lib/active_model/type/float.rb
index ea1987df7c..36c7a5103c 100644
--- a/activemodel/lib/active_model/type/float.rb
+++ b/activemodel/lib/active_model/type/float.rb
@@ -19,7 +19,6 @@ module ActiveModel
end
private
-
def cast_value(value)
case value
when ::Float then value
diff --git a/activemodel/lib/active_model/type/helpers/numeric.rb b/activemodel/lib/active_model/type/helpers/numeric.rb
index 1d8171e25b..074316b559 100644
--- a/activemodel/lib/active_model/type/helpers/numeric.rb
+++ b/activemodel/lib/active_model/type/helpers/numeric.rb
@@ -24,7 +24,6 @@ module ActiveModel
end
private
-
def number_to_non_number?(old_value, new_value_before_type_cast)
old_value != nil && non_numeric_string?(new_value_before_type_cast.to_s)
end
diff --git a/activemodel/lib/active_model/type/helpers/time_value.rb b/activemodel/lib/active_model/type/helpers/time_value.rb
index 735b9a75a6..075e906034 100644
--- a/activemodel/lib/active_model/type/helpers/time_value.rb
+++ b/activemodel/lib/active_model/type/helpers/time_value.rb
@@ -11,10 +11,10 @@ module ActiveModel
value = apply_seconds_precision(value)
if value.acts_like?(:time)
- zone_conversion_method = is_utc? ? :getutc : :getlocal
-
- if value.respond_to?(zone_conversion_method)
- value = value.send(zone_conversion_method)
+ if is_utc?
+ value = value.getutc if value.respond_to?(:getutc) && !value.utc?
+ else
+ value = value.getlocal if value.respond_to?(:getlocal)
end
end
@@ -22,10 +22,17 @@ module ActiveModel
end
def apply_seconds_precision(value)
- return value unless precision && value.respond_to?(:usec)
- number_of_insignificant_digits = 6 - precision
+ return value unless precision && value.respond_to?(:nsec)
+
+ number_of_insignificant_digits = 9 - precision
round_power = 10**number_of_insignificant_digits
- value.change(usec: value.usec - value.usec % round_power)
+ rounded_off_nsec = value.nsec % round_power
+
+ if rounded_off_nsec > 0
+ value.change(nsec: value.nsec - rounded_off_nsec)
+ else
+ value
+ end
end
def type_cast_for_schema(value)
@@ -37,7 +44,6 @@ module ActiveModel
end
private
-
def new_time(year, mon, mday, hour, min, sec, microsec, offset = nil)
# Treat 0000-00-00 00:00:00 as nil.
return if year.nil? || (year == 0 && mon == 0 && mday == 0)
diff --git a/activemodel/lib/active_model/type/immutable_string.rb b/activemodel/lib/active_model/type/immutable_string.rb
index 826bd7038f..18e12c54d1 100644
--- a/activemodel/lib/active_model/type/immutable_string.rb
+++ b/activemodel/lib/active_model/type/immutable_string.rb
@@ -17,7 +17,6 @@ module ActiveModel
end
private
-
def cast_value(value)
result = \
case value
diff --git a/activemodel/lib/active_model/type/integer.rb b/activemodel/lib/active_model/type/integer.rb
index 1e1061ff60..e9bbdf4b7b 100644
--- a/activemodel/lib/active_model/type/integer.rb
+++ b/activemodel/lib/active_model/type/integer.rb
@@ -18,6 +18,11 @@ module ActiveModel
:integer
end
+ def deserialize(value)
+ return if value.blank?
+ value.to_i
+ end
+
def serialize(value)
return if value.is_a?(::String) && non_numeric_string?(value)
ensure_in_range(super)
diff --git a/activemodel/lib/active_model/type/string.rb b/activemodel/lib/active_model/type/string.rb
index a9c9bfadb6..0d9f4a63b4 100644
--- a/activemodel/lib/active_model/type/string.rb
+++ b/activemodel/lib/active_model/type/string.rb
@@ -12,7 +12,6 @@ module ActiveModel
end
private
-
def cast_value(value)
case value
when ::String then ::String.new(value)
diff --git a/activemodel/lib/active_model/type/time.rb b/activemodel/lib/active_model/type/time.rb
index 61847a4ce7..f230bd4257 100644
--- a/activemodel/lib/active_model/type/time.rb
+++ b/activemodel/lib/active_model/type/time.rb
@@ -29,7 +29,6 @@ module ActiveModel
end
private
-
def cast_value(value)
return apply_seconds_precision(value) unless value.is_a?(::String)
return if value.empty?
diff --git a/activemodel/lib/active_model/type/value.rb b/activemodel/lib/active_model/type/value.rb
index b6914dd63c..788ded3e96 100644
--- a/activemodel/lib/active_model/type/value.rb
+++ b/activemodel/lib/active_model/type/value.rb
@@ -110,11 +110,10 @@ module ActiveModel
[self.class, precision, scale, limit].hash
end
- def assert_valid_value(*)
+ def assert_valid_value(_)
end
private
-
# Convenience method for types which do not need separate type casting
# behavior for user and database inputs. Called by Value#cast for
# values except +nil+.
diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb
index f18f9a601a..4a6b464131 100644
--- a/activemodel/lib/active_model/validations.rb
+++ b/activemodel/lib/active_model/validations.rb
@@ -402,7 +402,6 @@ module ActiveModel
alias :read_attribute_for_validation :send
private
-
def run_validations!
_run_validate_callbacks
errors.empty?
diff --git a/activemodel/lib/active_model/validations/acceptance.rb b/activemodel/lib/active_model/validations/acceptance.rb
index 6fd54270f2..1b96575a10 100644
--- a/activemodel/lib/active_model/validations/acceptance.rb
+++ b/activemodel/lib/active_model/validations/acceptance.rb
@@ -15,7 +15,6 @@ module ActiveModel
end
private
-
def setup!(klass)
klass.include(LazilyDefineAttributes.new(AttributeDefinition.new(attributes)))
end
diff --git a/activemodel/lib/active_model/validations/callbacks.rb b/activemodel/lib/active_model/validations/callbacks.rb
index 887d31ae2a..7178ba99e9 100644
--- a/activemodel/lib/active_model/validations/callbacks.rb
+++ b/activemodel/lib/active_model/validations/callbacks.rb
@@ -112,7 +112,6 @@ module ActiveModel
end
private
-
# Overwrite run validations to include callbacks.
def run_validations!
_run_validation_callbacks { super }
diff --git a/activemodel/lib/active_model/validations/clusivity.rb b/activemodel/lib/active_model/validations/clusivity.rb
index bafb8e2106..fb9f48301c 100644
--- a/activemodel/lib/active_model/validations/clusivity.rb
+++ b/activemodel/lib/active_model/validations/clusivity.rb
@@ -15,7 +15,6 @@ module ActiveModel
end
private
-
def include?(record, value)
members = if delimiter.respond_to?(:call)
delimiter.call(record)
diff --git a/activemodel/lib/active_model/validations/format.rb b/activemodel/lib/active_model/validations/format.rb
index 7c3f091473..bea57415b0 100644
--- a/activemodel/lib/active_model/validations/format.rb
+++ b/activemodel/lib/active_model/validations/format.rb
@@ -23,7 +23,6 @@ module ActiveModel
end
private
-
def option_call(record, name)
option = options[name]
option.respond_to?(:call) ? option.call(record) : option
diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb
index 51e224d5cd..e7be668e9d 100644
--- a/activemodel/lib/active_model/validations/numericality.rb
+++ b/activemodel/lib/active_model/validations/numericality.rb
@@ -79,7 +79,6 @@ module ActiveModel
end
private
-
def is_number?(raw_value)
!parse_as_number(raw_value).nil?
rescue ArgumentError, TypeError
diff --git a/activemodel/lib/active_model/validations/validates.rb b/activemodel/lib/active_model/validations/validates.rb
index 21c4ce0dfe..97612d474d 100644
--- a/activemodel/lib/active_model/validations/validates.rb
+++ b/activemodel/lib/active_model/validations/validates.rb
@@ -150,7 +150,6 @@ module ActiveModel
end
private
-
# When creating custom validators, it might be useful to be able to specify
# additional default keys. This can be done by overwriting this method.
def _validates_default_keys
diff --git a/activemodel/lib/active_model/validator.rb b/activemodel/lib/active_model/validator.rb
index 94d53b8dd1..3ba6acea15 100644
--- a/activemodel/lib/active_model/validator.rb
+++ b/activemodel/lib/active_model/validator.rb
@@ -175,7 +175,6 @@ module ActiveModel
end
private
-
def validate_each(record, attribute, value)
@block.call(record, attribute, value)
end
diff --git a/activemodel/test/cases/attribute_methods_test.rb b/activemodel/test/cases/attribute_methods_test.rb
index 4e228032c3..e3b3b15f25 100644
--- a/activemodel/test/cases/attribute_methods_test.rb
+++ b/activemodel/test/cases/attribute_methods_test.rb
@@ -40,7 +40,6 @@ private
end
protected
-
def protected_method
"O_o O_o"
end
diff --git a/activemodel/test/cases/errors_test.rb b/activemodel/test/cases/errors_test.rb
index baaf404f2e..a6cd1da717 100644
--- a/activemodel/test/cases/errors_test.rb
+++ b/activemodel/test/cases/errors_test.rb
@@ -44,6 +44,14 @@ class ErrorsTest < ActiveModel::TestCase
assert_includes errors, "foo", "errors should include 'foo' as :foo"
end
+ def test_each_when_arity_is_negative
+ errors = ActiveModel::Errors.new(Person.new)
+ errors.add(:name, :blank)
+ errors.add(:gender, :blank)
+
+ assert_equal([:name, :gender], errors.map(&:attribute))
+ end
+
def test_any?
errors = ActiveModel::Errors.new(Person.new)
errors.add(:name)
@@ -274,6 +282,28 @@ class ErrorsTest < ActiveModel::TestCase
assert_equal [msg], person.errors[:name]
end
+ test "added? when attribute was added through a collection" do
+ person = Person.new
+ person.errors.add(:"family_members.name", :too_long, count: 25)
+ assert person.errors.added?(:"family_members.name", :too_long, count: 25)
+ assert_not person.errors.added?(:"family_members.name", :too_long)
+ assert_not person.errors.added?(:"family_members.name", :too_long, name: "hello")
+ end
+
+ test "added? ignores callback option" do
+ person = Person.new
+
+ person.errors.add(:name, :too_long, if: -> { true })
+ assert person.errors.added?(:name, :too_long)
+ end
+
+ test "added? ignores message option" do
+ person = Person.new
+
+ person.errors.add(:name, :too_long, message: proc { "foo" })
+ assert person.errors.added?(:name, :too_long)
+ end
+
test "added? detects indifferent if a specific error was added to the object" do
person = Person.new
person.errors.add(:name, "cannot be blank")
@@ -444,6 +474,17 @@ class ErrorsTest < ActiveModel::TestCase
assert_equal ["name cannot be blank", "name cannot be nil"], person.errors.to_a
end
+ test "to_h is deprecated" do
+ person = Person.new
+ person.errors.add(:name, "cannot be blank")
+ person.errors.add(:name, "too long")
+
+ expected_deprecation = "ActiveModel::Errors#to_h is deprecated"
+ assert_deprecated(expected_deprecation) do
+ assert_equal({ name: "too long" }, person.errors.to_h)
+ end
+ end
+
test "to_hash returns the error messages hash" do
person = Person.new
person.errors.add(:name, "cannot be blank")
@@ -460,6 +501,27 @@ class ErrorsTest < ActiveModel::TestCase
assert_nil person.errors.as_json.default_proc
end
+ test "full_messages doesn't require the base object to respond to `:errors" do
+ model = Class.new do
+ def initialize
+ @errors = ActiveModel::Errors.new(self)
+ @errors.add(:name, "bar")
+ end
+
+ def self.human_attribute_name(attr, options = {})
+ "foo"
+ end
+
+ def call
+ error_wrapper = Struct.new(:model_errors)
+
+ error_wrapper.new(@errors)
+ end
+ end
+
+ assert_equal(["foo bar"], model.new.call.model_errors.full_messages)
+ end
+
test "full_messages creates a list of error messages with the attribute name included" do
person = Person.new
person.errors.add(:name, "cannot be blank")
@@ -573,6 +635,12 @@ class ErrorsTest < ActiveModel::TestCase
assert_not_equal errors_dup.details, errors.details
end
+ test "delete returns nil when no errors were deleted" do
+ errors = ActiveModel::Errors.new(Person.new)
+
+ assert_nil(errors.delete(:name))
+ end
+
test "delete removes details on given attribute" do
errors = ActiveModel::Errors.new(Person.new)
errors.add(:name, :invalid)
diff --git a/activemodel/test/cases/nested_error_test.rb b/activemodel/test/cases/nested_error_test.rb
index 5bad100da5..6c2458ba83 100644
--- a/activemodel/test/cases/nested_error_test.rb
+++ b/activemodel/test/cases/nested_error_test.rb
@@ -5,7 +5,7 @@ require "active_model/nested_error"
require "models/topic"
require "models/reply"
-class ErrorTest < ActiveModel::TestCase
+class NestedErrorTest < ActiveModel::TestCase
def test_initialize
topic = Topic.new
inner_error = ActiveModel::Error.new(topic, :title, :not_enough, count: 2)
diff --git a/activemodel/test/cases/railtie_test.rb b/activemodel/test/cases/railtie_test.rb
index 95ee7cace3..f5ff1a3fd7 100644
--- a/activemodel/test/cases/railtie_test.rb
+++ b/activemodel/test/cases/railtie_test.rb
@@ -35,20 +35,20 @@ class RailtieTest < ActiveModel::TestCase
test "i18n customize full message defaults to false" do
@app.initialize!
- assert_equal false, ActiveModel::Errors.i18n_customize_full_message
+ assert_equal false, ActiveModel::Error.i18n_customize_full_message
end
test "i18n customize full message can be disabled" do
@app.config.active_model.i18n_customize_full_message = false
@app.initialize!
- assert_equal false, ActiveModel::Errors.i18n_customize_full_message
+ assert_equal false, ActiveModel::Error.i18n_customize_full_message
end
test "i18n customize full message can be enabled" do
@app.config.active_model.i18n_customize_full_message = true
@app.initialize!
- assert_equal true, ActiveModel::Errors.i18n_customize_full_message
+ assert_equal true, ActiveModel::Error.i18n_customize_full_message
end
end
diff --git a/activemodel/test/cases/type/date_time_test.rb b/activemodel/test/cases/type/date_time_test.rb
index 74b47d1b4d..4a63eee0cf 100644
--- a/activemodel/test/cases/type/date_time_test.rb
+++ b/activemodel/test/cases/type/date_time_test.rb
@@ -37,7 +37,6 @@ module ActiveModel
end
private
-
def with_timezone_config(default:)
old_zone_default = ::Time.zone_default
::Time.zone_default = ::Time.find_zone(default)
diff --git a/activemodel/test/cases/validations/acceptance_validation_test.rb b/activemodel/test/cases/validations/acceptance_validation_test.rb
index 72baf6e7a7..6bd3d292f8 100644
--- a/activemodel/test/cases/validations/acceptance_validation_test.rb
+++ b/activemodel/test/cases/validations/acceptance_validation_test.rb
@@ -92,7 +92,6 @@ class AcceptanceValidationTest < ActiveModel::TestCase
end
private
-
# Acceptance validator includes anonymous module into class, which cannot
# be cleared, so to avoid multiple inclusions we use a named subclass which
# we can remove in teardown.
diff --git a/activemodel/test/cases/validations/i18n_validation_test.rb b/activemodel/test/cases/validations/i18n_validation_test.rb
index b7ee50832c..c81649f493 100644
--- a/activemodel/test/cases/validations/i18n_validation_test.rb
+++ b/activemodel/test/cases/validations/i18n_validation_test.rb
@@ -13,8 +13,8 @@ class I18nValidationTest < ActiveModel::TestCase
I18n.backend = I18n::Backend::Simple.new
I18n.backend.store_translations("en", errors: { messages: { custom: nil } })
- @original_i18n_customize_full_message = ActiveModel::Errors.i18n_customize_full_message
- ActiveModel::Errors.i18n_customize_full_message = true
+ @original_i18n_customize_full_message = ActiveModel::Error.i18n_customize_full_message
+ ActiveModel::Error.i18n_customize_full_message = true
end
def teardown
@@ -24,7 +24,7 @@ class I18nValidationTest < ActiveModel::TestCase
I18n.load_path.replace @old_load_path
I18n.backend = @old_backend
I18n.backend.reload!
- ActiveModel::Errors.i18n_customize_full_message = @original_i18n_customize_full_message
+ ActiveModel::Error.i18n_customize_full_message = @original_i18n_customize_full_message
end
def test_full_message_encoding
@@ -49,7 +49,7 @@ class I18nValidationTest < ActiveModel::TestCase
end
def test_errors_full_messages_doesnt_use_attribute_format_without_config
- ActiveModel::Errors.i18n_customize_full_message = false
+ ActiveModel::Error.i18n_customize_full_message = false
I18n.backend.store_translations("en", activemodel: {
errors: { models: { person: { attributes: { name: { format: "%{message}" } } } } } })
@@ -59,8 +59,21 @@ class I18nValidationTest < ActiveModel::TestCase
assert_equal "Name test cannot be blank", person.errors.full_message(:name_test, "cannot be blank")
end
+ def test_errors_full_messages_on_nested_error_uses_attribute_format
+ ActiveModel::Error.i18n_customize_full_message = true
+ I18n.backend.store_translations("en", activemodel: {
+ errors: { models: { person: { attributes: { gender: "Gender" } } } },
+ attributes: { "person/contacts": { gender: "Gender" } }
+ })
+
+ person = person_class.new
+ error = ActiveModel::Error.new(person, :gender, "can't be blank")
+ person.errors.import(error, attribute: "person[0].contacts.gender")
+ assert_equal ["Gender can't be blank"], person.errors.full_messages
+ end
+
def test_errors_full_messages_uses_attribute_format
- ActiveModel::Errors.i18n_customize_full_message = true
+ ActiveModel::Error.i18n_customize_full_message = true
I18n.backend.store_translations("en", activemodel: {
errors: { models: { person: { attributes: { name: { format: "%{message}" } } } } } })
@@ -71,7 +84,7 @@ class I18nValidationTest < ActiveModel::TestCase
end
def test_errors_full_messages_uses_model_format
- ActiveModel::Errors.i18n_customize_full_message = true
+ ActiveModel::Error.i18n_customize_full_message = true
I18n.backend.store_translations("en", activemodel: {
errors: { models: { person: { format: "%{message}" } } } })
@@ -82,7 +95,7 @@ class I18nValidationTest < ActiveModel::TestCase
end
def test_errors_full_messages_uses_deeply_nested_model_attributes_format
- ActiveModel::Errors.i18n_customize_full_message = true
+ ActiveModel::Error.i18n_customize_full_message = true
I18n.backend.store_translations("en", activemodel: {
errors: { models: { 'person/contacts/addresses': { attributes: { street: { format: "%{message}" } } } } } })
@@ -93,7 +106,7 @@ class I18nValidationTest < ActiveModel::TestCase
end
def test_errors_full_messages_uses_deeply_nested_model_model_format
- ActiveModel::Errors.i18n_customize_full_message = true
+ ActiveModel::Error.i18n_customize_full_message = true
I18n.backend.store_translations("en", activemodel: {
errors: { models: { 'person/contacts/addresses': { format: "%{message}" } } } })
@@ -104,7 +117,7 @@ class I18nValidationTest < ActiveModel::TestCase
end
def test_errors_full_messages_with_indexed_deeply_nested_attributes_and_attributes_format
- ActiveModel::Errors.i18n_customize_full_message = true
+ ActiveModel::Error.i18n_customize_full_message = true
I18n.backend.store_translations("en", activemodel: {
errors: { models: { 'person/contacts/addresses': { attributes: { street: { format: "%{message}" } } } } } })
@@ -115,7 +128,7 @@ class I18nValidationTest < ActiveModel::TestCase
end
def test_errors_full_messages_with_indexed_deeply_nested_attributes_and_model_format
- ActiveModel::Errors.i18n_customize_full_message = true
+ ActiveModel::Error.i18n_customize_full_message = true
I18n.backend.store_translations("en", activemodel: {
errors: { models: { 'person/contacts/addresses': { format: "%{message}" } } } })
@@ -126,7 +139,7 @@ class I18nValidationTest < ActiveModel::TestCase
end
def test_errors_full_messages_with_indexed_deeply_nested_attributes_and_i18n_attribute_name
- ActiveModel::Errors.i18n_customize_full_message = true
+ ActiveModel::Error.i18n_customize_full_message = true
I18n.backend.store_translations("en", activemodel: {
attributes: { 'person/contacts/addresses': { country: "Country" } }
@@ -138,7 +151,7 @@ class I18nValidationTest < ActiveModel::TestCase
end
def test_errors_full_messages_with_indexed_deeply_nested_attributes_without_i18n_config
- ActiveModel::Errors.i18n_customize_full_message = false
+ ActiveModel::Error.i18n_customize_full_message = false
I18n.backend.store_translations("en", activemodel: {
errors: { models: { 'person/contacts/addresses': { attributes: { street: { format: "%{message}" } } } } } })
@@ -149,7 +162,7 @@ class I18nValidationTest < ActiveModel::TestCase
end
def test_errors_full_messages_with_i18n_attribute_name_without_i18n_config
- ActiveModel::Errors.i18n_customize_full_message = false
+ ActiveModel::Error.i18n_customize_full_message = false
I18n.backend.store_translations("en", activemodel: {
attributes: { 'person/contacts[0]/addresses[0]': { country: "Country" } }
@@ -178,8 +191,8 @@ class I18nValidationTest < ActiveModel::TestCase
test "validates_confirmation_of on generated message #{name}" do
person_class.validates_confirmation_of :title, validation_options
@person.title_confirmation = "foo"
- call = [:title_confirmation, :confirmation, generate_message_options.merge(attribute: "Title")]
- assert_called_with(@person.errors, :generate_message, call) do
+ call = [:title_confirmation, :confirmation, @person, generate_message_options.merge(attribute: "Title")]
+ assert_called_with(ActiveModel::Error, :generate_message, call) do
@person.valid?
@person.errors.messages
end
@@ -189,8 +202,8 @@ class I18nValidationTest < ActiveModel::TestCase
COMMON_CASES.each do |name, validation_options, generate_message_options|
test "validates_acceptance_of on generated message #{name}" do
person_class.validates_acceptance_of :title, validation_options.merge(allow_nil: false)
- call = [:title, :accepted, generate_message_options]
- assert_called_with(@person.errors, :generate_message, call) do
+ call = [:title, :accepted, @person, generate_message_options]
+ assert_called_with(ActiveModel::Error, :generate_message, call) do
@person.valid?
@person.errors.messages
end
@@ -200,8 +213,8 @@ class I18nValidationTest < ActiveModel::TestCase
COMMON_CASES.each do |name, validation_options, generate_message_options|
test "validates_presence_of on generated message #{name}" do
person_class.validates_presence_of :title, validation_options
- call = [:title, :blank, generate_message_options]
- assert_called_with(@person.errors, :generate_message, call) do
+ call = [:title, :blank, @person, generate_message_options]
+ assert_called_with(ActiveModel::Error, :generate_message, call) do
@person.valid?
@person.errors.messages
end
@@ -211,8 +224,8 @@ class I18nValidationTest < ActiveModel::TestCase
COMMON_CASES.each do |name, validation_options, generate_message_options|
test "validates_length_of for :within on generated message when too short #{name}" do
person_class.validates_length_of :title, validation_options.merge(within: 3..5)
- call = [:title, :too_short, generate_message_options.merge(count: 3)]
- assert_called_with(@person.errors, :generate_message, call) do
+ call = [:title, :too_short, @person, generate_message_options.merge(count: 3)]
+ assert_called_with(ActiveModel::Error, :generate_message, call) do
@person.valid?
@person.errors.messages
end
@@ -223,8 +236,8 @@ class I18nValidationTest < ActiveModel::TestCase
test "validates_length_of for :too_long generated message #{name}" do
person_class.validates_length_of :title, validation_options.merge(within: 3..5)
@person.title = "this title is too long"
- call = [:title, :too_long, generate_message_options.merge(count: 5)]
- assert_called_with(@person.errors, :generate_message, call) do
+ call = [:title, :too_long, @person, generate_message_options.merge(count: 5)]
+ assert_called_with(ActiveModel::Error, :generate_message, call) do
@person.valid?
@person.errors.messages
end
@@ -234,8 +247,8 @@ class I18nValidationTest < ActiveModel::TestCase
COMMON_CASES.each do |name, validation_options, generate_message_options|
test "validates_length_of for :is on generated message #{name}" do
person_class.validates_length_of :title, validation_options.merge(is: 5)
- call = [:title, :wrong_length, generate_message_options.merge(count: 5)]
- assert_called_with(@person.errors, :generate_message, call) do
+ call = [:title, :wrong_length, @person, generate_message_options.merge(count: 5)]
+ assert_called_with(ActiveModel::Error, :generate_message, call) do
@person.valid?
@person.errors.messages
end
@@ -246,8 +259,8 @@ class I18nValidationTest < ActiveModel::TestCase
test "validates_format_of on generated message #{name}" do
person_class.validates_format_of :title, validation_options.merge(with: /\A[1-9][0-9]*\z/)
@person.title = "72x"
- call = [:title, :invalid, generate_message_options.merge(value: "72x")]
- assert_called_with(@person.errors, :generate_message, call) do
+ call = [:title, :invalid, @person, generate_message_options.merge(value: "72x")]
+ assert_called_with(ActiveModel::Error, :generate_message, call) do
@person.valid?
@person.errors.messages
end
@@ -258,8 +271,8 @@ class I18nValidationTest < ActiveModel::TestCase
test "validates_inclusion_of on generated message #{name}" do
person_class.validates_inclusion_of :title, validation_options.merge(in: %w(a b c))
@person.title = "z"
- call = [:title, :inclusion, generate_message_options.merge(value: "z")]
- assert_called_with(@person.errors, :generate_message, call) do
+ call = [:title, :inclusion, @person, generate_message_options.merge(value: "z")]
+ assert_called_with(ActiveModel::Error, :generate_message, call) do
@person.valid?
@person.errors.messages
end
@@ -270,8 +283,8 @@ class I18nValidationTest < ActiveModel::TestCase
test "validates_inclusion_of using :within on generated message #{name}" do
person_class.validates_inclusion_of :title, validation_options.merge(within: %w(a b c))
@person.title = "z"
- call = [:title, :inclusion, generate_message_options.merge(value: "z")]
- assert_called_with(@person.errors, :generate_message, call) do
+ call = [:title, :inclusion, @person, generate_message_options.merge(value: "z")]
+ assert_called_with(ActiveModel::Error, :generate_message, call) do
@person.valid?
@person.errors.messages
end
@@ -282,8 +295,8 @@ class I18nValidationTest < ActiveModel::TestCase
test "validates_exclusion_of generated message #{name}" do
person_class.validates_exclusion_of :title, validation_options.merge(in: %w(a b c))
@person.title = "a"
- call = [:title, :exclusion, generate_message_options.merge(value: "a")]
- assert_called_with(@person.errors, :generate_message, call) do
+ call = [:title, :exclusion, @person, generate_message_options.merge(value: "a")]
+ assert_called_with(ActiveModel::Error, :generate_message, call) do
@person.valid?
@person.errors.messages
end
@@ -294,8 +307,8 @@ class I18nValidationTest < ActiveModel::TestCase
test "validates_exclusion_of using :within generated message #{name}" do
person_class.validates_exclusion_of :title, validation_options.merge(within: %w(a b c))
@person.title = "a"
- call = [:title, :exclusion, generate_message_options.merge(value: "a")]
- assert_called_with(@person.errors, :generate_message, call) do
+ call = [:title, :exclusion, @person, generate_message_options.merge(value: "a")]
+ assert_called_with(ActiveModel::Error, :generate_message, call) do
@person.valid?
@person.errors.messages
end
@@ -306,8 +319,8 @@ class I18nValidationTest < ActiveModel::TestCase
test "validates_numericality_of generated message #{name}" do
person_class.validates_numericality_of :title, validation_options
@person.title = "a"
- call = [:title, :not_a_number, generate_message_options.merge(value: "a")]
- assert_called_with(@person.errors, :generate_message, call) do
+ call = [:title, :not_a_number, @person, generate_message_options.merge(value: "a")]
+ assert_called_with(ActiveModel::Error, :generate_message, call) do
@person.valid?
@person.errors.messages
end
@@ -318,8 +331,8 @@ class I18nValidationTest < ActiveModel::TestCase
test "validates_numericality_of for :only_integer on generated message #{name}" do
person_class.validates_numericality_of :title, validation_options.merge(only_integer: true)
@person.title = "0.0"
- call = [:title, :not_an_integer, generate_message_options.merge(value: "0.0")]
- assert_called_with(@person.errors, :generate_message, call) do
+ call = [:title, :not_an_integer, @person, generate_message_options.merge(value: "0.0")]
+ assert_called_with(ActiveModel::Error, :generate_message, call) do
@person.valid?
@person.errors.messages
end
@@ -330,8 +343,8 @@ class I18nValidationTest < ActiveModel::TestCase
test "validates_numericality_of for :odd on generated message #{name}" do
person_class.validates_numericality_of :title, validation_options.merge(only_integer: true, odd: true)
@person.title = 0
- call = [:title, :odd, generate_message_options.merge(value: 0)]
- assert_called_with(@person.errors, :generate_message, call) do
+ call = [:title, :odd, @person, generate_message_options.merge(value: 0)]
+ assert_called_with(ActiveModel::Error, :generate_message, call) do
@person.valid?
@person.errors.messages
end
@@ -342,8 +355,8 @@ class I18nValidationTest < ActiveModel::TestCase
test "validates_numericality_of for :less_than on generated message #{name}" do
person_class.validates_numericality_of :title, validation_options.merge(only_integer: true, less_than: 0)
@person.title = 1
- call = [:title, :less_than, generate_message_options.merge(value: 1, count: 0)]
- assert_called_with(@person.errors, :generate_message, call) do
+ call = [:title, :less_than, @person, generate_message_options.merge(value: 1, count: 0)]
+ assert_called_with(ActiveModel::Error, :generate_message, call) do
@person.valid?
@person.errors.messages
end
diff --git a/activemodel/test/cases/validations/numericality_validation_test.rb b/activemodel/test/cases/validations/numericality_validation_test.rb
index 16c44762cb..191af033df 100644
--- a/activemodel/test/cases/validations/numericality_validation_test.rb
+++ b/activemodel/test/cases/validations/numericality_validation_test.rb
@@ -310,7 +310,6 @@ class NumericalityValidationTest < ActiveModel::TestCase
end
private
-
def invalid!(values, error = nil)
with_each_topic_approved_value(values) do |topic, value|
assert topic.invalid?, "#{value.inspect} not rejected as a number"
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index f708d42e43..2af48f99db 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,60 @@
+* Add a warning for enum elements with 'not_' prefix.
+
+ class Foo
+ enum status: [:sent, :not_sent]
+ end
+
+ *Edu Depetris*
+
+* Make currency symbols optional for money column type in PostgreSQL
+
+ *Joel Schneider*
+
+* Add support for beginless ranges, introduced in Ruby 2.7.
+
+ *Josh Goodall*
+
+* Add database_exists? method to connection adapters to check if a database exists.
+
+ *Guilherme Mansur*
+
+* Loading the schema for a model that has no `table_name` raises a `TableNotSpecified` error.
+
+ *Guilherme Mansur*, *Eugene Kenny*
+
+* PostgreSQL: Fix GROUP BY with ORDER BY virtual count attribute.
+
+ Fixes #36022.
+
+ *Ryuta Kamizono*
+
+* Make ActiveRecord `ConnectionPool.connections` method thread-safe.
+
+ Fixes #36465.
+
+ *Jeff Doering*
+
+* Add support for multiple databases to `rails db:abort_if_pending_migrations`.
+
+ *Mark Lee*
+
+* Fix sqlite3 collation parsing when using decimal columns.
+
+ *Martin R. Schuster*
+
+* Fix invalid schema when primary key column has a comment.
+
+ Fixes #29966.
+
+ *Guilherme Goettems Schneider*
+
+* Fix table comment also being applied to the primary key column.
+
+ *Guilherme Goettems Schneider*
+
+* Allow generated `create_table` migrations to include or skip timestamps.
+
+ *Michael Duchemin*
Please check [6-0-stable](https://github.com/rails/rails/blob/6-0-stable/activerecord/CHANGELOG.md) for previous changes.
diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb
index 3250e29b82..aa08124158 100644
--- a/activerecord/lib/active_record/aggregations.rb
+++ b/activerecord/lib/active_record/aggregations.rb
@@ -14,7 +14,6 @@ module ActiveRecord
end
private
-
def clear_aggregation_cache
@aggregation_cache.clear if persisted?
end
diff --git a/activerecord/lib/active_record/association_relation.rb b/activerecord/lib/active_record/association_relation.rb
index 4c538ef2bd..de9892e48d 100644
--- a/activerecord/lib/active_record/association_relation.rb
+++ b/activerecord/lib/active_record/association_relation.rb
@@ -29,7 +29,6 @@ module ActiveRecord
end
private
-
def exec_queries
super do |record|
@association.set_inverse_instance_from_queries(record)
diff --git a/activerecord/lib/active_record/associations/alias_tracker.rb b/activerecord/lib/active_record/associations/alias_tracker.rb
index 272eede824..ac90ba0137 100644
--- a/activerecord/lib/active_record/associations/alias_tracker.rb
+++ b/activerecord/lib/active_record/associations/alias_tracker.rb
@@ -72,7 +72,6 @@ module ActiveRecord
attr_reader :aliases
private
-
def truncate(name)
name.slice(0, @connection.table_alias_length - 2)
end
diff --git a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb
index 0140aa15c8..6ad4c75fb5 100644
--- a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb
+++ b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb
@@ -46,7 +46,6 @@ module ActiveRecord::Associations::Builder # :nodoc:
end
private
-
def self.suppress_composite_primary_key(pk)
pk unless pk.is_a?(Array)
end
@@ -73,7 +72,6 @@ module ActiveRecord::Associations::Builder # :nodoc:
end
private
-
def middle_options(join_model)
middle_options = {}
middle_options[:class_name] = "#{lhs_model.name}::#{join_model.name}"
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index c3d4eab562..891b50d160 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -56,7 +56,7 @@ module ActiveRecord
def ids_writer(ids)
primary_key = reflection.association_primary_key
pk_type = klass.type_for_attribute(primary_key)
- ids = Array(ids).reject(&:blank?)
+ ids = Array(ids).compact_blank
ids.map! { |i| pk_type.cast(i) }
records = klass.where(primary_key => ids).index_by do |r|
diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb
index 85e0f076da..0db0ad8595 100644
--- a/activerecord/lib/active_record/associations/collection_proxy.rb
+++ b/activerecord/lib/active_record/associations/collection_proxy.rb
@@ -1029,7 +1029,7 @@ module ActiveRecord
alias_method :append, :<<
alias_method :concat, :<<
- def prepend(*args)
+ def prepend(*args) # :nodoc:
raise NoMethodError, "prepend on association is not defined. Please use <<, push or append"
end
@@ -1101,7 +1101,6 @@ module ActiveRecord
delegate(*delegate_methods, to: :scope)
private
-
def find_nth_with_limit(index, limit)
load_target if find_from_target?
super
diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb
index 5972846940..dd2ed55279 100644
--- a/activerecord/lib/active_record/associations/has_many_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_association.rb
@@ -37,7 +37,6 @@ module ActiveRecord
end
private
-
# Returns the number of records in this collection.
#
# If the association has a counter cache it gets that value. Otherwise
diff --git a/activerecord/lib/active_record/associations/join_dependency/join_association.rb b/activerecord/lib/active_record/associations/join_dependency/join_association.rb
index ca0305abbb..6a7e92dc28 100644
--- a/activerecord/lib/active_record/associations/join_dependency/join_association.rb
+++ b/activerecord/lib/active_record/associations/join_dependency/join_association.rb
@@ -44,8 +44,7 @@ module ActiveRecord
unless others.empty?
joins.concat arel.join_sources
- right = joins.last.right
- right.expr.children.concat(others)
+ append_constraints(joins.last, others)
end
# The current table in this iteration becomes the foreign table in the next
@@ -65,6 +64,16 @@ module ActiveRecord
@readonly = reflection.scope && reflection.scope_for(base_klass.unscoped).readonly_value
end
+
+ private
+ def append_constraints(join, constraints)
+ if join.is_a?(Arel::Nodes::StringJoin)
+ join_string = table.create_and(constraints.unshift(join.left))
+ join.left = Arel.sql(base_klass.connection.visitor.compile(join_string))
+ else
+ join.right.expr.children.concat(constraints)
+ end
+ end
end
end
end
diff --git a/activerecord/lib/active_record/associations/preloader.rb b/activerecord/lib/active_record/associations/preloader.rb
index 6b57e5093a..d4e8b364e1 100644
--- a/activerecord/lib/active_record/associations/preloader.rb
+++ b/activerecord/lib/active_record/associations/preloader.rb
@@ -95,7 +95,6 @@ module ActiveRecord
end
private
-
# Loads all the given data into +records+ for the +association+.
def preloaders_on(association, records, scope, polymorphic_parent = false)
case association
diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb
index 342d9e7a5a..4c7b0e6f07 100644
--- a/activerecord/lib/active_record/associations/preloader/association.rb
+++ b/activerecord/lib/active_record/associations/preloader/association.rb
@@ -27,7 +27,9 @@ module ActiveRecord
end
def records_by_owner
- @records_by_owner ||= preloaded_records.each_with_object({}) do |record, result|
+ # owners can be duplicated when a relation has a collection association join
+ # #compare_by_identity makes such owners different hash keys
+ @records_by_owner ||= preloaded_records.each_with_object({}.compare_by_identity) do |record, result|
owners_by_key[convert_key(record[association_key_name])].each do |owner|
(result[owner] ||= []) << record
end
diff --git a/activerecord/lib/active_record/attribute_assignment.rb b/activerecord/lib/active_record/attribute_assignment.rb
index 929045f29b..acb8ba7e5a 100644
--- a/activerecord/lib/active_record/attribute_assignment.rb
+++ b/activerecord/lib/active_record/attribute_assignment.rb
@@ -7,7 +7,6 @@ module ActiveRecord
include ActiveModel::AttributeAssignment
private
-
def _assign_attributes(attributes)
multi_parameter_attributes = {}
nested_parameter_attributes = {}
diff --git a/activerecord/lib/active_record/attribute_decorators.rb b/activerecord/lib/active_record/attribute_decorators.rb
index 98b7805c0a..0b66043d2a 100644
--- a/activerecord/lib/active_record/attribute_decorators.rb
+++ b/activerecord/lib/active_record/attribute_decorators.rb
@@ -46,7 +46,6 @@ module ActiveRecord
end
private
-
def load_schema!
super
attribute_types.each do |name, type|
@@ -75,7 +74,6 @@ module ActiveRecord
end
private
-
def decorators_for(name, type)
matching(name, type).map(&:last)
end
diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb
index 220043c061..21f72bb6c7 100644
--- a/activerecord/lib/active_record/attribute_methods.rb
+++ b/activerecord/lib/active_record/attribute_methods.rb
@@ -159,57 +159,6 @@ module ActiveRecord
end
end
- # Regexp for column names (with or without a table name prefix). Matches
- # the following:
- # "#{table_name}.#{column_name}"
- # "#{column_name}"
- COLUMN_NAME = /\A(?:\w+\.)?\w+\z/i
-
- # Regexp for column names with order (with or without a table name
- # prefix, with or without various order modifiers). Matches the following:
- # "#{table_name}.#{column_name}"
- # "#{table_name}.#{column_name} #{direction}"
- # "#{table_name}.#{column_name} #{direction} NULLS FIRST"
- # "#{table_name}.#{column_name} NULLS LAST"
- # "#{column_name}"
- # "#{column_name} #{direction}"
- # "#{column_name} #{direction} NULLS FIRST"
- # "#{column_name} NULLS LAST"
- COLUMN_NAME_WITH_ORDER = /
- \A
- (?:\w+\.)?
- \w+
- (?:\s+asc|\s+desc)?
- (?:\s+nulls\s+(?:first|last))?
- \z
- /ix
-
- def disallow_raw_sql!(args, permit: COLUMN_NAME) # :nodoc:
- unexpected = args.reject do |arg|
- Arel.arel_node?(arg) ||
- arg.to_s.split(/\s*,\s*/).all? { |part| permit.match?(part) }
- end
-
- return if unexpected.none?
-
- if allow_unsafe_raw_sql == :deprecated
- ActiveSupport::Deprecation.warn(
- "Dangerous query method (method whose arguments are used as raw " \
- "SQL) called with non-attribute argument(s): " \
- "#{unexpected.map(&:inspect).join(", ")}. Non-attribute " \
- "arguments will be disallowed in Rails 6.1. This method should " \
- "not be called with user-provided values, such as request " \
- "parameters or model attributes. Known-safe values can be passed " \
- "by wrapping them in Arel.sql()."
- )
- else
- raise(ActiveRecord::UnknownAttributeReference,
- "Query method called with non-attribute argument(s): " +
- unexpected.map(&:inspect).join(", ")
- )
- end
- end
-
# Returns true if the given attribute exists, otherwise false.
#
# class Person < ActiveRecord::Base
@@ -437,7 +386,7 @@ module ActiveRecord
def attributes_for_update(attribute_names)
attribute_names &= self.class.column_names
attribute_names.delete_if do |name|
- readonly_attribute?(name)
+ self.class.readonly_attribute?(name)
end
end
@@ -460,10 +409,6 @@ module ActiveRecord
end
end
- def readonly_attribute?(name)
- self.class.readonly_attributes.include?(name)
- end
-
def pk_attribute?(name)
name == @primary_key
end
diff --git a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb
index 3d917ec9b1..4a7b6c60e5 100644
--- a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb
+++ b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb
@@ -66,7 +66,6 @@ module ActiveRecord
end
private
-
# Dispatch target for <tt>*_before_type_cast</tt> attribute methods.
def attribute_before_type_cast(attribute_name)
read_attribute_before_type_cast(attribute_name)
diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb
index a43ebdf60d..45341765c1 100644
--- a/activerecord/lib/active_record/attribute_methods/dirty.rb
+++ b/activerecord/lib/active_record/attribute_methods/dirty.rb
@@ -177,6 +177,11 @@ module ActiveRecord
affected_rows = super
+ if @_skip_dirty_tracking ||= false
+ clear_attribute_changes(@_touch_attr_names)
+ return affected_rows
+ end
+
changes = {}
@attributes.keys.each do |attr_name|
next if @_touch_attr_names.include?(attr_name)
@@ -193,7 +198,7 @@ module ActiveRecord
affected_rows
ensure
- @_touch_attr_names = nil
+ @_touch_attr_names, @_skip_dirty_tracking = nil, nil
end
def _update_record(attribute_names = attribute_names_for_partial_writes)
diff --git a/activerecord/lib/active_record/attribute_methods/primary_key.rb b/activerecord/lib/active_record/attribute_methods/primary_key.rb
index b4f5e6e75a..768c5f8c05 100644
--- a/activerecord/lib/active_record/attribute_methods/primary_key.rb
+++ b/activerecord/lib/active_record/attribute_methods/primary_key.rb
@@ -45,7 +45,6 @@ module ActiveRecord
end
private
-
def attribute_method?(attr_name)
attr_name == "id" || super
end
@@ -120,7 +119,6 @@ module ActiveRecord
end
private
-
def suppress_composite_primary_key(pk)
return pk unless pk.is_a?(Array)
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb
index 0562327a9a..0f0e721b24 100644
--- a/activerecord/lib/active_record/attribute_methods/read.rb
+++ b/activerecord/lib/active_record/attribute_methods/read.rb
@@ -7,7 +7,6 @@ module ActiveRecord
module ClassMethods # :nodoc:
private
-
def define_method_attribute(name)
ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
generated_attribute_methods, name
diff --git a/activerecord/lib/active_record/attribute_methods/serialization.rb b/activerecord/lib/active_record/attribute_methods/serialization.rb
index 6e0e90f39c..7bc03b9eed 100644
--- a/activerecord/lib/active_record/attribute_methods/serialization.rb
+++ b/activerecord/lib/active_record/attribute_methods/serialization.rb
@@ -79,7 +79,6 @@ module ActiveRecord
end
private
-
def type_incompatible_with_serialize?(type, class_name)
type.is_a?(ActiveRecord::Type::Json) && class_name == ::JSON ||
type.respond_to?(:type_cast_array, true) && class_name == ::Array
diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
index 294a3dc32c..fb44232dff 100644
--- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
+++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
@@ -25,7 +25,6 @@ module ActiveRecord
end
private
-
def convert_time_to_time_zone(value)
return if value.nil?
@@ -64,7 +63,6 @@ module ActiveRecord
module ClassMethods # :nodoc:
private
-
def inherited(subclass)
super
# We need to apply this decorator here, rather than on module inclusion. The closure
diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb
index 1c63b553d0..66536a8ddf 100644
--- a/activerecord/lib/active_record/attribute_methods/write.rb
+++ b/activerecord/lib/active_record/attribute_methods/write.rb
@@ -11,7 +11,6 @@ module ActiveRecord
module ClassMethods # :nodoc:
private
-
def define_method_attribute=(name)
ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
generated_attribute_methods, name, writer: true,
diff --git a/activerecord/lib/active_record/attributes.rb b/activerecord/lib/active_record/attributes.rb
index 7cf421c184..c7846dbe7a 100644
--- a/activerecord/lib/active_record/attributes.rb
+++ b/activerecord/lib/active_record/attributes.rb
@@ -255,7 +255,6 @@ module ActiveRecord
end
private
-
NO_DEFAULT_PROVIDED = Object.new # :nodoc:
private_constant :NO_DEFAULT_PROVIDED
diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb
index 8d89e7d84a..734ebb45ae 100644
--- a/activerecord/lib/active_record/autosave_association.rb
+++ b/activerecord/lib/active_record/autosave_association.rb
@@ -147,7 +147,6 @@ module ActiveRecord
module ClassMethods # :nodoc:
private
-
def define_non_cyclic_method(name, &block)
return if instance_methods(false).include?(name)
define_method(name) do |*args|
@@ -267,7 +266,6 @@ module ActiveRecord
end
private
-
# Returns the record for an association collection that should be validated
# or saved. If +autosave+ is +false+ only new records will be returned,
# unless the parent is/was a new record itself.
@@ -304,7 +302,7 @@ module ActiveRecord
def validate_single_association(reflection)
association = association_instance_get(reflection.name)
record = association && association.reader
- association_valid?(reflection, record) if record
+ association_valid?(reflection, record) if record && record.changed_for_autosave?
end
# Validate the associated records if <tt>:validate</tt> or
@@ -411,7 +409,7 @@ module ActiveRecord
saved = record.save(validate: false)
end
- raise ActiveRecord::Rollback unless saved
+ raise(RecordInvalid.new(association.owner)) unless saved
end
end
end
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 2af6d09b53..282c9fcf30 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -12,7 +12,6 @@ require "active_support/core_ext/hash/slice"
require "active_support/core_ext/string/behavior"
require "active_support/core_ext/kernel/singleton_class"
require "active_support/core_ext/module/introspection"
-require "active_support/core_ext/object/duplicable"
require "active_support/core_ext/class/subclasses"
require "active_record/attribute_decorators"
require "active_record/define_callbacks"
diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb
index ef5444dfc3..a9ab9ab7a9 100644
--- a/activerecord/lib/active_record/callbacks.rb
+++ b/activerecord/lib/active_record/callbacks.rb
@@ -323,7 +323,6 @@ module ActiveRecord
end
private
-
def create_or_update(**)
_run_save_callbacks { super }
end
diff --git a/activerecord/lib/active_record/coders/yaml_column.rb b/activerecord/lib/active_record/coders/yaml_column.rb
index 11559141c7..881f0bcdb0 100644
--- a/activerecord/lib/active_record/coders/yaml_column.rb
+++ b/activerecord/lib/active_record/coders/yaml_column.rb
@@ -39,7 +39,6 @@ module ActiveRecord
end
private
-
def check_arity_of_constructor
load(nil)
rescue ArgumentError
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
index 68498b5dc5..36001efdd5 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -3,6 +3,7 @@
require "thread"
require "concurrent/map"
require "monitor"
+require "weakref"
module ActiveRecord
# Raised when a connection could not be obtained within the connection
@@ -19,6 +20,26 @@ module ActiveRecord
end
module ConnectionAdapters
+ module AbstractPool # :nodoc:
+ def get_schema_cache(connection)
+ @schema_cache ||= SchemaCache.new(connection)
+ @schema_cache.connection = connection
+ @schema_cache
+ end
+
+ def set_schema_cache(cache)
+ @schema_cache = cache
+ end
+ end
+
+ class NullPool # :nodoc:
+ include ConnectionAdapters::AbstractPool
+
+ def initialize
+ @schema_cache = nil
+ end
+ end
+
# Connection pool base class for managing Active Record database
# connections.
#
@@ -146,7 +167,6 @@ module ActiveRecord
end
private
-
def internal_poll(timeout)
no_wait_poll || (timeout && wait_poll(timeout))
end
@@ -294,23 +314,50 @@ module ActiveRecord
@frequency = frequency
end
+ @mutex = Mutex.new
+ @pools = {}
+
+ class << self
+ def register_pool(pool, frequency) # :nodoc:
+ @mutex.synchronize do
+ unless @pools.key?(frequency)
+ @pools[frequency] = []
+ spawn_thread(frequency)
+ end
+ @pools[frequency] << WeakRef.new(pool)
+ end
+ end
+
+ private
+ def spawn_thread(frequency)
+ Thread.new(frequency) do |t|
+ loop do
+ sleep t
+ @mutex.synchronize do
+ @pools[frequency].select!(&:weakref_alive?)
+ @pools[frequency].each do |p|
+ p.reap
+ p.flush
+ rescue WeakRef::RefError
+ end
+ end
+ end
+ end
+ end
+ end
+
def run
return unless frequency && frequency > 0
- Thread.new(frequency, pool) { |t, p|
- loop do
- sleep t
- p.reap
- p.flush
- end
- }
+ self.class.register_pool(pool, frequency)
end
end
include MonitorMixin
include QueryCache::ConnectionPoolConfiguration
+ include ConnectionAdapters::AbstractPool
attr_accessor :automatic_reconnect, :checkout_timeout, :schema_cache
- attr_reader :spec, :connections, :size, :reaper
+ attr_reader :spec, :size, :reaper
# Creates a new ConnectionPool object. +spec+ is a ConnectionSpecification
# object which describes database connection information (e.g. adapter,
@@ -379,7 +426,7 @@ module ActiveRecord
# #connection can be called any number of times; the connection is
# held in a cache keyed by a thread.
def connection
- @thread_cached_conns[connection_cache_key(@lock_thread || Thread.current)] ||= checkout
+ @thread_cached_conns[connection_cache_key(current_thread)] ||= checkout
end
# Returns true if there is an open connection being used for the current thread.
@@ -388,7 +435,7 @@ module ActiveRecord
# #connection or #with_connection methods. Connections obtained through
# #checkout will not be detected by #active_connection?
def active_connection?
- @thread_cached_conns[connection_cache_key(Thread.current)]
+ @thread_cached_conns[connection_cache_key(current_thread)]
end
# Signal that the thread is finished with the current connection.
@@ -423,6 +470,21 @@ module ActiveRecord
synchronize { @connections.any? }
end
+ # Returns an array containing the connections currently in the pool.
+ # Access to the array does not require synchronization on the pool because
+ # the array is newly created and not retained by the pool.
+ #
+ # However; this method bypasses the ConnectionPool's thread-safe connection
+ # access pattern. A returned connection may be owned by another thread,
+ # unowned, or by happen-stance owned by the calling thread.
+ #
+ # Calling methods on a connection without ownership is subject to the
+ # thread-safety guarantees of the underlying method. Many of the methods
+ # on connection adapter classes are inherently multi-thread unsafe.
+ def connections
+ synchronize { @connections.dup }
+ end
+
# Disconnects all connections in the pool, and clears the pool.
#
# Raises:
@@ -668,6 +730,10 @@ module ActiveRecord
thread
end
+ def current_thread
+ @lock_thread || Thread.current
+ end
+
# Take control of all existing connections so a "group" action such as
# reload/disconnect can be performed safely. It is no longer enough to
# wrap it in +synchronize+ because some pool's actions are allowed
@@ -809,7 +875,6 @@ module ActiveRecord
def new_connection
Base.send(spec.adapter_method, spec.config).tap do |conn|
- conn.schema_cache = schema_cache.dup if schema_cache
conn.check_version
end
end
@@ -938,15 +1003,30 @@ module ActiveRecord
end
end
+ attr_reader :prevent_writes
+
def initialize
# These caches are keyed by spec.name (ConnectionSpecification#name).
@owner_to_pool = ConnectionHandler.create_owner_to_pool
+ @prevent_writes = false
# Backup finalizer: if the forked child never needed a pool, the above
# early discard has not occurred
ObjectSpace.define_finalizer self, ConnectionHandler.unowned_pool_finalizer(@owner_to_pool)
end
+ # Prevent writing to the database regardless of role.
+ #
+ # In some cases you may want to prevent writes to the database
+ # even if you are on a database that can write. `while_preventing_writes`
+ # will prevent writes to the database for the duration of the block.
+ def while_preventing_writes
+ original, @prevent_writes = @prevent_writes, true
+ yield
+ ensure
+ @prevent_writes = original
+ end
+
def connection_pool_list
owner_to_pool.values.compact
end
@@ -1064,7 +1144,6 @@ module ActiveRecord
end
private
-
def owner_to_pool
@owner_to_pool[Process.pid]
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb
index 75e959045e..d932f068f2 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require "active_support/deprecation"
-
module ActiveRecord
module ConnectionAdapters # :nodoc:
module DatabaseLimits
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 ef19538447..044272ea51 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -205,8 +205,6 @@ module ActiveRecord
# In order to get around this problem, #transaction will emulate the effect
# of nested transactions, by using savepoints:
# https://dev.mysql.com/doc/refman/5.7/en/savepoint.html
- # Savepoints are supported by MySQL and PostgreSQL. SQLite3 version >= '3.6.8'
- # supports savepoints.
#
# It is safe to call this method if a database transaction is already open,
# i.e. if #transaction is called within another #transaction block. In case
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb
index a7753e3e9c..768122b4d2 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb
@@ -33,17 +33,17 @@ module ActiveRecord
end
def enable_query_cache!
- @query_cache_enabled[connection_cache_key(Thread.current)] = true
+ @query_cache_enabled[connection_cache_key(current_thread)] = true
connection.enable_query_cache! if active_connection?
end
def disable_query_cache!
- @query_cache_enabled.delete connection_cache_key(Thread.current)
+ @query_cache_enabled.delete connection_cache_key(current_thread)
connection.disable_query_cache! if active_connection?
end
def query_cache_enabled
- @query_cache_enabled[connection_cache_key(Thread.current)]
+ @query_cache_enabled[connection_cache_key(current_thread)]
end
end
@@ -109,7 +109,6 @@ module ActiveRecord
end
private
-
def cache_sql(sql, name, binds)
@lock.synchronize do
result =
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
index 2877530917..93273f6cf6 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
@@ -114,16 +114,16 @@ module ActiveRecord
# if the value is a Time responding to usec.
def quoted_date(value)
if value.acts_like?(:time)
- zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
-
- if value.respond_to?(zone_conversion_method)
- value = value.send(zone_conversion_method)
+ if ActiveRecord::Base.default_timezone == :utc
+ value = value.getutc if value.respond_to?(:getutc) && !value.utc?
+ else
+ value = value.getlocal if value.respond_to?(:getlocal)
end
end
result = value.to_s(:db)
if value.respond_to?(:usec) && value.usec > 0
- "#{result}.#{sprintf("%06d", value.usec)}"
+ result << "." << sprintf("%06d", value.usec)
else
result
end
@@ -142,6 +142,59 @@ module ActiveRecord
value.to_s.gsub(%r{ (/ (?: | \g<1>) \*) \+? \s* | \s* (\* (?: | \g<2>) /) }x, "")
end
+ def column_name_matcher # :nodoc:
+ COLUMN_NAME
+ end
+
+ def column_name_with_order_matcher # :nodoc:
+ COLUMN_NAME_WITH_ORDER
+ end
+
+ # Regexp for column names (with or without a table name prefix).
+ # Matches the following:
+ #
+ # "#{table_name}.#{column_name}"
+ # "#{column_name}"
+ COLUMN_NAME = /
+ \A
+ (
+ (?:
+ # table_name.column_name | function(one or no argument)
+ ((?:\w+\.)?\w+) | \w+\((?:|\g<2>)\)
+ )
+ (?:(?:\s+AS)?\s+\w+)?
+ )
+ (?:\s*,\s*\g<1>)*
+ \z
+ /ix
+
+ # Regexp for column names with order (with or without a table name prefix,
+ # with or without various order modifiers). Matches the following:
+ #
+ # "#{table_name}.#{column_name}"
+ # "#{table_name}.#{column_name} #{direction}"
+ # "#{table_name}.#{column_name} #{direction} NULLS FIRST"
+ # "#{table_name}.#{column_name} NULLS LAST"
+ # "#{column_name}"
+ # "#{column_name} #{direction}"
+ # "#{column_name} #{direction} NULLS FIRST"
+ # "#{column_name} NULLS LAST"
+ COLUMN_NAME_WITH_ORDER = /
+ \A
+ (
+ (?:
+ # table_name.column_name | function(one or no argument)
+ ((?:\w+\.)?\w+) | \w+\((?:|\g<2>)\)
+ )
+ (?:\s+ASC|\s+DESC)?
+ (?:\s+NULLS\s+(?:FIRST|LAST))?
+ )
+ (?:\s*,\s*\g<1>)*
+ \z
+ /ix
+
+ private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
+
private
def type_casted_binds(binds)
if binds.first.is_a?(Array)
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/savepoints.rb b/activerecord/lib/active_record/connection_adapters/abstract/savepoints.rb
index 52a796b926..d6dbef3fc8 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/savepoints.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/savepoints.rb
@@ -8,15 +8,15 @@ module ActiveRecord
end
def create_savepoint(name = current_savepoint_name)
- execute("SAVEPOINT #{name}")
+ execute("SAVEPOINT #{name}", "TRANSACTION")
end
def exec_rollback_to_savepoint(name = current_savepoint_name)
- execute("ROLLBACK TO SAVEPOINT #{name}")
+ execute("ROLLBACK TO SAVEPOINT #{name}", "TRANSACTION")
end
def release_savepoint(name = current_savepoint_name)
- execute("RELEASE SAVEPOINT #{name}")
+ execute("RELEASE SAVEPOINT #{name}", "TRANSACTION")
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb
index 7d20825a75..23c993cfc3 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb
@@ -19,7 +19,6 @@ module ActiveRecord
to: :@conn, private: true
private
-
def visit_AlterTable(o)
sql = +"ALTER TABLE #{quote_table_name(o.name)} "
sql << o.adds.map { |col| accept col }.join(" ")
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 688eea75e8..dbd533b4b3 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -264,8 +264,7 @@ module ActiveRecord
if_not_exists: false,
options: nil,
as: nil,
- comment: nil,
- **
+ comment: nil
)
@conn = conn
@columns_hash = {}
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 622e00fffb..fb56e712be 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
@@ -15,7 +15,7 @@ module ActiveRecord
def column_spec_for_primary_key(column)
return {} if default_primary_key?(column)
spec = { id: schema_type(column).inspect }
- spec.merge!(prepare_column_options(column).except!(:null))
+ spec.merge!(prepare_column_options(column).except!(:null, :comment))
spec[:default] ||= "nil" if explicit_primary_key_default?(column)
spec
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index 2b64e96450..88367c79a1 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -2,7 +2,6 @@
require "active_record/migration/join_table"
require "active_support/core_ext/string/access"
-require "active_support/deprecation"
require "digest/sha2"
module ActiveRecord
@@ -101,7 +100,7 @@ module ActiveRecord
def index_exists?(table_name, column_name, options = {})
column_names = Array(column_name).map(&:to_s)
checks = []
- checks << lambda { |i| i.columns == column_names }
+ checks << lambda { |i| Array(i.columns) == column_names }
checks << lambda { |i| i.unique } if options[:unique]
checks << lambda { |i| i.name == options[:name].to_s } if options[:name]
@@ -291,25 +290,27 @@ module ActiveRecord
# SELECT * FROM orders INNER JOIN line_items ON order_id=orders.id
#
# See also TableDefinition#column for details on how to create columns.
- def create_table(table_name, **options)
- td = create_table_definition(table_name, options)
+ def create_table(table_name, id: :primary_key, primary_key: nil, force: nil, **options)
+ td = create_table_definition(
+ table_name, options.extract!(:temporary, :if_not_exists, :options, :as, :comment)
+ )
- if options[:id] != false && !options[:as]
- pk = options.fetch(:primary_key) do
- Base.get_primary_key table_name.to_s.singularize
- end
+ if id && !td.as
+ pk = primary_key || Base.get_primary_key(table_name.to_s.singularize)
if pk.is_a?(Array)
td.primary_keys pk
else
- td.primary_key pk, options.fetch(:id, :primary_key), options
+ td.primary_key pk, id, options
end
end
yield td if block_given?
- if options[:force]
- drop_table(table_name, options.merge(if_exists: true))
+ if force
+ drop_table(table_name, force: force, if_exists: true)
+ else
+ schema_cache.clear_data_source_cache!(table_name.to_s)
end
result = execute schema_creation.accept td
@@ -321,7 +322,7 @@ module ActiveRecord
end
if supports_comments? && !supports_comments_in_create?
- if table_comment = options[:comment].presence
+ if table_comment = td.comment.presence
change_table_comment(table_name, table_comment)
end
@@ -499,6 +500,7 @@ module ActiveRecord
# it can be helpful to provide these in a migration's +change+ method so it can be reverted.
# In that case, +options+ and the block will be used by #create_table.
def drop_table(table_name, options = {})
+ schema_cache.clear_data_source_cache!(table_name.to_s)
execute "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}"
end
@@ -518,14 +520,15 @@ module ActiveRecord
# Available options are (none of these exists by default):
# * <tt>:limit</tt> -
# Requests a maximum column length. This is the number of characters for a <tt>:string</tt> column
- # and number of bytes for <tt>:text</tt>, <tt>:binary</tt> and <tt>:integer</tt> columns.
+ # and number of bytes for <tt>:text</tt>, <tt>:binary</tt>, and <tt>:integer</tt> columns.
# This option is ignored by some backends.
# * <tt>:default</tt> -
# The column's default value. Use +nil+ for +NULL+.
# * <tt>:null</tt> -
# Allows or disallows +NULL+ values in the column.
# * <tt>:precision</tt> -
- # Specifies the precision for the <tt>:decimal</tt> and <tt>:numeric</tt> columns.
+ # Specifies the precision for the <tt>:decimal</tt>, <tt>:numeric</tt>,
+ # <tt>:datetime</tt>, and <tt>:time</tt> columns.
# * <tt>:scale</tt> -
# Specifies the scale for the <tt>:decimal</tt> and <tt>:numeric</tt> columns.
# * <tt>:collation</tt> -
@@ -735,7 +738,7 @@ module ActiveRecord
#
# CREATE UNIQUE INDEX index_accounts_on_branch_id_and_party_id ON accounts(branch_id, party_id) WHERE active
#
- # Note: Partial indexes are only supported for PostgreSQL and SQLite 3.8.0+.
+ # Note: Partial indexes are only supported for PostgreSQL and SQLite.
#
# ====== Creating an index with a specific method
#
@@ -1060,8 +1063,8 @@ module ActiveRecord
options
end
- def dump_schema_information #:nodoc:
- versions = ActiveRecord::SchemaMigration.all_versions
+ def dump_schema_information # :nodoc:
+ versions = schema_migration.all_versions
insert_versions_sql(versions) if versions.any?
end
@@ -1077,7 +1080,7 @@ module ActiveRecord
end
version = version.to_i
- sm_table = quote_table_name(ActiveRecord::SchemaMigration.table_name)
+ sm_table = quote_table_name(schema_migration.table_name)
migrated = migration_context.get_all_versions
versions = migration_context.migrations.map(&:version)
@@ -1450,7 +1453,7 @@ module ActiveRecord
end
def insert_versions_sql(versions)
- sm_table = quote_table_name(ActiveRecord::SchemaMigration.table_name)
+ sm_table = quote_table_name(schema_migration.table_name)
if versions.is_a?(Array)
sql = +"INSERT INTO #{sm_table} (version) VALUES\n"
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb
index c9e84e48cc..53ce8df491 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb
@@ -5,10 +5,11 @@ module ActiveRecord
class TransactionState
def initialize(state = nil)
@state = state
- @children = []
+ @children = nil
end
def add_child(state)
+ @children ||= []
@children << state
end
@@ -41,12 +42,12 @@ module ActiveRecord
end
def rollback!
- @children.each { |c| c.rollback! }
+ @children&.each { |c| c.rollback! }
@state = :rolledback
end
def full_rollback!
- @children.each { |c| c.rollback! }
+ @children&.each { |c| c.rollback! }
@state = :fully_rolledback
end
@@ -75,18 +76,19 @@ module ActiveRecord
class Transaction #:nodoc:
attr_reader :connection, :state, :records, :savepoint_name, :isolation_level
- def initialize(connection, options, run_commit_callbacks: false)
+ def initialize(connection, isolation: nil, joinable: true, run_commit_callbacks: false)
@connection = connection
@state = TransactionState.new
- @records = []
- @isolation_level = options[:isolation]
+ @records = nil
+ @isolation_level = isolation
@materialized = false
- @joinable = options.fetch(:joinable, true)
+ @joinable = joinable
@run_commit_callbacks = run_commit_callbacks
end
def add_record(record)
- records << record
+ @records ||= []
+ @records << record
end
def materialize!
@@ -98,32 +100,42 @@ module ActiveRecord
end
def rollback_records
- ite = records.uniq
+ return unless records
+ ite = records.uniq(&:object_id)
+ already_run_callbacks = {}
while record = ite.shift
- record.rolledback!(force_restore_state: full_rollback?)
+ trigger_callbacks = record.trigger_transactional_callbacks?
+ should_run_callbacks = !already_run_callbacks[record] && trigger_callbacks
+ already_run_callbacks[record] ||= trigger_callbacks
+ record.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: should_run_callbacks)
end
ensure
- ite.each do |i|
+ ite&.each do |i|
i.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: false)
end
end
def before_commit_records
- records.uniq.each(&:before_committed!) if @run_commit_callbacks
+ records.uniq.each(&:before_committed!) if records && @run_commit_callbacks
end
def commit_records
- ite = records.uniq
+ return unless records
+ ite = records.uniq(&:object_id)
+ already_run_callbacks = {}
while record = ite.shift
if @run_commit_callbacks
- record.committed!
+ trigger_callbacks = record.trigger_transactional_callbacks?
+ should_run_callbacks = !already_run_callbacks[record] && trigger_callbacks
+ already_run_callbacks[record] ||= trigger_callbacks
+ record.committed!(should_run_callbacks: should_run_callbacks)
else
# if not running callbacks, only adds the record to the parent transaction
connection.add_transaction_record(record)
end
end
ensure
- ite.each { |i| i.committed!(should_run_callbacks: false) }
+ ite&.each { |i| i.committed!(should_run_callbacks: false) }
end
def full_rollback?; true; end
@@ -133,8 +145,8 @@ module ActiveRecord
end
class SavepointTransaction < Transaction
- def initialize(connection, savepoint_name, parent_transaction, *args)
- super(connection, *args)
+ def initialize(connection, savepoint_name, parent_transaction, **options)
+ super(connection, options)
parent_transaction.state.add_child(@state)
@@ -194,18 +206,29 @@ module ActiveRecord
@lazy_transactions_enabled = true
end
- def begin_transaction(options = {})
+ def begin_transaction(isolation: nil, joinable: true, _lazy: true)
@connection.lock.synchronize do
run_commit_callbacks = !current_transaction.joinable?
transaction =
if @stack.empty?
- RealTransaction.new(@connection, options, run_commit_callbacks: run_commit_callbacks)
+ RealTransaction.new(
+ @connection,
+ isolation: isolation,
+ joinable: joinable,
+ run_commit_callbacks: run_commit_callbacks
+ )
else
- SavepointTransaction.new(@connection, "active_record_#{@stack.size}", @stack.last, options,
- run_commit_callbacks: run_commit_callbacks)
+ SavepointTransaction.new(
+ @connection,
+ "active_record_#{@stack.size}",
+ @stack.last,
+ isolation: isolation,
+ joinable: joinable,
+ run_commit_callbacks: run_commit_callbacks
+ )
end
- if @connection.supports_lazy_transactions? && lazy_transactions_enabled? && options[:_lazy] != false
+ if @connection.supports_lazy_transactions? && lazy_transactions_enabled? && _lazy
@has_unmaterialized_transactions = true
else
transaction.materialize!
@@ -266,9 +289,9 @@ module ActiveRecord
end
end
- def within_new_transaction(options = {})
+ def within_new_transaction(isolation: nil, joinable: true)
@connection.lock.synchronize do
- transaction = begin_transaction options
+ transaction = begin_transaction(isolation: isolation, joinable: joinable)
yield
rescue Exception => error
if transaction
@@ -301,7 +324,6 @@ module ActiveRecord
end
private
-
NULL_TRANSACTION = NullTransaction.new
# Deallocate invalidated prepared statements outside of the transaction
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index bf0bb84c93..dc970c384b 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -6,7 +6,6 @@ require "active_record/connection_adapters/sql_type_metadata"
require "active_record/connection_adapters/abstract/schema_dumper"
require "active_record/connection_adapters/abstract/schema_creation"
require "active_support/concurrency/load_interlock_aware_monitor"
-require "active_support/deprecation"
require "arel/collectors/bind"
require "arel/collectors/composite"
require "arel/collectors/sql_string"
@@ -78,7 +77,7 @@ module ActiveRecord
SIMPLE_INT = /\A\d+\z/
attr_accessor :pool
- attr_reader :schema_cache, :visitor, :owner, :logger, :lock, :prepared_statements, :prevent_writes
+ attr_reader :visitor, :owner, :logger, :lock, :prepared_statements
alias :in_use? :owner
set_callback :checkin, :after, :enable_lazy_transactions!
@@ -106,6 +105,14 @@ module ActiveRecord
Regexp.union(*parts)
end
+ def self.quoted_column_names # :nodoc:
+ @quoted_column_names ||= {}
+ end
+
+ def self.quoted_table_names # :nodoc:
+ @quoted_table_names ||= {}
+ end
+
def initialize(connection, logger = nil, config = {}) # :nodoc:
super()
@@ -114,11 +121,8 @@ module ActiveRecord
@instrumenter = ActiveSupport::Notifications.instrumenter
@logger = logger
@config = config
- @pool = nil
+ @pool = ActiveRecord::ConnectionAdapters::NullPool.new
@idle_since = Concurrent.monotonic_time
- @schema_cache = SchemaCache.new self
- @quoted_column_names, @quoted_table_names = {}, {}
- @prevent_writes = false
@visitor = arel_visitor
@statements = build_statement_pool
@lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
@@ -144,19 +148,7 @@ module ActiveRecord
# Returns true if the connection is a replica, or if +prevent_writes+
# is set to true.
def preventing_writes?
- replica? || prevent_writes
- end
-
- # Prevent writing to the database regardless of role.
- #
- # In some cases you may want to prevent writes to the database
- # even if you are on a database that can write. `while_preventing_writes`
- # will prevent writes to the database for the duration of the block.
- def while_preventing_writes
- original, @prevent_writes = @prevent_writes, true
- yield
- ensure
- @prevent_writes = original
+ replica? || ActiveRecord::Base.connection_handler.prevent_writes
end
def migrations_paths # :nodoc:
@@ -164,7 +156,22 @@ module ActiveRecord
end
def migration_context # :nodoc:
- MigrationContext.new(migrations_paths)
+ MigrationContext.new(migrations_paths, schema_migration)
+ end
+
+ def schema_migration # :nodoc:
+ @schema_migration ||= begin
+ conn = self
+ spec_name = conn.pool.spec.name
+ name = "#{spec_name}::SchemaMigration"
+
+ Class.new(ActiveRecord::SchemaMigration) do
+ define_singleton_method(:name) { name }
+ define_singleton_method(:to_s) { name }
+
+ self.connection_specification_name = spec_name
+ end
+ end
end
class Version
@@ -206,9 +213,13 @@ module ActiveRecord
@owner = Thread.current
end
+ def schema_cache
+ @pool.get_schema_cache(self)
+ end
+
def schema_cache=(cache)
cache.connection = self
- @schema_cache = cache
+ @pool.set_schema_cache(cache)
end
# this method must only be called while holding connection pool's mutex
@@ -259,6 +270,11 @@ module ActiveRecord
self.class::ADAPTER_NAME
end
+ # Does the database for this adapter exist?
+ def self.database_exists?(config)
+ raise NotImplementedError
+ end
+
# Does this adapter support DDL rollbacks in transactions? That is, would
# CREATE TABLE or ALTER TABLE get rolled back by a transaction?
def supports_ddl_transactions?
@@ -487,6 +503,9 @@ module ActiveRecord
#
# Prevent @connection's finalizer from touching the socket, or
# otherwise communicating with its server, when it is collected.
+ if schema_cache.connection == self
+ schema_cache.connection = nil
+ end
end
# Reset the state of this connection, directing the DBMS to clear
@@ -587,7 +606,6 @@ module ActiveRecord
end
private
-
def type_map
@type_map ||= Type::TypeMap.new.tap do |mapping|
initialize_type_map(mapping)
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 282b2b1838..ef1eef6b69 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -45,7 +45,6 @@ module ActiveRecord
class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
private
-
def dealloc(stmt)
stmt.close
end
@@ -176,15 +175,6 @@ module ActiveRecord
# DATABASE STATEMENTS ======================================
#++
- def explain(arel, binds = [])
- sql = "EXPLAIN #{to_sql(arel, binds)}"
- start = Concurrent.monotonic_time
- result = exec_query(sql, "EXPLAIN", binds)
- elapsed = Concurrent.monotonic_time - start
-
- MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
- end
-
# Executes the SQL statement in the context of this connection.
def execute(sql, name = nil)
materialize_transactions
@@ -204,7 +194,7 @@ module ActiveRecord
end
def begin_db_transaction
- execute "BEGIN"
+ execute("BEGIN", "TRANSACTION")
end
def begin_isolated_db_transaction(isolation)
@@ -213,11 +203,11 @@ module ActiveRecord
end
def commit_db_transaction #:nodoc:
- execute "COMMIT"
+ execute("COMMIT", "TRANSACTION")
end
def exec_rollback_db_transaction #:nodoc:
- execute "ROLLBACK"
+ execute("ROLLBACK", "TRANSACTION")
end
def empty_insert_statement_value(primary_key = nil)
@@ -298,6 +288,8 @@ module ActiveRecord
# Example:
# rename_table('octopuses', 'octopi')
def rename_table(table_name, new_name)
+ schema_cache.clear_data_source_cache!(table_name.to_s)
+ schema_cache.clear_data_source_cache!(new_name.to_s)
execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
rename_table_indexes(table_name, new_name)
end
@@ -318,6 +310,7 @@ module ActiveRecord
# it can be helpful to provide these in a migration's +change+ method so it can be reverted.
# In that case, +options+ and the block will be used by create_table.
def drop_table(table_name, options = {})
+ schema_cache.clear_data_source_cache!(table_name.to_s)
execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
end
@@ -483,12 +476,12 @@ module ActiveRecord
# distinct queries, and requires that the ORDER BY include the distinct column.
# See https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
def columns_for_distinct(columns, orders) # :nodoc:
- order_columns = orders.reject(&:blank?).map { |s|
+ order_columns = orders.compact_blank.map { |s|
# Convert Arel node to string
s = s.to_sql unless s.is_a?(String)
# Remove any ASC/DESC modifiers
s.gsub(/\s+(?:ASC|DESC)\b/i, "")
- }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
+ }.compact_blank.map.with_index { |column, i| "#{column} AS alias_#{i}" }
(order_columns << super).join(", ")
end
@@ -522,7 +515,6 @@ module ActiveRecord
end
private
-
def initialize_type_map(m = type_map)
super
@@ -627,7 +619,11 @@ module ActiveRecord
when ER_QUERY_INTERRUPTED
QueryCanceled.new(message, sql: sql, binds: binds)
else
- super
+ if exception.is_a?(Mysql2::Error::TimeoutError)
+ ActiveRecord::AdapterTimeout.new(message, sql: sql, binds: binds)
+ else
+ super
+ end
end
end
@@ -745,7 +741,7 @@ module ActiveRecord
end.compact.join(", ")
# ...and send them all in one query
- execute "SET #{encoding} #{sql_mode_assignment} #{variable_assignments}"
+ execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
end
def column_definitions(table_name) # :nodoc:
@@ -804,7 +800,6 @@ module ActiveRecord
end
private
-
def cast_value(value)
case value
when true then "1"
diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb
index 279d0b9e84..2708d2756b 100644
--- a/activerecord/lib/active_record/connection_adapters/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/column.rb
@@ -5,6 +5,8 @@ module ActiveRecord
module ConnectionAdapters
# An abstract definition of a column in a table.
class Column
+ include Deduplicable
+
attr_reader :name, :default, :sql_type_metadata, :null, :default_function, :collation, :comment
delegate :precision, :scale, :limit, :type, :sql_type, to: :sql_type_metadata, allow_nil: true
@@ -76,6 +78,7 @@ module ActiveRecord
def hash
Column.hash ^
name.hash ^
+ name.encoding.hash ^
default.hash ^
sql_type_metadata.hash ^
null.hash ^
@@ -83,6 +86,17 @@ module ActiveRecord
collation.hash ^
comment.hash
end
+
+ private
+ def deduplicated
+ @name = -name
+ @sql_type_metadata = sql_type_metadata.deduplicate if sql_type_metadata
+ @default = -default if default
+ @default_function = -default_function if default_function
+ @collation = -collation if collation
+ @comment = -comment if comment
+ super
+ end
end
class NullColumn < Column
diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb
index 9eaf9d9a89..0732b69f81 100644
--- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb
+++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb
@@ -50,13 +50,12 @@ module ActiveRecord
# Converts the given URL to a full connection hash.
def to_hash
- config = raw_config.reject { |_, value| value.blank? }
+ config = raw_config.compact_blank
config.map { |key, value| config[key] = uri_parser.unescape(value) if value.is_a? String }
config
end
private
-
attr_reader :uri
def uri_parser
diff --git a/activerecord/lib/active_record/connection_adapters/deduplicable.rb b/activerecord/lib/active_record/connection_adapters/deduplicable.rb
new file mode 100644
index 0000000000..fb2fd60bbc
--- /dev/null
+++ b/activerecord/lib/active_record/connection_adapters/deduplicable.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module ActiveRecord
+ module ConnectionAdapters # :nodoc:
+ module Deduplicable
+ extend ActiveSupport::Concern
+
+ module ClassMethods
+ def registry
+ @registry ||= {}
+ end
+
+ def new(*)
+ super.deduplicate
+ end
+ end
+
+ def deduplicate
+ self.class.registry[self] ||= deduplicated
+ end
+ alias :-@ :deduplicate
+
+ private
+ def deduplicated
+ freeze
+ end
+ end
+ end
+end
diff --git a/activerecord/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb b/activerecord/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb
index 1df4dea2d8..97d74df529 100644
--- a/activerecord/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb
+++ b/activerecord/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb
@@ -5,7 +5,7 @@ module ActiveRecord
module DetermineIfPreparableVisitor
attr_accessor :preparable
- def accept(*)
+ def accept(object, collector)
@preparable = true
super
end
@@ -20,7 +20,7 @@ module ActiveRecord
super
end
- def visit_Arel_Nodes_SqlLiteral(*)
+ def visit_Arel_Nodes_SqlLiteral(o, collector)
@preparable = false
super
end
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb b/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb
index 2132e5d248..bbcdc96cdc 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb
@@ -26,6 +26,15 @@ module ActiveRecord
!READ_QUERY.match?(sql)
end
+ def explain(arel, binds = [])
+ sql = "EXPLAIN #{to_sql(arel, binds)}"
+ start = Concurrent.monotonic_time
+ result = exec_query(sql, "EXPLAIN", binds)
+ elapsed = Concurrent.monotonic_time - start
+
+ MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
+ end
+
# Executes the SQL statement in the context of this connection.
def execute(sql, name = nil)
if preventing_writes? && write_query?(sql)
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb b/activerecord/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb
index 20c3c83664..edd5ea0542 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb
@@ -37,7 +37,6 @@ module ActiveRecord
end
private
-
def compute_column_widths(result)
[].tap do |widths|
result.columns.each_with_index do |column, i|
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb
index 75564a61d6..0069f5871c 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb
@@ -5,11 +5,11 @@ module ActiveRecord
module MySQL
module Quoting # :nodoc:
def quote_column_name(name)
- @quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`"
+ self.class.quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`"
end
def quote_table_name(name)
- @quoted_table_names[name] ||= super.gsub(".", "`.`").freeze
+ self.class.quoted_table_names[name] ||= super.gsub(".", "`.`").freeze
end
def unquoted_true
@@ -32,12 +32,49 @@ module ActiveRecord
"x'#{value.hex}'"
end
- def _type_cast(value)
- case value
- when Date, Time then value
- else super
- end
+ def column_name_matcher
+ COLUMN_NAME
+ end
+
+ def column_name_with_order_matcher
+ COLUMN_NAME_WITH_ORDER
end
+
+ COLUMN_NAME = /
+ \A
+ (
+ (?:
+ # `table_name`.`column_name` | function(one or no argument)
+ ((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`)) | \w+\((?:|\g<2>)\)
+ )
+ (?:(?:\s+AS)?\s+(?:\w+|`\w+`))?
+ )
+ (?:\s*,\s*\g<1>)*
+ \z
+ /ix
+
+ COLUMN_NAME_WITH_ORDER = /
+ \A
+ (
+ (?:
+ # `table_name`.`column_name` | function(one or no argument)
+ ((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`)) | \w+\((?:|\g<2>)\)
+ )
+ (?:\s+ASC|\s+DESC)?
+ )
+ (?:\s*,\s*\g<1>)*
+ \z
+ /ix
+
+ private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
+
+ private
+ def _type_cast(value)
+ case value
+ when Date, Time then value
+ else super
+ end
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/schema_creation.rb b/activerecord/lib/active_record/connection_adapters/mysql/schema_creation.rb
index 82ed320617..0f5ab7562a 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/schema_creation.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/schema_creation.rb
@@ -7,7 +7,6 @@ module ActiveRecord
delegate :add_sql_comment!, :mariadb?, to: :@conn, private: true
private
-
def visit_DropForeignKey(name)
"DROP FOREIGN KEY #{name}"
end
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb
index 234fb25fdf..bcd300f3db 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb
@@ -41,13 +41,15 @@ module ActiveRecord
case column.sql_type
when /\Atimestamp\b/
:timestamp
+ when /\A(?:enum|set)\b/
+ column.sql_type
else
super
end
end
def schema_limit(column)
- super unless /\A(?:tiny|medium|long)?(?:text|blob)/.match?(column.sql_type)
+ super unless /\A(?:enum|set|(?:tiny|medium|long)?(?:text|blob))\b/.match?(column.sql_type)
end
def schema_precision(column)
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb b/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb
index 9167593064..a7232fa249 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb
@@ -6,9 +6,11 @@ module ActiveRecord
class TypeMetadata < DelegateClass(SqlTypeMetadata) # :nodoc:
undef to_yaml if method_defined?(:to_yaml)
+ include Deduplicable
+
attr_reader :extra
- def initialize(type_metadata, extra: "")
+ def initialize(type_metadata, extra: nil)
super(type_metadata)
@extra = extra
end
@@ -25,6 +27,13 @@ module ActiveRecord
__getobj__.hash ^
extra.hash
end
+
+ private
+ def deduplicated
+ __setobj__(__getobj__.deduplicate)
+ @extra = -extra if extra
+ super
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
index 5b0335c22b..1df9ac32c9 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
@@ -8,6 +8,8 @@ require "mysql2"
module ActiveRecord
module ConnectionHandling # :nodoc:
+ ER_BAD_DB_ERROR = 1049
+
# Establishes a connection to the database that's used by all Active Record objects.
def mysql2_connection(config)
config = config.symbolize_keys
@@ -22,7 +24,7 @@ module ActiveRecord
client = Mysql2::Client.new(config)
ConnectionAdapters::Mysql2Adapter.new(client, logger, nil, config)
rescue Mysql2::Error => error
- if error.message.include?("Unknown database")
+ if error.error_number == ER_BAD_DB_ERROR
raise ActiveRecord::NoDatabaseError
else
raise
@@ -42,6 +44,12 @@ module ActiveRecord
configure_connection
end
+ def self.database_exists?(config)
+ !!ActiveRecord::Base.mysql2_connection(config)
+ rescue ActiveRecord::NoDatabaseError
+ false
+ end
+
def supports_json?
!mariadb? && database_version >= "5.7.8"
end
@@ -109,12 +117,12 @@ module ActiveRecord
end
def discard! # :nodoc:
+ super
@connection.automatic_close = false
@connection = nil
end
private
-
def connect
@connection = Mysql2::Client.new(@config)
configure_connection
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
index ec25bb1e19..f1ecf6df30 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
@@ -23,6 +23,29 @@ module ActiveRecord
def sql_type
super.sub(/\[\]\z/, "")
end
+
+ def init_with(coder)
+ @serial = coder["serial"]
+ super
+ end
+
+ def encode_with(coder)
+ coder["serial"] = @serial
+ super
+ end
+
+ def ==(other)
+ other.is_a?(Column) &&
+ super &&
+ serial? == other.serial?
+ end
+ alias :eql? :==
+
+ def hash
+ Column.hash ^
+ super.hash ^
+ serial?.hash
+ end
end
end
PostgreSQLColumn = PostgreSQL::Column # :nodoc:
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb
index d872bd662f..45ec79ca78 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb
@@ -145,7 +145,7 @@ module ActiveRecord
# Begins a transaction.
def begin_db_transaction
- execute "BEGIN"
+ execute("BEGIN", "TRANSACTION")
end
def begin_isolated_db_transaction(isolation)
@@ -155,12 +155,12 @@ module ActiveRecord
# Commits a transaction.
def commit_db_transaction
- execute "COMMIT"
+ execute("COMMIT", "TRANSACTION")
end
# Aborts a transaction.
def exec_rollback_db_transaction
- execute "ROLLBACK"
+ execute("ROLLBACK", "TRANSACTION")
end
private
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 b1dfbde86e..0bbe98145a 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
@@ -77,7 +77,6 @@ module ActiveRecord
end
private
-
def type_cast_array(value, method)
if value.is_a?(::Array)
value.map { |item| type_cast_array(item, method) }
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 f70f09ad95..bae34472e1 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb
@@ -10,7 +10,6 @@ module ActiveRecord
end
private
-
def cast_value(value)
value.to_s
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb
index 7b42677101..8d4dacbd64 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb
@@ -46,7 +46,6 @@ module ActiveRecord
end
private
-
HstorePair = begin
quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/
unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb
index 7f6adc351c..e52d4385ef 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb
@@ -34,7 +34,6 @@ module ActiveRecord
end
private
-
def number_for_point(number)
number.to_s.gsub(/\.0$/, "")
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/money.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/money.rb
index 6434377b57..357493dfc0 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/money.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/money.rb
@@ -26,9 +26,9 @@ module ActiveRecord
value = value.sub(/^\((.+)\)$/, '-\1') # (4)
case value
- when /^-?\D+[\d,]+\.\d{2}$/ # (1)
+ when /^-?\D*[\d,]+\.\d{2}$/ # (1)
value.gsub!(/[^-\d.]/, "")
- when /^-?\D+[\d.]+,\d{2}$/ # (2)
+ when /^-?\D*[\d.]+,\d{2}$/ # (2)
value.gsub!(/[^-\d,]/, "").sub!(/,/, ".")
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb
index 8c74cecc4d..e81e18ff70 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb
@@ -50,7 +50,6 @@ module ActiveRecord
end
private
-
def number_for_point(number)
number.to_s.gsub(/\.0$/, "")
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb
index aa7701e038..d19f1f9cf8 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb
@@ -58,7 +58,6 @@ module ActiveRecord
end
private
-
def type_cast_single(value)
infinity?(value) ? value : @subtype.deserialize(value)
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/uuid.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/uuid.rb
index 28abdbd073..74a28eef58 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/uuid.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/uuid.rb
@@ -14,7 +14,6 @@ module ActiveRecord
end
private
-
def cast_value(value)
casted = value.to_s
casted if casted.match?(ACCEPTABLE_UUID)
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
index d40e0ef1f0..07b66de366 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
@@ -30,7 +30,7 @@ module ActiveRecord
# - "schema.name".table_name
# - "schema.name"."table.name"
def quote_table_name(name) # :nodoc:
- @quoted_table_names[name] ||= Utils.extract_schema_qualified_name(name.to_s).quoted.freeze
+ self.class.quoted_table_names[name] ||= Utils.extract_schema_qualified_name(name.to_s).quoted.freeze
end
# Quotes schema names for use in SQL queries.
@@ -44,7 +44,7 @@ module ActiveRecord
# Quotes column names for use in SQL queries.
def quote_column_name(name) # :nodoc:
- @quoted_column_names[name] ||= PG::Connection.quote_ident(super).freeze
+ self.class.quoted_column_names[name] ||= PG::Connection.quote_ident(super).freeze
end
# Quote date/time values for use in SQL input.
@@ -78,6 +78,43 @@ module ActiveRecord
type_map.lookup(column.oid, column.fmod, column.sql_type)
end
+ def column_name_matcher
+ COLUMN_NAME
+ end
+
+ def column_name_with_order_matcher
+ COLUMN_NAME_WITH_ORDER
+ end
+
+ COLUMN_NAME = /
+ \A
+ (
+ (?:
+ # "table_name"."column_name"::type_name | function(one or no argument)::type_name
+ ((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")(?:::\w+)?) | \w+\((?:|\g<2>)\)(?:::\w+)?
+ )
+ (?:(?:\s+AS)?\s+(?:\w+|"\w+"))?
+ )
+ (?:\s*,\s*\g<1>)*
+ \z
+ /ix
+
+ COLUMN_NAME_WITH_ORDER = /
+ \A
+ (
+ (?:
+ # "table_name"."column_name"::type_name | function(one or no argument)::type_name
+ ((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")(?:::\w+)?) | \w+\((?:|\g<2>)\)(?:::\w+)?
+ )
+ (?:\s+ASC|\s+DESC)?
+ (?:\s+NULLS\s+(?:FIRST|LAST))?
+ )
+ (?:\s*,\s*\g<1>)*
+ \z
+ /ix
+
+ private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
+
private
def lookup_cast_type(sql_type)
super(query_value("SELECT #{quote(sql_type)}::regtype::oid", "SCHEMA").to_i)
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb
index 84643d20da..d201e40190 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb
@@ -5,7 +5,6 @@ module ActiveRecord
module PostgreSQL
class SchemaDumper < ConnectionAdapters::SchemaDumper # :nodoc:
private
-
def extensions(stream)
extensions = @connection.extensions
if extensions.any?
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 40c5e51d92..628a609521 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -55,6 +55,7 @@ module ActiveRecord
end
def drop_table(table_name, options = {}) # :nodoc:
+ schema_cache.clear_data_source_cache!(table_name.to_s)
execute "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
end
@@ -376,6 +377,8 @@ module ActiveRecord
# rename_table('octopuses', 'octopi')
def rename_table(table_name, new_name)
clear_cache!
+ schema_cache.clear_data_source_cache!(table_name.to_s)
+ schema_cache.clear_data_source_cache!(new_name.to_s)
execute "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}"
pk, seq = pk_and_sequence_for(new_name)
if pk
@@ -552,13 +555,13 @@ module ActiveRecord
# PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
# requires that the ORDER BY include the distinct column.
def columns_for_distinct(columns, orders) #:nodoc:
- order_columns = orders.reject(&:blank?).map { |s|
+ order_columns = orders.compact_blank.map { |s|
# Convert Arel node to string
s = s.to_sql unless s.is_a?(String)
# Remove any ASC/DESC modifiers
s.gsub(/\s+(?:ASC|DESC)\b/i, "")
.gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, "")
- }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
+ }.compact_blank.map.with_index { |column, i| "#{column} AS alias_#{i}" }
(order_columns << super).join(", ")
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb b/activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb
index 8bdec623af..b7f6479357 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb
@@ -7,6 +7,8 @@ module ActiveRecord
class TypeMetadata < DelegateClass(SqlTypeMetadata)
undef to_yaml if method_defined?(:to_yaml)
+ include Deduplicable
+
attr_reader :oid, :fmod
def initialize(type_metadata, oid: nil, fmod: nil)
@@ -29,6 +31,12 @@ module ActiveRecord
oid.hash ^
fmod.hash
end
+
+ private
+ def deduplicated
+ __setobj__(__getobj__.deduplicate)
+ super
+ end
end
end
PostgreSQLTypeMetadata = PostgreSQL::TypeMetadata
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/utils.rb b/activerecord/lib/active_record/connection_adapters/postgresql/utils.rb
index f2f4701500..e8caeb8132 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/utils.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/utils.rb
@@ -37,7 +37,6 @@ module ActiveRecord
end
protected
-
def parts
@parts ||= [@schema, @identifier].compact
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 91318a0af1..0a7c6d8ac4 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -46,7 +46,7 @@ module ActiveRecord
conn = PG.connect(conn_params)
ConnectionAdapters::PostgreSQLAdapter.new(conn, logger, conn_params, config)
rescue ::PG::Error => error
- if error.message.include?("does not exist")
+ if error.message.include?(conn_params[:dbname])
raise ActiveRecord::NoDatabaseError
else
raise
@@ -259,6 +259,12 @@ module ActiveRecord
@use_insert_returning = @config.key?(:insert_returning) ? self.class.type_cast_config_to_boolean(@config[:insert_returning]) : true
end
+ def self.database_exists?(config)
+ !!ActiveRecord::Base.postgresql_connection(config)
+ rescue ActiveRecord::NoDatabaseError
+ false
+ end
+
# Is this connection alive and ready for queries?
def active?
@lock.synchronize do
@@ -302,6 +308,7 @@ module ActiveRecord
end
def discard! # :nodoc:
+ super
@connection.socket_io.reopen(IO::NULL) rescue nil
@connection = nil
end
@@ -452,7 +459,6 @@ module ActiveRecord
end
private
-
# See https://www.postgresql.org/docs/current/static/errcodes-appendix.html
VALUE_LIMIT_VIOLATION = "22001"
NUMERIC_VALUE_OUT_OF_RANGE = "22003"
diff --git a/activerecord/lib/active_record/connection_adapters/schema_cache.rb b/activerecord/lib/active_record/connection_adapters/schema_cache.rb
index dbfe1e4a34..5e30304864 100644
--- a/activerecord/lib/active_record/connection_adapters/schema_cache.rb
+++ b/activerecord/lib/active_record/connection_adapters/schema_cache.rb
@@ -27,7 +27,6 @@ module ActiveRecord
def encode_with(coder)
coder["columns"] = @columns
- coder["columns_hash"] = @columns_hash
coder["primary_keys"] = @primary_keys
coder["data_sources"] = @data_sources
coder["indexes"] = @indexes
@@ -37,16 +36,21 @@ module ActiveRecord
def init_with(coder)
@columns = coder["columns"]
- @columns_hash = coder["columns_hash"]
@primary_keys = coder["primary_keys"]
@data_sources = coder["data_sources"]
@indexes = coder["indexes"] || {}
@version = coder["version"]
@database_version = coder["database_version"]
+
+ derive_columns_hash_and_deduplicate_values
end
def primary_keys(table_name)
- @primary_keys[table_name] ||= data_source_exists?(table_name) ? connection.primary_key(table_name) : nil
+ @primary_keys.fetch(table_name) do
+ if data_source_exists?(table_name)
+ @primary_keys[deep_deduplicate(table_name)] = deep_deduplicate(connection.primary_key(table_name))
+ end
+ end
end
# A cached lookup for table existence.
@@ -54,7 +58,7 @@ module ActiveRecord
prepare_data_sources if @data_sources.empty?
return @data_sources[name] if @data_sources.key? name
- @data_sources[name] = connection.data_source_exists?(name)
+ @data_sources[deep_deduplicate(name)] = connection.data_source_exists?(name)
end
# Add internal cache for table with +table_name+.
@@ -73,15 +77,17 @@ module ActiveRecord
# Get the columns for a table
def columns(table_name)
- @columns[table_name] ||= connection.columns(table_name)
+ @columns.fetch(table_name) do
+ @columns[deep_deduplicate(table_name)] = deep_deduplicate(connection.columns(table_name))
+ end
end
# Get the columns for a table as a hash, key is the column name
# value is the column object.
def columns_hash(table_name)
- @columns_hash[table_name] ||= Hash[columns(table_name).map { |col|
- [col.name, col]
- }]
+ @columns_hash.fetch(table_name) do
+ @columns_hash[deep_deduplicate(table_name)] = columns(table_name).index_by(&:name)
+ end
end
# Checks whether the columns hash is already cached for a table.
@@ -90,7 +96,9 @@ module ActiveRecord
end
def indexes(table_name)
- @indexes[table_name] ||= connection.indexes(table_name)
+ @indexes.fetch(table_name) do
+ @indexes[deep_deduplicate(table_name)] = deep_deduplicate(connection.indexes(table_name))
+ end
end
def database_version # :nodoc:
@@ -124,15 +132,38 @@ module ActiveRecord
def marshal_dump
# if we get current version during initialization, it happens stack over flow.
@version = connection.migration_context.current_version
- [@version, @columns, @columns_hash, @primary_keys, @data_sources, @indexes, database_version]
+ [@version, @columns, {}, @primary_keys, @data_sources, @indexes, database_version]
end
def marshal_load(array)
- @version, @columns, @columns_hash, @primary_keys, @data_sources, @indexes, @database_version = array
- @indexes = @indexes || {}
+ @version, @columns, _columns_hash, @primary_keys, @data_sources, @indexes, @database_version = array
+ @indexes ||= {}
+
+ derive_columns_hash_and_deduplicate_values
end
private
+ def derive_columns_hash_and_deduplicate_values
+ @columns = deep_deduplicate(@columns)
+ @columns_hash = @columns.transform_values { |columns| columns.index_by(&:name) }
+ @primary_keys = deep_deduplicate(@primary_keys)
+ @data_sources = deep_deduplicate(@data_sources)
+ @indexes = deep_deduplicate(@indexes)
+ end
+
+ def deep_deduplicate(value)
+ case value
+ when Hash
+ value.transform_keys { |k| deep_deduplicate(k) }.transform_values { |v| deep_deduplicate(v) }
+ when Array
+ value.map { |i| deep_deduplicate(i) }
+ when String, Deduplicable
+ -value
+ else
+ value
+ end
+ end
+
def prepare_data_sources
connection.data_sources.each { |source| @data_sources[source] = true }
end
diff --git a/activerecord/lib/active_record/connection_adapters/sql_type_metadata.rb b/activerecord/lib/active_record/connection_adapters/sql_type_metadata.rb
index df28df7a7c..969867e70f 100644
--- a/activerecord/lib/active_record/connection_adapters/sql_type_metadata.rb
+++ b/activerecord/lib/active_record/connection_adapters/sql_type_metadata.rb
@@ -1,9 +1,13 @@
# frozen_string_literal: true
+require "active_record/connection_adapters/deduplicable"
+
module ActiveRecord
# :stopdoc:
module ConnectionAdapters
class SqlTypeMetadata
+ include Deduplicable
+
attr_reader :sql_type, :type, :limit, :precision, :scale
def initialize(sql_type: nil, type: nil, limit: nil, precision: nil, scale: nil)
@@ -32,6 +36,12 @@ module ActiveRecord
precision.hash >> 1 ^
scale.hash >> 2
end
+
+ private
+ def deduplicated
+ @sql_type = -sql_type
+ super
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3/database_statements.rb b/activerecord/lib/active_record/connection_adapters/sqlite3/database_statements.rb
index 46ce1a15b5..85053acf91 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3/database_statements.rb
@@ -11,6 +11,11 @@ module ActiveRecord
!READ_QUERY.match?(sql)
end
+ def explain(arel, binds = [])
+ sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
+ SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
+ end
+
def execute(sql, name = nil) #:nodoc:
if preventing_writes? && write_query?(sql)
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
@@ -68,18 +73,17 @@ module ActiveRecord
alias :exec_update :exec_delete
def begin_db_transaction #:nodoc:
- log("begin transaction", nil) { @connection.transaction }
+ log("begin transaction", "TRANSACTION") { @connection.transaction }
end
def commit_db_transaction #:nodoc:
- log("commit transaction", nil) { @connection.commit }
+ log("commit transaction", "TRANSACTION") { @connection.commit }
end
def exec_rollback_db_transaction #:nodoc:
- log("rollback transaction", nil) { @connection.rollback }
+ log("rollback transaction", "TRANSACTION") { @connection.rollback }
end
-
private
def execute_batch(sql, name = nil)
if preventing_writes? && write_query?(sql)
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb b/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb
index cb9d32a577..9b74a774e5 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb
@@ -13,11 +13,11 @@ module ActiveRecord
end
def quote_table_name(name)
- @quoted_table_names[name] ||= super.gsub(".", "\".\"").freeze
+ self.class.quoted_table_names[name] ||= super.gsub(".", "\".\"").freeze
end
def quote_column_name(name)
- @quoted_column_names[name] ||= %Q("#{super.gsub('"', '""')}")
+ self.class.quoted_column_names[name] ||= %Q("#{super.gsub('"', '""')}")
end
def quoted_time(value)
@@ -45,8 +45,43 @@ module ActiveRecord
0
end
- private
+ def column_name_matcher
+ COLUMN_NAME
+ end
+
+ def column_name_with_order_matcher
+ COLUMN_NAME_WITH_ORDER
+ end
+ COLUMN_NAME = /
+ \A
+ (
+ (?:
+ # "table_name"."column_name" | function(one or no argument)
+ ((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")) | \w+\((?:|\g<2>)\)
+ )
+ (?:(?:\s+AS)?\s+(?:\w+|"\w+"))?
+ )
+ (?:\s*,\s*\g<1>)*
+ \z
+ /ix
+
+ COLUMN_NAME_WITH_ORDER = /
+ \A
+ (
+ (?:
+ # "table_name"."column_name" | function(one or no argument)
+ ((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")) | \w+\((?:|\g<2>)\)
+ )
+ (?:\s+ASC|\s+DESC)?
+ )
+ (?:\s*,\s*\g<1>)*
+ \z
+ /ix
+
+ private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
+
+ private
def _type_cast(value)
case value
when BigDecimal
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index f5f5827d04..f4847eb6c0 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -48,8 +48,8 @@ module ActiveRecord
end
module ConnectionAdapters #:nodoc:
- # The SQLite3 adapter works SQLite 3.6.16 or newer
- # with the sqlite3-ruby drivers (available as gem from https://rubygems.org/gems/sqlite3).
+ # The SQLite3 adapter works with the sqlite3-ruby drivers
+ # (available as gem from https://rubygems.org/gems/sqlite3).
#
# Options:
#
@@ -98,6 +98,16 @@ module ActiveRecord
configure_connection
end
+ def self.database_exists?(config)
+ config = config.symbolize_keys
+ if config[:database] == ":memory:"
+ return true
+ else
+ database_file = defined?(Rails.root) ? File.expand_path(config[:database], Rails.root) : config[:database]
+ File.exist?(database_file)
+ end
+ end
+
def supports_ddl_transactions?
true
end
@@ -201,14 +211,6 @@ module ActiveRecord
end
end
- #--
- # DATABASE STATEMENTS ======================================
- #++
- def explain(arel, binds = [])
- sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
- SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
- end
-
# SCHEMA STATEMENTS ========================================
def primary_keys(table_name) # :nodoc:
@@ -226,6 +228,8 @@ module ActiveRecord
# Example:
# rename_table('octopuses', 'octopi')
def rename_table(table_name, new_name)
+ schema_cache.clear_data_source_cache!(table_name.to_s)
+ schema_cache.clear_data_source_cache!(new_name.to_s)
exec_query "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}"
rename_table_indexes(table_name, new_name)
end
@@ -389,6 +393,7 @@ module ActiveRecord
if from_primary_key.is_a?(Array)
@definition.primary_keys from_primary_key
end
+
columns(from).each do |column|
column_name = options[:rename] ?
(options[:rename][column.name] ||
@@ -485,9 +490,9 @@ module ActiveRecord
result = exec_query(sql, "SCHEMA").first
if result
- # Splitting with left parentheses and picking up last will return all
+ # Splitting with left parentheses and discarding the first part will return all
# columns separated with comma(,).
- columns_string = result["sql"].split("(").last
+ columns_string = result["sql"].split("(", 2).last
columns_string.split(",").each do |column_string|
# This regex will match the column name and collation type and will save
diff --git a/activerecord/lib/active_record/connection_adapters/statement_pool.rb b/activerecord/lib/active_record/connection_adapters/statement_pool.rb
index 46bd831da7..0960feed84 100644
--- a/activerecord/lib/active_record/connection_adapters/statement_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/statement_pool.rb
@@ -48,7 +48,6 @@ module ActiveRecord
end
private
-
def cache
@cache[Process.pid]
end
diff --git a/activerecord/lib/active_record/connection_handling.rb b/activerecord/lib/active_record/connection_handling.rb
index 040ebdb960..c8cefa9906 100644
--- a/activerecord/lib/active_record/connection_handling.rb
+++ b/activerecord/lib/active_record/connection_handling.rb
@@ -173,7 +173,7 @@ module ActiveRecord
raise "Anonymous class is not allowed." unless name
config_or_env ||= DEFAULT_ENV.call.to_sym
- pool_name = self == Base ? "primary" : name
+ pool_name = primary_class? ? "primary" : name
self.connection_specification_name = pool_name
resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new(Base.configurations)
@@ -204,11 +204,15 @@ module ActiveRecord
# Return the specification name from the current class or its parent.
def connection_specification_name
if !defined?(@connection_specification_name) || @connection_specification_name.nil?
- return self == Base ? "primary" : superclass.connection_specification_name
+ return primary_class? ? "primary" : superclass.connection_specification_name
end
@connection_specification_name
end
+ def primary_class? # :nodoc:
+ self == Base || defined?(ApplicationRecord) && self == ApplicationRecord
+ end
+
# Returns the configuration of the associated connection as a hash:
#
# ActiveRecord::Base.connection_config
@@ -252,7 +256,6 @@ module ActiveRecord
:clear_all_connections!, :flush_idle_connections!, to: :connection_handler
private
-
def swap_connection_handler(handler, &blk) # :nodoc:
old_handler, ActiveRecord::Base.connection_handler = ActiveRecord::Base.connection_handler, handler
yield
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index dfd33d3dd7..595ef4ee25 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -286,7 +286,6 @@ module ActiveRecord
end
private
-
def cached_find_by_statement(key, &block)
cache = @find_by_statement_cache[connection.prepared_statements]
cache.compute_if_absent(key) { StatementCache.create(connection, &block) }
@@ -554,7 +553,6 @@ module ActiveRecord
end
private
-
# +Array#flatten+ will call +#to_ary+ (recursively) on each of the elements of
# the array, and then rescues from the possible +NoMethodError+. If those elements are
# +ActiveRecord::Base+'s, then this triggers the various +method_missing+'s that we have,
diff --git a/activerecord/lib/active_record/database_configurations.rb b/activerecord/lib/active_record/database_configurations.rb
index 44b5cfc738..8baa0f5af6 100644
--- a/activerecord/lib/active_record/database_configurations.rb
+++ b/activerecord/lib/active_record/database_configurations.rb
@@ -104,18 +104,30 @@ module ActiveRecord
return configs.configurations if configs.is_a?(DatabaseConfigurations)
return configs if configs.is_a?(Array)
- build_db_config = configs.each_pair.flat_map do |env_name, config|
- walk_configs(env_name.to_s, "primary", config)
- end.flatten.compact
+ db_configs = configs.flat_map do |env_name, config|
+ if config.is_a?(Hash) && config.all? { |_, v| v.is_a?(Hash) }
+ walk_configs(env_name.to_s, config)
+ else
+ build_db_config_from_raw_config(env_name.to_s, "primary", config)
+ end
+ end
- if url = ENV["DATABASE_URL"]
- build_url_config(url, build_db_config)
- else
- build_db_config
+ current_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call.to_s
+
+ unless db_configs.find(&:for_current_env?)
+ db_configs << environment_url_config(current_env, "primary", {})
+ end
+
+ merge_db_environment_variables(current_env, db_configs.compact)
+ end
+
+ def walk_configs(env_name, config)
+ config.map do |spec_name, sub_config|
+ build_db_config_from_raw_config(env_name, spec_name.to_s, sub_config)
end
end
- def walk_configs(env_name, spec_name, config)
+ def build_db_config_from_raw_config(env_name, spec_name, config)
case config
when String
build_db_config_from_string(env_name, spec_name, config)
@@ -141,31 +153,27 @@ module ActiveRecord
config_without_url.delete "url"
ActiveRecord::DatabaseConfigurations::UrlConfig.new(env_name, spec_name, url, config_without_url)
- elsif config["database"] || (config.size == 1 && config.values.all? { |v| v.is_a? String })
- ActiveRecord::DatabaseConfigurations::HashConfig.new(env_name, spec_name, config)
else
- config.each_pair.map do |sub_spec_name, sub_config|
- walk_configs(env_name, sub_spec_name, sub_config)
- end
+ ActiveRecord::DatabaseConfigurations::HashConfig.new(env_name, spec_name, config)
end
end
- def build_url_config(url, configs)
- env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call.to_s
+ def merge_db_environment_variables(current_env, configs)
+ configs.map do |config|
+ next config if config.url_config? || config.env_name != current_env
- if original_config = configs.find(&:for_current_env?)
- if original_config.url_config?
- configs
- else
- configs.map do |config|
- ActiveRecord::DatabaseConfigurations::UrlConfig.new(config.env_name, config.spec_name, url, config.config)
- end
- end
- else
- configs + [ActiveRecord::DatabaseConfigurations::UrlConfig.new(env, "primary", url)]
+ url_config = environment_url_config(current_env, config.spec_name, config.config)
+ url_config || config
end
end
+ def environment_url_config(env, spec_name, config)
+ url = ENV["DATABASE_URL"]
+ return unless url
+
+ ActiveRecord::DatabaseConfigurations::UrlConfig.new(env, spec_name, url, config)
+ end
+
def method_missing(method, *args, &blk)
case method
when :each, :first
diff --git a/activerecord/lib/active_record/database_configurations/url_config.rb b/activerecord/lib/active_record/database_configurations/url_config.rb
index e2d30ae416..e6b4acc647 100644
--- a/activerecord/lib/active_record/database_configurations/url_config.rb
+++ b/activerecord/lib/active_record/database_configurations/url_config.rb
@@ -56,7 +56,6 @@ module ActiveRecord
end
private
-
def build_url_hash(url)
if url.nil? || /^jdbc:/.match?(url)
{ "url" => url }
diff --git a/activerecord/lib/active_record/dynamic_matchers.rb b/activerecord/lib/active_record/dynamic_matchers.rb
index 398a029068..7d9e221faa 100644
--- a/activerecord/lib/active_record/dynamic_matchers.rb
+++ b/activerecord/lib/active_record/dynamic_matchers.rb
@@ -69,7 +69,6 @@ module ActiveRecord
end
private
-
def body
"#{finder}(#{attributes_hash})"
end
diff --git a/activerecord/lib/active_record/enum.rb b/activerecord/lib/active_record/enum.rb
index 8077630aeb..fc49f752aa 100644
--- a/activerecord/lib/active_record/enum.rb
+++ b/activerecord/lib/active_record/enum.rb
@@ -200,6 +200,8 @@ module ActiveRecord
# scope :active, -> { where(status: 0) }
# scope :not_active, -> { where.not(status: 0) }
if enum_scopes != false
+ klass.send(:detect_negative_condition!, value_method_name)
+
klass.send(:detect_enum_conflict!, name, value_method_name, true)
klass.scope value_method_name, -> { where(attr => value) }
@@ -261,5 +263,12 @@ module ActiveRecord
source: source
}
end
+
+ def detect_negative_condition!(method_name)
+ if method_name.start_with?("not_") && logger
+ logger.warn "An enum element in #{self.name} uses the prefix 'not_'." \
+ " This will cause a conflict with auto generated negative scopes."
+ end
+ end
end
end
diff --git a/activerecord/lib/active_record/errors.rb b/activerecord/lib/active_record/errors.rb
index 60cf9818c1..20cc987d6e 100644
--- a/activerecord/lib/active_record/errors.rb
+++ b/activerecord/lib/active_record/errors.rb
@@ -38,6 +38,10 @@ module ActiveRecord
class AdapterNotSpecified < ActiveRecordError
end
+ # Raised when a model makes a query but it has not specified an associated table.
+ class TableNotSpecified < ActiveRecordError
+ end
+
# Raised when Active Record cannot find database adapter specified in
# +config/database.yml+ or programmatically.
class AdapterNotFound < ActiveRecordError
@@ -349,16 +353,24 @@ module ActiveRecord
class IrreversibleOrderError < ActiveRecordError
end
+ # Superclass for errors that have been aborted (either by client or server).
+ class QueryAborted < StatementInvalid
+ end
+
# LockWaitTimeout will be raised when lock wait timeout exceeded.
class LockWaitTimeout < StatementInvalid
end
# StatementTimeout will be raised when statement timeout exceeded.
- class StatementTimeout < StatementInvalid
+ class StatementTimeout < QueryAborted
end
# QueryCanceled will be raised when canceling statement due to user request.
- class QueryCanceled < StatementInvalid
+ class QueryCanceled < QueryAborted
+ end
+
+ # AdapterTimeout will be raised when database clients times out while waiting from the server.
+ class AdapterTimeout < QueryAborted
end
# UnknownAttributeReference is raised when an unknown and potentially unsafe
diff --git a/activerecord/lib/active_record/explain.rb b/activerecord/lib/active_record/explain.rb
index 919e96cd7a..5dca75c539 100644
--- a/activerecord/lib/active_record/explain.rb
+++ b/activerecord/lib/active_record/explain.rb
@@ -36,7 +36,6 @@ module ActiveRecord
end
private
-
def render_bind(attr)
value = if attr.type.binary? && attr.value
"<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
diff --git a/activerecord/lib/active_record/fixture_set/table_row.rb b/activerecord/lib/active_record/fixture_set/table_row.rb
index cb4726f1ee..f65329f91d 100644
--- a/activerecord/lib/active_record/fixture_set/table_row.rb
+++ b/activerecord/lib/active_record/fixture_set/table_row.rb
@@ -48,7 +48,6 @@ module ActiveRecord
end
private
-
def model_metadata
@table_rows.model_metadata
end
diff --git a/activerecord/lib/active_record/fixture_set/table_rows.rb b/activerecord/lib/active_record/fixture_set/table_rows.rb
index 23814b6cb5..df1cd63963 100644
--- a/activerecord/lib/active_record/fixture_set/table_rows.rb
+++ b/activerecord/lib/active_record/fixture_set/table_rows.rb
@@ -29,7 +29,6 @@ module ActiveRecord
end
private
-
def build_table_rows_from(table_name, fixtures, config)
now = config.default_timezone == :utc ? Time.now.utc : Time.now
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 327121a2a2..046ed0e95c 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -464,7 +464,6 @@ module ActiveRecord
end
private
-
def insert_class(class_names, name, klass)
# We only want to deal with AR objects.
if klass && klass < ActiveRecord::Base
@@ -570,7 +569,6 @@ module ActiveRecord
end
private
-
def read_and_insert(fixtures_directory, fixture_files, class_names, connection) # :nodoc:
fixtures_map = {}
fixture_sets = fixture_files.map do |fixture_set_name|
@@ -661,7 +659,6 @@ module ActiveRecord
end
private
-
def model_class=(class_name)
if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any?
@model_class = class_name
diff --git a/activerecord/lib/active_record/inheritance.rb b/activerecord/lib/active_record/inheritance.rb
index 9570bc6f86..5ca48fa18c 100644
--- a/activerecord/lib/active_record/inheritance.rb
+++ b/activerecord/lib/active_record/inheritance.rb
@@ -176,7 +176,6 @@ module ActiveRecord
end
protected
-
# Returns the class type of the record using the current module as a prefix. So descendants of
# MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
def compute_type(type_name)
@@ -208,7 +207,6 @@ module ActiveRecord
end
private
-
# Called by +instantiate+ to decide which class to use for a new
# record instance. For single-table inheritance, we check the record
# for a +type+ column and return the corresponding class.
@@ -272,7 +270,6 @@ module ActiveRecord
end
private
-
def initialize_internals_callback
super
ensure_proper_type
diff --git a/activerecord/lib/active_record/integration.rb b/activerecord/lib/active_record/integration.rb
index 573a823dbc..4a97061731 100644
--- a/activerecord/lib/active_record/integration.rb
+++ b/activerecord/lib/active_record/integration.rb
@@ -93,7 +93,7 @@ module ActiveRecord
# cache_version, but this method can be overwritten to return something else.
#
# Note, this method will return nil if ActiveRecord::Base.cache_versioning is set to
- # +false+ (which it is by default until Rails 6.0).
+ # +false+.
def cache_version
return unless cache_versioning
diff --git a/activerecord/lib/active_record/internal_metadata.rb b/activerecord/lib/active_record/internal_metadata.rb
index e6166581f1..8f3c6d0ee3 100644
--- a/activerecord/lib/active_record/internal_metadata.rb
+++ b/activerecord/lib/active_record/internal_metadata.rb
@@ -28,10 +28,6 @@ module ActiveRecord
where(key: key).pluck(:value).first
end
- def table_exists?
- connection.table_exists?(table_name)
- end
-
# Creates an internal metadata table with columns +key+ and +value+
def create_table
unless table_exists?
diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb
index 6711ee9bf4..c2a083bf3b 100644
--- a/activerecord/lib/active_record/locking/optimistic.rb
+++ b/activerecord/lib/active_record/locking/optimistic.rb
@@ -156,7 +156,6 @@ module ActiveRecord
end
private
-
# We need to apply this decorator here, rather than on module inclusion. The closure
# created by the matcher would otherwise evaluate for `ActiveRecord::Base`, not the
# sub class being decorated. As such, changes to `lock_optimistically`, or
diff --git a/activerecord/lib/active_record/middleware/database_selector.rb b/activerecord/lib/active_record/middleware/database_selector.rb
index b5b5df074c..7374107048 100644
--- a/activerecord/lib/active_record/middleware/database_selector.rb
+++ b/activerecord/lib/active_record/middleware/database_selector.rb
@@ -35,10 +35,10 @@ module ActiveRecord
# config.active_record.database_resolver = MyResolver
# config.active_record.database_resolver_context = MyResolver::MySession
class DatabaseSelector
- def initialize(app, resolver_klass = Resolver, context_klass = Resolver::Session, options = {})
+ def initialize(app, resolver_klass = nil, context_klass = nil, options = {})
@app = app
- @resolver_klass = resolver_klass
- @context_klass = context_klass
+ @resolver_klass = resolver_klass || Resolver
+ @context_klass = context_klass || Resolver::Session
@options = options
end
@@ -55,7 +55,6 @@ module ActiveRecord
end
private
-
def select_database(request, &blk)
context = context_klass.call(request)
resolver = resolver_klass.call(context, options)
diff --git a/activerecord/lib/active_record/middleware/database_selector/resolver.rb b/activerecord/lib/active_record/middleware/database_selector/resolver.rb
index 80b8cd7cae..3eb1039c50 100644
--- a/activerecord/lib/active_record/middleware/database_selector/resolver.rb
+++ b/activerecord/lib/active_record/middleware/database_selector/resolver.rb
@@ -44,10 +44,9 @@ module ActiveRecord
end
private
-
def read_from_primary(&blk)
- ActiveRecord::Base.connection.while_preventing_writes do
- ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role) do
+ ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role) do
+ ActiveRecord::Base.connection_handler.while_preventing_writes do
instrumenter.instrument("database_selector.active_record.read_from_primary") do
yield
end
diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb
index f20edbeb93..7edfec9903 100644
--- a/activerecord/lib/active_record/migration.rb
+++ b/activerecord/lib/active_record/migration.rb
@@ -494,9 +494,9 @@ module ActiveRecord
# This migration will create the horses table for you on the way up, and
# automatically figure out how to drop the table on the way down.
#
- # Some commands like +remove_column+ cannot be reversed. If you care to
- # define how to move up and down in these cases, you should define the +up+
- # and +down+ methods as before.
+ # Some commands cannot be reversed. If you care to define how to move up
+ # and down in these cases, you should define the +up+ and +down+ methods
+ # as before.
#
# If a command cannot be reversed, an
# <tt>ActiveRecord::IrreversibleMigration</tt> exception will be raised when
@@ -568,7 +568,6 @@ module ActiveRecord
end
private
-
def connection
ActiveRecord::Base.connection
end
@@ -885,13 +884,14 @@ module ActiveRecord
def copy(destination, sources, options = {})
copied = []
+ schema_migration = options[:schema_migration] || ActiveRecord::SchemaMigration
FileUtils.mkdir_p(destination) unless File.exist?(destination)
- destination_migrations = ActiveRecord::MigrationContext.new(destination).migrations
+ destination_migrations = ActiveRecord::MigrationContext.new(destination, schema_migration).migrations
last = destination_migrations.last
sources.each do |scope, path|
- source_migrations = ActiveRecord::MigrationContext.new(path).migrations
+ source_migrations = ActiveRecord::MigrationContext.new(path, schema_migration).migrations
source_migrations.each do |migration|
source = File.binread(migration.filename)
@@ -992,7 +992,6 @@ module ActiveRecord
delegate :migrate, :announce, :write, :disable_ddl_transaction, to: :migration
private
-
def migration
@migration ||= load_migration
end
@@ -1014,10 +1013,11 @@ module ActiveRecord
end
class MigrationContext #:nodoc:
- attr_reader :migrations_paths
+ attr_reader :migrations_paths, :schema_migration
- def initialize(migrations_paths)
+ def initialize(migrations_paths, schema_migration)
@migrations_paths = migrations_paths
+ @schema_migration = schema_migration
end
def migrate(target_version = nil, &block)
@@ -1048,7 +1048,7 @@ module ActiveRecord
migrations
end
- Migrator.new(:up, selected_migrations, target_version).migrate
+ Migrator.new(:up, selected_migrations, schema_migration, target_version).migrate
end
def down(target_version = nil)
@@ -1058,20 +1058,20 @@ module ActiveRecord
migrations
end
- Migrator.new(:down, selected_migrations, target_version).migrate
+ Migrator.new(:down, selected_migrations, schema_migration, target_version).migrate
end
def run(direction, target_version)
- Migrator.new(direction, migrations, target_version).run
+ Migrator.new(direction, migrations, schema_migration, target_version).run
end
def open
- Migrator.new(:up, migrations, nil)
+ Migrator.new(:up, migrations, schema_migration)
end
def get_all_versions
- if SchemaMigration.table_exists?
- SchemaMigration.all_versions.map(&:to_i)
+ if schema_migration.table_exists?
+ schema_migration.all_versions.map(&:to_i)
else
[]
end
@@ -1108,12 +1108,12 @@ module ActiveRecord
end
def migrations_status
- db_list = ActiveRecord::SchemaMigration.normalized_versions
+ db_list = schema_migration.normalized_versions
file_list = migration_files.map do |file|
version, name, scope = parse_migration_filename(file)
raise IllegalMigrationNameError.new(file) unless version
- version = ActiveRecord::SchemaMigration.normalize_migration_number(version)
+ version = schema_migration.normalize_migration_number(version)
status = db_list.delete(version) ? "up" : "down"
[status, version, (name + scope).humanize]
end.compact
@@ -1153,7 +1153,7 @@ module ActiveRecord
end
def move(direction, steps)
- migrator = Migrator.new(direction, migrations)
+ migrator = Migrator.new(direction, migrations, schema_migration)
if current_version != 0 && !migrator.current_migration
raise UnknownMigrationVersionError.new(current_version)
@@ -1172,27 +1172,28 @@ module ActiveRecord
end
end
- class Migrator #:nodoc:
+ class Migrator # :nodoc:
class << self
attr_accessor :migrations_paths
# For cases where a table doesn't exist like loading from schema cache
def current_version
- MigrationContext.new(migrations_paths).current_version
+ MigrationContext.new(migrations_paths, SchemaMigration).current_version
end
end
self.migrations_paths = ["db/migrate"]
- def initialize(direction, migrations, target_version = nil)
+ def initialize(direction, migrations, schema_migration, target_version = nil)
@direction = direction
@target_version = target_version
@migrated_versions = nil
@migrations = migrations
+ @schema_migration = schema_migration
validate(@migrations)
- ActiveRecord::SchemaMigration.create_table
+ @schema_migration.create_table
ActiveRecord::InternalMetadata.create_table
end
@@ -1246,11 +1247,10 @@ module ActiveRecord
end
def load_migrated
- @migrated_versions = Set.new(Base.connection.migration_context.get_all_versions)
+ @migrated_versions = Set.new(@schema_migration.all_versions.map(&:to_i))
end
private
-
# Used for running a specific migration.
def run_without_lock
migration = migrations.detect { |m| m.version == @target_version }
@@ -1330,10 +1330,10 @@ module ActiveRecord
def record_version_state_after_migrating(version)
if down?
migrated.delete(version)
- ActiveRecord::SchemaMigration.delete_by(version: version.to_s)
+ @schema_migration.delete_by(version: version.to_s)
else
migrated << version
- ActiveRecord::SchemaMigration.create!(version: version.to_s)
+ @schema_migration.create!(version: version.to_s)
end
end
diff --git a/activerecord/lib/active_record/migration/command_recorder.rb b/activerecord/lib/active_record/migration/command_recorder.rb
index efed4b0e26..67172ef395 100644
--- a/activerecord/lib/active_record/migration/command_recorder.rb
+++ b/activerecord/lib/active_record/migration/command_recorder.rb
@@ -118,7 +118,6 @@ module ActiveRecord
end
private
-
module StraightReversions # :nodoc:
private
{
diff --git a/activerecord/lib/active_record/migration/join_table.rb b/activerecord/lib/active_record/migration/join_table.rb
index 9abb289bb0..45169617c1 100644
--- a/activerecord/lib/active_record/migration/join_table.rb
+++ b/activerecord/lib/active_record/migration/join_table.rb
@@ -4,7 +4,6 @@ module ActiveRecord
class Migration
module JoinTable #:nodoc:
private
-
def find_join_table_name(table_1, table_2, options = {})
options.delete(:table_name) || join_table_name(table_1, table_2)
end
diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb
index 55fc58e339..18f19af6be 100644
--- a/activerecord/lib/active_record/model_schema.rb
+++ b/activerecord/lib/active_record/model_schema.rb
@@ -456,13 +456,11 @@ module ActiveRecord
end
protected
-
def initialize_load_schema_monitor
@load_schema_monitor = Monitor.new
end
private
-
def inherited(child_class)
super
child_class.initialize_load_schema_monitor
@@ -484,6 +482,9 @@ module ActiveRecord
end
def load_schema!
+ unless table_name
+ raise ActiveRecord::TableNotSpecified, "#{self} has no table configured. Set one with #{self}.table_name="
+ end
@columns_hash = connection.schema_cache.columns_hash(table_name).except(*ignored_columns)
@columns_hash.each do |name, column|
define_attribute(
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
index 8b9098df6c..ab107742ed 100644
--- a/activerecord/lib/active_record/nested_attributes.rb
+++ b/activerecord/lib/active_record/nested_attributes.rb
@@ -2,7 +2,6 @@
require "active_support/core_ext/hash/except"
require "active_support/core_ext/module/redefine_method"
-require "active_support/core_ext/object/try"
require "active_support/core_ext/hash/indifferent_access"
module ActiveRecord
@@ -354,7 +353,6 @@ module ActiveRecord
end
private
-
# Generates a writer method for this association. Serves as a point for
# accessing the objects in the association. For example, this method
# could generate the following:
@@ -386,7 +384,6 @@ module ActiveRecord
end
private
-
# Attribute hash keys that should not be assigned as normal attributes.
# These hash keys are nested attributes implementation details.
UNASSIGNABLE_KEYS = %w( id _destroy )
diff --git a/activerecord/lib/active_record/null_relation.rb b/activerecord/lib/active_record/null_relation.rb
index cf0de0fdeb..bee5b5f24a 100644
--- a/activerecord/lib/active_record/null_relation.rb
+++ b/activerecord/lib/active_record/null_relation.rb
@@ -60,7 +60,6 @@ module ActiveRecord
end
private
-
def exec_queries
@records = [].freeze
end
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index a58c5fd48a..323b01ab2d 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -865,7 +865,6 @@ module ActiveRecord
end
private
-
# A hook to be overridden by association modules.
def destroy_associations
end
@@ -939,7 +938,7 @@ module ActiveRecord
end
def verify_readonly_attribute(name)
- raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attributes.include?(name)
+ raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attribute?(name)
end
def _raise_record_not_destroyed
diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb
index a1d7c893bf..d5375390c7 100644
--- a/activerecord/lib/active_record/railtie.rb
+++ b/activerecord/lib/active_record/railtie.rb
@@ -134,7 +134,6 @@ end_error
cache = YAML.load(File.read(filename))
if cache.version == current_version
- connection.schema_cache = cache
connection_pool.schema_cache = cache.dup
else
warn "Ignoring db/schema_cache.yml because it has expired. The current schema version is #{current_version}, but the one in the cache is #{cache.version}."
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index e0bc5180c0..4d9acc911b 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -2,6 +2,8 @@
require "active_record"
+databases = ActiveRecord::Tasks::DatabaseTasks.setup_initial_database_yaml
+
db_namespace = namespace :db do
desc "Set the environment value for the database"
task "environment:set" => :load_config do
@@ -23,7 +25,7 @@ db_namespace = namespace :db do
ActiveRecord::Tasks::DatabaseTasks.create_all
end
- ActiveRecord::Tasks::DatabaseTasks.for_each do |spec_name|
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
desc "Create #{spec_name} database for current environment"
task spec_name => :load_config do
db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
@@ -42,7 +44,7 @@ db_namespace = namespace :db do
ActiveRecord::Tasks::DatabaseTasks.drop_all
end
- ActiveRecord::Tasks::DatabaseTasks.for_each do |spec_name|
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
desc "Drop #{spec_name} database for current environment"
task spec_name => [:load_config, :check_protected_environments] do
db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
@@ -101,7 +103,7 @@ db_namespace = namespace :db do
end
namespace :migrate do
- ActiveRecord::Tasks::DatabaseTasks.for_each do |spec_name|
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
desc "Migrate #{spec_name} database for current environment"
task spec_name => :load_config do
db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
@@ -110,7 +112,7 @@ db_namespace = namespace :db do
end
end
- # desc 'Rollbacks the database one migration and re migrate up (options: STEP=x, VERSION=x).'
+ desc "Rolls back the database one migration and re-migrates up (options: STEP=x, VERSION=x)."
task redo: :load_config do
raise "Empty VERSION provided" if ENV["VERSION"] && ENV["VERSION"].empty?
@@ -126,7 +128,7 @@ db_namespace = namespace :db do
# desc 'Resets your database using your migrations for the current environment'
task reset: ["db:drop", "db:create", "db:migrate"]
- # desc 'Runs the "up" for a given migration VERSION.'
+ desc 'Runs the "up" for a given migration VERSION.'
task up: :load_config do
ActiveRecord::Tasks::DatabaseTasks.raise_for_multi_db(command: "db:migrate:up")
@@ -142,7 +144,7 @@ db_namespace = namespace :db do
end
namespace :up do
- ActiveRecord::Tasks::DatabaseTasks.for_each do |spec_name|
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
task spec_name => :load_config do
raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty?
@@ -160,7 +162,7 @@ db_namespace = namespace :db do
end
end
- # desc 'Runs the "down" for a given migration VERSION.'
+ desc 'Runs the "down" for a given migration VERSION.'
task down: :load_config do
ActiveRecord::Tasks::DatabaseTasks.raise_for_multi_db(command: "db:migrate:down")
@@ -176,7 +178,7 @@ db_namespace = namespace :db do
end
namespace :down do
- ActiveRecord::Tasks::DatabaseTasks.for_each do |spec_name|
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
task spec_name => :load_config do
raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty?
@@ -203,7 +205,7 @@ db_namespace = namespace :db do
end
namespace :status do
- ActiveRecord::Tasks::DatabaseTasks.for_each do |spec_name|
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
desc "Display status of migrations for #{spec_name} database"
task spec_name => :load_config do
db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
@@ -228,7 +230,7 @@ db_namespace = namespace :db do
db_namespace["_dump"].invoke
end
- # desc 'Drops and recreates the database from db/schema.rb for the current environment and loads the seeds.'
+ desc "Drops and recreates the database from db/schema.rb for the current environment and loads the seeds."
task reset: [ "db:drop", "db:setup" ]
# desc "Retrieves the charset for the current environment's database"
@@ -250,7 +252,11 @@ db_namespace = namespace :db do
# desc "Raises an error if there are pending migrations"
task abort_if_pending_migrations: :load_config do
- pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations
+ pending_migrations = ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).flat_map do |db_config|
+ ActiveRecord::Base.establish_connection(db_config.config)
+
+ ActiveRecord::Base.connection.migration_context.open.pending_migrations
+ end
if pending_migrations.any?
puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}"
@@ -261,17 +267,57 @@ db_namespace = namespace :db do
end
end
+ namespace :abort_if_pending_migrations do
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
+ # desc "Raises an error if there are pending migrations for #{spec_name} database"
+ task spec_name => :load_config do
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
+ ActiveRecord::Base.establish_connection(db_config.config)
+
+ pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations
+
+ if pending_migrations.any?
+ puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}"
+ pending_migrations.each do |pending_migration|
+ puts " %4d %s" % [pending_migration.version, pending_migration.name]
+ end
+ abort %{Run `rails db:migrate:#{spec_name}` to update your database then try again.}
+ end
+ end
+ end
+ end
+
desc "Creates the database, loads the schema, and initializes with the seed data (use db:reset to also drop the database first)"
task setup: ["db:schema:load_if_ruby", "db:structure:load_if_sql", :seed]
desc "Runs setup if database does not exist, or runs migrations if it does"
task prepare: :load_config do
+ seed = false
+
ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
ActiveRecord::Base.establish_connection(db_config.config)
- db_namespace["migrate"].invoke
+
+ # Skipped when no database
+ ActiveRecord::Tasks::DatabaseTasks.migrate
+ if ActiveRecord::Base.dump_schema_after_migration
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config.config, ActiveRecord::Base.schema_format, db_config.spec_name)
+ end
+
rescue ActiveRecord::NoDatabaseError
- db_namespace["setup"].invoke
+ ActiveRecord::Tasks::DatabaseTasks.create_current(db_config.env_name, db_config.spec_name)
+ ActiveRecord::Tasks::DatabaseTasks.load_schema(
+ db_config.config,
+ ActiveRecord::Base.schema_format,
+ nil,
+ db_config.env_name,
+ db_config.spec_name
+ )
+
+ seed = true
end
+
+ ActiveRecord::Base.establish_connection
+ ActiveRecord::Tasks::DatabaseTasks.load_seed if seed
end
desc "Loads the seed data from db/seeds.rb"
@@ -336,13 +382,9 @@ db_namespace = namespace :db do
namespace :schema do
desc "Creates a db/schema.rb file that is portable against any DB supported by Active Record"
task dump: :load_config do
- require "active_record/schema_dumper"
ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
- filename = ActiveRecord::Tasks::DatabaseTasks.dump_filename(db_config.spec_name, :ruby)
- File.open(filename, "w:utf-8") do |file|
- ActiveRecord::Base.establish_connection(db_config.config)
- ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
- end
+ ActiveRecord::Base.establish_connection(db_config.config)
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config.config, :ruby, db_config.spec_name)
end
db_namespace["schema:dump"].reenable
@@ -385,14 +427,7 @@ db_namespace = namespace :db do
task dump: :load_config do
ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
ActiveRecord::Base.establish_connection(db_config.config)
- filename = ActiveRecord::Tasks::DatabaseTasks.dump_filename(db_config.spec_name, :sql)
- ActiveRecord::Tasks::DatabaseTasks.structure_dump(db_config.config, filename)
- if ActiveRecord::SchemaMigration.table_exists?
- File.open(filename, "a") do |f|
- f.puts ActiveRecord::Base.connection.dump_schema_information
- f.print "\n"
- end
- end
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config.config, :sql, db_config.spec_name)
end
db_namespace["structure:dump"].reenable
diff --git a/activerecord/lib/active_record/readonly_attributes.rb b/activerecord/lib/active_record/readonly_attributes.rb
index 7bc26993d5..c851ed52c3 100644
--- a/activerecord/lib/active_record/readonly_attributes.rb
+++ b/activerecord/lib/active_record/readonly_attributes.rb
@@ -19,6 +19,10 @@ module ActiveRecord
def readonly_attributes
_attr_readonly
end
+
+ def readonly_attribute?(name) # :nodoc:
+ _attr_readonly.include?(name)
+ end
end
end
end
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index eefda2b8f4..cbfa60d4d9 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -590,7 +590,6 @@ module ActiveRecord
end
private
-
def calculate_constructable(macro, options)
true
end
@@ -704,7 +703,6 @@ module ActiveRecord
end
private
-
def calculate_constructable(macro, options)
!options[:through]
end
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index add95f6a0a..ea8f44752b 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -468,7 +468,19 @@ module ActiveRecord
end
end
- def update_counters(counters) # :nodoc:
+ # Updates the counters of the records in the current relation.
+ #
+ # === Parameters
+ #
+ # * +counter+ - A Hash containing the names of the fields to update as keys and the amount to update as values.
+ # * <tt>:touch</tt> option - Touch the timestamp columns when updating.
+ # * If attributes names are passed, they are updated along with update_at/on attributes.
+ #
+ # === Examples
+ #
+ # # For Posts by a given author increment the comment_count by 1.
+ # Post.where(author_id: author.id).update_counters(comment_count: 1)
+ def update_counters(counters)
touch = counters.delete(:touch)
updates = {}
diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb
index 9c579843b1..30b8edd0bd 100644
--- a/activerecord/lib/active_record/relation/batches.rb
+++ b/activerecord/lib/active_record/relation/batches.rb
@@ -258,7 +258,6 @@ module ActiveRecord
end
private
-
def apply_limits(relation, start, finish)
relation = apply_start_limit(relation, start) if start
relation = apply_finish_limit(relation, finish) if finish
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index 0be9ba7d7b..0a14a33c1d 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -340,7 +340,7 @@ module ActiveRecord
}
relation = except(:group).distinct!(false)
- relation.group_values = group_aliases
+ relation.group_values = group_fields
relation.select_values = select_values
calculated_data = skip_query_cache_if_necessary { @klass.connection.select_all(relation.arel, nil) }
diff --git a/activerecord/lib/active_record/relation/delegation.rb b/activerecord/lib/active_record/relation/delegation.rb
index d59331053e..2f61c05eca 100644
--- a/activerecord/lib/active_record/relation/delegation.rb
+++ b/activerecord/lib/active_record/relation/delegation.rb
@@ -99,7 +99,6 @@ module ActiveRecord
end
private
-
def method_missing(method, *args, &block)
if @klass.respond_to?(method)
@klass.generate_relation_method(method)
@@ -116,7 +115,6 @@ module ActiveRecord
end
private
-
def relation_class_for(klass)
klass.relation_delegate_class(self)
end
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 9c7ac80447..1dbf4808fd 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -346,7 +346,6 @@ module ActiveRecord
end
private
-
def offset_index
offset_value || 0
end
@@ -355,7 +354,7 @@ module ActiveRecord
conditions = sanitize_forbidden_attributes(conditions)
if distinct_value && offset_value
- relation = limit(1)
+ relation = except(:order).limit!(1)
else
relation = except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
end
diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb
index 84fe424ef0..e1735c0522 100644
--- a/activerecord/lib/active_record/relation/merger.rb
+++ b/activerecord/lib/active_record/relation/merger.rb
@@ -89,7 +89,6 @@ module ActiveRecord
end
private
-
def merge_preloads
return if other.preload_values.empty? && other.includes_values.empty?
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index b8fd2fce14..6957ba052b 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -138,7 +138,7 @@ module ActiveRecord
end
def includes!(*args) # :nodoc:
- args.reject!(&:blank?)
+ args.compact_blank!
args.flatten!
self.includes_values |= args
@@ -265,7 +265,7 @@ module ActiveRecord
end
def _select!(*fields) # :nodoc:
- fields.reject!(&:blank?)
+ fields.compact_blank!
fields.flatten!
self.select_values += fields
self
@@ -952,7 +952,7 @@ module ActiveRecord
def optimizer_hints!(*args) # :nodoc:
args.flatten!
- self.optimizer_hints_values += args
+ self.optimizer_hints_values |= args
self
end
@@ -965,7 +965,7 @@ module ActiveRecord
def reverse_order! # :nodoc:
orders = order_values.uniq
- orders.reject!(&:blank?)
+ orders.compact_blank!
self.order_values = reverse_sql_order(orders)
self
end
@@ -1053,7 +1053,7 @@ module ActiveRecord
)
arel.skip(Arel::Nodes::BindParam.new(offset_attribute))
end
- arel.group(*arel_columns(group_values.uniq.reject(&:blank?))) unless group_values.empty?
+ arel.group(*arel_columns(group_values.uniq.compact_blank)) unless group_values.empty?
build_order(arel)
@@ -1128,27 +1128,21 @@ module ActiveRecord
association_joins = buckets[:association_join]
stashed_joins = buckets[:stashed_join]
- join_nodes = buckets[:join_node].uniq
- string_joins = buckets[:string_join].map(&:strip).uniq
+ join_nodes = buckets[:join_node].tap(&:uniq!)
+ string_joins = buckets[:string_join].compact_blank!.map!(&:strip).tap(&:uniq!)
- join_list = join_nodes + convert_join_strings_to_ast(string_joins)
- alias_tracker = alias_tracker(join_list, aliases)
+ string_joins.map! { |join| table.create_string_join(Arel.sql(join)) }
- join_dependency = construct_join_dependency(association_joins, join_type)
+ join_sources = manager.join_sources
+ join_sources.concat(join_nodes) unless join_nodes.empty?
- joins = join_dependency.join_constraints(stashed_joins, alias_tracker)
- joins.each { |join| manager.from(join) }
-
- manager.join_sources.concat(join_list)
-
- alias_tracker.aliases
- end
+ unless association_joins.empty? && stashed_joins.empty?
+ alias_tracker = alias_tracker(join_nodes + string_joins, aliases)
+ join_dependency = construct_join_dependency(association_joins, join_type)
+ join_sources.concat(join_dependency.join_constraints(stashed_joins, alias_tracker))
+ end
- def convert_join_strings_to_ast(joins)
- joins
- .flatten
- .reject(&:blank?)
- .map { |join| table.create_string_join(Arel.sql(join)) }
+ join_sources.concat(string_joins) unless string_joins.empty?
end
def build_select(arel)
@@ -1165,8 +1159,9 @@ module ActiveRecord
columns.flat_map do |field|
case field
when Symbol
- field = field.to_s
- arel_column(field, &connection.method(:quote_table_name))
+ arel_column(field.to_s) do |attr_name|
+ connection.quote_table_name(attr_name)
+ end
when String
arel_column(field, &:itself)
when Proc
@@ -1232,7 +1227,7 @@ module ActiveRecord
def build_order(arel)
orders = order_values.uniq
- orders.reject!(&:blank?)
+ orders.compact_blank!
arel.order(*orders) unless orders.empty?
end
@@ -1253,6 +1248,7 @@ module ActiveRecord
end
def preprocess_order_args(order_args)
+ order_args.reject!(&:blank?)
order_args.map! do |arg|
klass.sanitize_sql_for_order(arg)
end
@@ -1260,7 +1256,7 @@ module ActiveRecord
@klass.disallow_raw_sql!(
order_args.flat_map { |a| a.is_a?(Hash) ? a.keys : a },
- permit: AttributeMethods::ClassMethods::COLUMN_NAME_WITH_ORDER
+ permit: connection.column_name_with_order_matcher
)
validate_order_args(order_args)
@@ -1273,20 +1269,14 @@ module ActiveRecord
order_args.map! do |arg|
case arg
when Symbol
- arg = arg.to_s
- arel_column(arg) {
- Arel.sql(connection.quote_table_name(arg))
- }.asc
+ order_column(arg.to_s).asc
when Hash
arg.map { |field, dir|
case field
when Arel::Nodes::SqlLiteral
field.send(dir.downcase)
else
- field = field.to_s
- arel_column(field) {
- Arel.sql(connection.quote_table_name(field))
- }.send(dir.downcase)
+ order_column(field.to_s).send(dir.downcase)
end
}
else
@@ -1295,6 +1285,16 @@ module ActiveRecord
end.flatten!
end
+ def order_column(field)
+ arel_column(field) do |attr_name|
+ if attr_name == "count" && !group_values.empty?
+ arel_attribute(attr_name)
+ else
+ Arel.sql(connection.quote_table_name(attr_name))
+ end
+ end
+ end
+
# Checks to make sure that the arguments are not blank. Note that if some
# blank-like object were initially passed into the query method, then this
# method will not raise an error.
diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb
index efc4b447aa..3f6dd50139 100644
--- a/activerecord/lib/active_record/relation/spawn_methods.rb
+++ b/activerecord/lib/active_record/relation/spawn_methods.rb
@@ -67,7 +67,6 @@ module ActiveRecord
end
private
-
def relation_with(values)
result = Relation.create(klass, values: values)
result.extend(*extending_values) if extending_values.any?
diff --git a/activerecord/lib/active_record/relation/where_clause.rb b/activerecord/lib/active_record/relation/where_clause.rb
index b91b135867..8fae380b0a 100644
--- a/activerecord/lib/active_record/relation/where_clause.rb
+++ b/activerecord/lib/active_record/relation/where_clause.rb
@@ -87,7 +87,6 @@ module ActiveRecord
end
protected
-
attr_reader :predicates
def referenced_columns
diff --git a/activerecord/lib/active_record/result.rb b/activerecord/lib/active_record/result.rb
index da6d10b6ec..3b615f29a3 100644
--- a/activerecord/lib/active_record/result.rb
+++ b/activerecord/lib/active_record/result.rb
@@ -132,7 +132,6 @@ module ActiveRecord
end
private
-
def column_type(name, type_overrides = {})
type_overrides.fetch(name) do
column_types.fetch(name, Type.default_value)
diff --git a/activerecord/lib/active_record/sanitization.rb b/activerecord/lib/active_record/sanitization.rb
index 750766714d..b16cbb0f84 100644
--- a/activerecord/lib/active_record/sanitization.rb
+++ b/activerecord/lib/active_record/sanitization.rb
@@ -61,8 +61,9 @@ module ActiveRecord
# # => "id ASC"
def sanitize_sql_for_order(condition)
if condition.is_a?(Array) && condition.first.to_s.include?("?")
- disallow_raw_sql!([condition.first],
- permit: AttributeMethods::ClassMethods::COLUMN_NAME_WITH_ORDER
+ disallow_raw_sql!(
+ [condition.first],
+ permit: connection.column_name_with_order_matcher
)
# Ensure we aren't dealing with a subclass of String that might
@@ -133,6 +134,33 @@ module ActiveRecord
end
end
+ def disallow_raw_sql!(args, permit: connection.column_name_matcher) # :nodoc:
+ unexpected = nil
+ args.each do |arg|
+ next if arg.is_a?(Symbol) || Arel.arel_node?(arg) || permit.match?(arg.to_s)
+ (unexpected ||= []) << arg
+ end
+
+ return unless unexpected
+
+ if allow_unsafe_raw_sql == :deprecated
+ ActiveSupport::Deprecation.warn(
+ "Dangerous query method (method whose arguments are used as raw " \
+ "SQL) called with non-attribute argument(s): " \
+ "#{unexpected.map(&:inspect).join(", ")}. Non-attribute " \
+ "arguments will be disallowed in Rails 6.1. This method should " \
+ "not be called with user-provided values, such as request " \
+ "parameters or model attributes. Known-safe values can be passed " \
+ "by wrapping them in Arel.sql()."
+ )
+ else
+ raise(ActiveRecord::UnknownAttributeReference,
+ "Query method called with non-attribute argument(s): " +
+ unexpected.map(&:inspect).join(", ")
+ )
+ end
+ end
+
private
def replace_bind_variables(statement, values)
raise_if_bind_arity_mismatch(statement, statement.count("?"), values.size)
diff --git a/activerecord/lib/active_record/schema.rb b/activerecord/lib/active_record/schema.rb
index 76bf53387d..aba25fb375 100644
--- a/activerecord/lib/active_record/schema.rb
+++ b/activerecord/lib/active_record/schema.rb
@@ -50,7 +50,7 @@ module ActiveRecord
instance_eval(&block)
if info[:version].present?
- ActiveRecord::SchemaMigration.create_table
+ connection.schema_migration.create_table
connection.assume_migrated_upto_version(info[:version])
end
diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb
index 2f7cc07221..f4b1f536b3 100644
--- a/activerecord/lib/active_record/schema_dumper.rb
+++ b/activerecord/lib/active_record/schema_dumper.rb
@@ -146,7 +146,11 @@ HEADER
raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type)
next if column.name == pk
type, colspec = column_spec(column)
- tbl.print " t.#{type} #{column.name.inspect}"
+ if type.is_a?(Symbol)
+ tbl.print " t.#{type} #{column.name.inspect}"
+ else
+ tbl.print " t.column #{column.name.inspect}, #{type.inspect}"
+ end
tbl.print ", #{format_colspec(colspec)}" if colspec.present?
tbl.puts
end
diff --git a/activerecord/lib/active_record/schema_migration.rb b/activerecord/lib/active_record/schema_migration.rb
index 74547de862..dec7fee986 100644
--- a/activerecord/lib/active_record/schema_migration.rb
+++ b/activerecord/lib/active_record/schema_migration.rb
@@ -22,10 +22,6 @@ module ActiveRecord
"#{table_name_prefix}#{schema_migrations_table_name}#{table_name_suffix}"
end
- def table_exists?
- connection.table_exists?(table_name)
- end
-
def create_table
unless table_exists?
version_options = connection.internal_string_options_for_primary_key
diff --git a/activerecord/lib/active_record/scoping.rb b/activerecord/lib/active_record/scoping.rb
index 35e9dcbffc..62c7988bd8 100644
--- a/activerecord/lib/active_record/scoping.rb
+++ b/activerecord/lib/active_record/scoping.rb
@@ -95,7 +95,6 @@ module ActiveRecord
end
private
-
def raise_invalid_scope_type!(scope_type)
if !VALID_SCOPE_TYPES.include?(scope_type)
raise ArgumentError, "Invalid scope type '#{scope_type}' sent to the registry. Scope types must be included in VALID_SCOPE_TYPES"
diff --git a/activerecord/lib/active_record/scoping/default.rb b/activerecord/lib/active_record/scoping/default.rb
index 87bcfd5181..151eef362b 100644
--- a/activerecord/lib/active_record/scoping/default.rb
+++ b/activerecord/lib/active_record/scoping/default.rb
@@ -44,7 +44,6 @@ module ActiveRecord
end
private
-
# Use this macro in your model to set a default scope for all operations on
# the model.
#
diff --git a/activerecord/lib/active_record/scoping/named.rb b/activerecord/lib/active_record/scoping/named.rb
index cd9801b7a0..7baef99e83 100644
--- a/activerecord/lib/active_record/scoping/named.rb
+++ b/activerecord/lib/active_record/scoping/named.rb
@@ -204,7 +204,6 @@ module ActiveRecord
end
private
-
def valid_scope_name?(name)
if respond_to?(name, true) && logger
logger.warn "Creating scope :#{name}. " \
diff --git a/activerecord/lib/active_record/table_metadata.rb b/activerecord/lib/active_record/table_metadata.rb
index 073866b894..9a1176db6a 100644
--- a/activerecord/lib/active_record/table_metadata.rb
+++ b/activerecord/lib/active_record/table_metadata.rb
@@ -4,8 +4,9 @@ module ActiveRecord
class TableMetadata # :nodoc:
delegate :foreign_type, :foreign_key, :join_primary_key, :join_foreign_key, to: :association, prefix: true
- def initialize(klass, arel_table, association = nil)
+ def initialize(klass, arel_table, association = nil, types = klass)
@klass = klass
+ @types = types
@arel_table = arel_table
@association = association
end
@@ -29,11 +30,7 @@ module ActiveRecord
end
def type(column_name)
- if klass
- klass.type_for_attribute(column_name)
- else
- Type.default_value
- end
+ types.type_for_attribute(column_name)
end
def has_column?(column_name)
@@ -52,13 +49,12 @@ module ActiveRecord
elsif association && !association.polymorphic?
association_klass = association.klass
arel_table = association_klass.arel_table.alias(table_name)
+ TableMetadata.new(association_klass, arel_table, association)
else
type_caster = TypeCaster::Connection.new(klass, table_name)
- association_klass = nil
arel_table = Arel::Table.new(table_name, type_caster: type_caster)
+ TableMetadata.new(nil, arel_table, association, type_caster)
end
-
- TableMetadata.new(association_klass, arel_table, association)
end
def polymorphic_association?
@@ -74,6 +70,6 @@ module ActiveRecord
end
private
- attr_reader :klass, :arel_table, :association
+ attr_reader :klass, :types, :arel_table, :association
end
end
diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb
index c79ed8db60..5d1ce19829 100644
--- a/activerecord/lib/active_record/tasks/database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/database_tasks.rb
@@ -141,10 +141,21 @@ module ActiveRecord
end
end
- def for_each
+ def setup_initial_database_yaml
+ return {} unless defined?(Rails)
+
+ begin
+ Rails.application.config.load_database_yaml
+ rescue
+ $stderr.puts "Rails couldn't infer whether you are using multiple databases from your database.yml and can't generate the tasks for the non-primary databases. If you'd like to use this feature, please simplify your ERB."
+
+ {}
+ end
+ end
+
+ def for_each(databases)
return {} unless defined?(Rails)
- databases = Rails.application.config.load_database_yaml
database_configs = ActiveRecord::DatabaseConfigurations.new(databases).configs_for(env_name: Rails.env)
# if this is a single database application we don't want tasks for each primary database
@@ -169,8 +180,8 @@ module ActiveRecord
end
end
- def create_current(environment = env)
- each_current_configuration(environment) { |configuration|
+ def create_current(environment = env, spec_name = nil)
+ each_current_configuration(environment, spec_name) { |configuration|
create configuration
}
ActiveRecord::Base.establish_connection(environment.to_sym)
@@ -200,9 +211,10 @@ module ActiveRecord
def truncate_tables(configuration)
ActiveRecord::Base.connected_to(database: { truncation: configuration }) do
- table_names = ActiveRecord::Base.connection.tables
+ conn = ActiveRecord::Base.connection
+ table_names = conn.tables
table_names -= [
- SchemaMigration.table_name,
+ conn.schema_migration.table_name,
InternalMetadata.table_name
]
@@ -233,7 +245,7 @@ module ActiveRecord
end
def migrate_status
- unless ActiveRecord::SchemaMigration.table_exists?
+ unless ActiveRecord::Base.connection.schema_migration.table_exists?
Kernel.abort "Schema migrations table does not exist yet."
end
@@ -325,6 +337,27 @@ module ActiveRecord
Migration.verbose = verbose_was
end
+ def dump_schema(configuration, format = ActiveRecord::Base.schema_format, spec_name = "primary") # :nodoc:
+ require "active_record/schema_dumper"
+ filename = dump_filename(spec_name, format)
+ connection = ActiveRecord::Base.connection
+
+ case format
+ when :ruby
+ File.open(filename, "w:utf-8") do |file|
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
+ end
+ when :sql
+ structure_dump(configuration, filename)
+ if connection.schema_migration.table_exists?
+ File.open(filename, "a") do |f|
+ f.puts connection.dump_schema_information
+ f.print "\n"
+ end
+ end
+ end
+ end
+
def schema_file(format = ActiveRecord::Base.schema_format)
File.join(db_dir, schema_file_type(format))
end
@@ -406,12 +439,14 @@ module ActiveRecord
task.is_a?(String) ? task.constantize : task
end
- def each_current_configuration(environment)
+ def each_current_configuration(environment, spec_name = nil)
environments = [environment]
environments << "test" if environment == "development"
environments.each do |env|
ActiveRecord::Base.configurations.configs_for(env_name: env).each do |db_config|
+ next if spec_name && spec_name != db_config.spec_name
+
yield db_config.config, db_config.spec_name, env
end
end
diff --git a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
index 1c1b29b5e1..e3efeb75b5 100644
--- a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
@@ -3,6 +3,8 @@
module ActiveRecord
module Tasks # :nodoc:
class MySQLDatabaseTasks # :nodoc:
+ ER_DB_CREATE_EXISTS = 1007
+
delegate :connection, :establish_connection, to: ActiveRecord::Base
def initialize(configuration)
@@ -14,7 +16,7 @@ module ActiveRecord
connection.create_database configuration["database"], creation_options
establish_connection configuration
rescue ActiveRecord::StatementInvalid => error
- if error.message.include?("database exists")
+ if connection.error_number(error.cause) == ER_DB_CREATE_EXISTS
raise DatabaseAlreadyExists
else
raise
@@ -67,7 +69,6 @@ module ActiveRecord
end
private
-
attr_reader :configuration
def configuration_without_database
diff --git a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
index 8acb11f75f..626ffdfdf9 100644
--- a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
@@ -89,7 +89,6 @@ module ActiveRecord
end
private
-
attr_reader :configuration
def encoding
diff --git a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb
index a82cea80ca..f67a3498b6 100644
--- a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb
@@ -59,7 +59,6 @@ module ActiveRecord
end
private
-
attr_reader :configuration, :root
def run_cmd(cmd, args, out)
diff --git a/activerecord/lib/active_record/test_fixtures.rb b/activerecord/lib/active_record/test_fixtures.rb
index 8c60d71669..1d6fef1eb9 100644
--- a/activerecord/lib/active_record/test_fixtures.rb
+++ b/activerecord/lib/active_record/test_fixtures.rb
@@ -179,7 +179,6 @@ module ActiveRecord
end
private
-
# Shares the writing connection pool with connections on
# other handlers.
#
diff --git a/activerecord/lib/active_record/timestamp.rb b/activerecord/lib/active_record/timestamp.rb
index 04a1c03474..c883d368b5 100644
--- a/activerecord/lib/active_record/timestamp.rb
+++ b/activerecord/lib/active_record/timestamp.rb
@@ -59,19 +59,26 @@ module ActiveRecord
attribute_names.index_with(time || current_time_from_proper_timezone)
end
- private
- def timestamp_attributes_for_create_in_model
- timestamp_attributes_for_create.select { |c| column_names.include?(c) }
- end
+ def timestamp_attributes_for_create_in_model
+ @timestamp_attributes_for_create_in_model ||=
+ (timestamp_attributes_for_create & column_names).freeze
+ end
- def timestamp_attributes_for_update_in_model
- timestamp_attributes_for_update.select { |c| column_names.include?(c) }
- end
+ def timestamp_attributes_for_update_in_model
+ @timestamp_attributes_for_update_in_model ||=
+ (timestamp_attributes_for_update & column_names).freeze
+ end
- def all_timestamp_attributes_in_model
- timestamp_attributes_for_create_in_model + timestamp_attributes_for_update_in_model
- end
+ def all_timestamp_attributes_in_model
+ @all_timestamp_attributes_in_model ||=
+ (timestamp_attributes_for_create_in_model + timestamp_attributes_for_update_in_model).freeze
+ end
+
+ def current_time_from_proper_timezone
+ default_timezone == :utc ? Time.now.utc : Time.now
+ end
+ private
def timestamp_attributes_for_create
["created_at", "created_on"]
end
@@ -80,13 +87,15 @@ module ActiveRecord
["updated_at", "updated_on"]
end
- def current_time_from_proper_timezone
- default_timezone == :utc ? Time.now.utc : Time.now
+ def reload_schema_from_cache
+ @timestamp_attributes_for_create_in_model = nil
+ @timestamp_attributes_for_update_in_model = nil
+ @all_timestamp_attributes_in_model = nil
+ super
end
end
private
-
def _create_record
if record_timestamps
current_time = current_time_from_proper_timezone
@@ -124,19 +133,19 @@ module ActiveRecord
end
def timestamp_attributes_for_create_in_model
- self.class.send(:timestamp_attributes_for_create_in_model)
+ self.class.timestamp_attributes_for_create_in_model
end
def timestamp_attributes_for_update_in_model
- self.class.send(:timestamp_attributes_for_update_in_model)
+ self.class.timestamp_attributes_for_update_in_model
end
def all_timestamp_attributes_in_model
- self.class.send(:all_timestamp_attributes_in_model)
+ self.class.all_timestamp_attributes_in_model
end
def current_time_from_proper_timezone
- self.class.send(:current_time_from_proper_timezone)
+ self.class.current_time_from_proper_timezone
end
def max_updated_column_timestamp
diff --git a/activerecord/lib/active_record/touch_later.rb b/activerecord/lib/active_record/touch_later.rb
index b60cc96165..3981bd46ad 100644
--- a/activerecord/lib/active_record/touch_later.rb
+++ b/activerecord/lib/active_record/touch_later.rb
@@ -18,6 +18,7 @@ module ActiveRecord
surreptitiously_touch @_defer_touch_attrs
add_to_transaction
+ @_new_record_before_last_commit ||= false
# touch the parents as we are not calling the after_save callbacks
self.class.reflect_on_all_associations(:belongs_to).each do |r|
@@ -35,7 +36,6 @@ module ActiveRecord
end
private
-
def surreptitiously_touch(attrs)
attrs.each { |attr| write_attribute attr, @_touch_time }
clear_attribute_changes attrs
@@ -43,6 +43,7 @@ module ActiveRecord
def touch_deferred_attributes
if has_defer_touch_attrs? && persisted?
+ @_skip_dirty_tracking = true
touch(*@_defer_touch_attrs, time: @_touch_time)
@_defer_touch_attrs, @_touch_time = nil, nil
end
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb
index 9e03deede7..5113e08e8e 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -164,12 +164,12 @@ module ActiveRecord
# end
# end
#
- # only "Kotori" is created. This works on MySQL and PostgreSQL. SQLite3 version >= '3.6.8' also supports it.
+ # only "Kotori" is created.
#
# Most databases don't support true nested transactions. At the time of
# writing, the only database that we're aware of that supports true nested
# transactions, is MS-SQL. Because of this, Active Record emulates nested
- # transactions by using savepoints on MySQL and PostgreSQL. See
+ # transactions by using savepoints. See
# https://dev.mysql.com/doc/refman/5.7/en/savepoint.html
# for more information about savepoints.
#
@@ -282,7 +282,6 @@ module ActiveRecord
end
private
-
def set_options_for_callbacks!(args, enforced_options = {})
options = args.extract_options!.merge!(enforced_options)
args << options
@@ -333,7 +332,7 @@ module ActiveRecord
# Ensure that it is not called if the object was never persisted (failed create),
# but call it after the commit of a destroyed object.
def committed!(should_run_callbacks: true) #:nodoc:
- if should_run_callbacks && trigger_transactional_callbacks?
+ if should_run_callbacks
@_committed_already_called = true
_run_commit_without_transaction_enrollment_callbacks
_run_commit_callbacks
@@ -346,7 +345,7 @@ module ActiveRecord
# Call the #after_rollback callbacks. The +force_restore_state+ argument indicates if the record
# state should be rolled back to the beginning or just to the last savepoint.
def rolledback!(force_restore_state: false, should_run_callbacks: true) #:nodoc:
- if should_run_callbacks && trigger_transactional_callbacks?
+ if should_run_callbacks
_run_rollback_callbacks
_run_rollback_without_transaction_enrollment_callbacks
end
@@ -378,6 +377,11 @@ module ActiveRecord
status
end
+ def trigger_transactional_callbacks? # :nodoc:
+ (@_new_record_before_last_commit || _trigger_update_callback) && persisted? ||
+ _trigger_destroy_callback && destroyed?
+ end
+
private
attr_reader :_committed_already_called, :_trigger_update_callback, :_trigger_destroy_callback
@@ -392,10 +396,7 @@ module ActiveRecord
level: 0
}
@_start_transaction_state[:level] += 1
- remember_new_record_before_last_commit
- end
- def remember_new_record_before_last_commit
if _committed_already_called
@_new_record_before_last_commit = false
else
@@ -457,10 +458,6 @@ module ActiveRecord
self.class.connection.add_transaction_record(self)
end
- def trigger_transactional_callbacks?
- @_new_record_before_last_commit && !new_record? || _trigger_update_callback || _trigger_destroy_callback
- end
-
def has_transactional_callbacks?
!_rollback_callbacks.empty? || !_commit_callbacks.empty? || !_before_commit_callbacks.empty?
end
diff --git a/activerecord/lib/active_record/type.rb b/activerecord/lib/active_record/type.rb
index 03d00006b7..4c1ef1a7e4 100644
--- a/activerecord/lib/active_record/type.rb
+++ b/activerecord/lib/active_record/type.rb
@@ -47,7 +47,6 @@ module ActiveRecord
end
private
-
def current_adapter_name
ActiveRecord::Base.connection.adapter_name.downcase.to_sym
end
diff --git a/activerecord/lib/active_record/type/adapter_specific_registry.rb b/activerecord/lib/active_record/type/adapter_specific_registry.rb
index b300fdfa05..c8c16635b1 100644
--- a/activerecord/lib/active_record/type/adapter_specific_registry.rb
+++ b/activerecord/lib/active_record/type/adapter_specific_registry.rb
@@ -11,7 +11,6 @@ module ActiveRecord
end
private
-
def registration_klass
Registration
end
@@ -53,7 +52,6 @@ module ActiveRecord
end
protected
-
attr_reader :name, :block, :adapter, :override
def priority
@@ -72,7 +70,6 @@ module ActiveRecord
end
private
-
def matches_adapter?(adapter: nil, **)
(self.adapter.nil? || adapter == self.adapter)
end
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 db9853fbcc..b260464df5 100644
--- a/activerecord/lib/active_record/type/hash_lookup_type_map.rb
+++ b/activerecord/lib/active_record/type/hash_lookup_type_map.rb
@@ -16,7 +16,6 @@ module ActiveRecord
end
private
-
def perform_fetch(type, *args, &block)
@mapping.fetch(type, block).call(type, *args)
end
diff --git a/activerecord/lib/active_record/type/serialized.rb b/activerecord/lib/active_record/type/serialized.rb
index 0a2f6cb9fb..a34b2fe702 100644
--- a/activerecord/lib/active_record/type/serialized.rb
+++ b/activerecord/lib/active_record/type/serialized.rb
@@ -56,7 +56,6 @@ module ActiveRecord
end
private
-
def default_value?(value)
value == coder.load(nil)
end
diff --git a/activerecord/lib/active_record/type/type_map.rb b/activerecord/lib/active_record/type/type_map.rb
index fc40b460f0..58f25ba075 100644
--- a/activerecord/lib/active_record/type/type_map.rb
+++ b/activerecord/lib/active_record/type/type_map.rb
@@ -45,7 +45,6 @@ module ActiveRecord
end
private
-
def perform_fetch(lookup_key, *args)
matching_pair = @mapping.reverse_each.detect do |key, _|
key === lookup_key
diff --git a/activerecord/lib/active_record/type/unsigned_integer.rb b/activerecord/lib/active_record/type/unsigned_integer.rb
index 4619528f81..535369e630 100644
--- a/activerecord/lib/active_record/type/unsigned_integer.rb
+++ b/activerecord/lib/active_record/type/unsigned_integer.rb
@@ -4,7 +4,6 @@ module ActiveRecord
module Type
class UnsignedInteger < ActiveModel::Type::Integer # :nodoc:
private
-
def max_value
super * 2
end
diff --git a/activerecord/lib/active_record/type_caster/connection.rb b/activerecord/lib/active_record/type_caster/connection.rb
index 7cf8181d8e..f43559f4cb 100644
--- a/activerecord/lib/active_record/type_caster/connection.rb
+++ b/activerecord/lib/active_record/type_caster/connection.rb
@@ -8,21 +8,27 @@ module ActiveRecord
@table_name = table_name
end
- def type_cast_for_database(attribute_name, value)
+ def type_cast_for_database(attr_name, value)
return value if value.is_a?(Arel::Nodes::BindParam)
- column = column_for(attribute_name)
- connection.type_cast_from_column(column, value)
+ type = type_for_attribute(attr_name)
+ type.serialize(value)
end
- private
- attr_reader :table_name
- delegate :connection, to: :@klass
+ def type_for_attribute(attr_name)
+ schema_cache = connection.schema_cache
- def column_for(attribute_name)
- if connection.schema_cache.data_source_exists?(table_name)
- connection.schema_cache.columns_hash(table_name)[attribute_name.to_s]
- end
+ if schema_cache.data_source_exists?(table_name)
+ column = schema_cache.columns_hash(table_name)[attr_name.to_s]
+ type = connection.lookup_cast_type_from_column(column) if column
end
+
+ type || Type.default_value
+ end
+
+ delegate :connection, to: :@klass, private: true
+
+ private
+ attr_reader :table_name
end
end
end
diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb
index ca27a3f0ab..23e8d53168 100644
--- a/activerecord/lib/active_record/validations.rb
+++ b/activerecord/lib/active_record/validations.rb
@@ -71,7 +71,6 @@ module ActiveRecord
alias_method :validate, :valid?
private
-
def default_validation_context
new_record? ? :create : :update
end
diff --git a/activerecord/lib/active_record/validations/associated.rb b/activerecord/lib/active_record/validations/associated.rb
index 3538aeec22..dc89df4be7 100644
--- a/activerecord/lib/active_record/validations/associated.rb
+++ b/activerecord/lib/active_record/validations/associated.rb
@@ -10,7 +10,6 @@ module ActiveRecord
end
private
-
def valid_object?(record)
(record.respond_to?(:marked_for_destruction?) && record.marked_for_destruction?) || record.valid?
end
diff --git a/activerecord/lib/arel.rb b/activerecord/lib/arel.rb
index 361cd915cc..0fc07e1ede 100644
--- a/activerecord/lib/arel.rb
+++ b/activerecord/lib/arel.rb
@@ -12,7 +12,7 @@ require "arel/math"
require "arel/alias_predication"
require "arel/order_predications"
require "arel/table"
-require "arel/attributes"
+require "arel/attributes/attribute"
require "arel/visitors"
require "arel/collectors/sql_string"
diff --git a/activerecord/lib/arel/attributes.rb b/activerecord/lib/arel/attributes.rb
deleted file mode 100644
index 35d586c948..0000000000
--- a/activerecord/lib/arel/attributes.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# frozen_string_literal: true
-
-require "arel/attributes/attribute"
-
-module Arel # :nodoc: all
- module Attributes
- ###
- # Factory method to wrap a raw database +column+ to an Arel Attribute.
- def self.for(column)
- case column.type
- when :string, :text, :binary then String
- when :integer then Integer
- when :float then Float
- when :decimal then Decimal
- when :date, :datetime, :timestamp, :time then Time
- when :boolean then Boolean
- else
- Undefined
- end
- end
- end
-end
diff --git a/activerecord/lib/arel/nodes/node.rb b/activerecord/lib/arel/nodes/node.rb
index 8086102bde..0416ff58de 100644
--- a/activerecord/lib/arel/nodes/node.rb
+++ b/activerecord/lib/arel/nodes/node.rb
@@ -6,7 +6,6 @@ module Arel # :nodoc: all
# Abstract base class for all AST nodes
class Node
include Arel::FactoryMethods
- include Enumerable
###
# Factory method to create a Nodes::Not node that has the recipient of
@@ -38,13 +37,6 @@ module Arel # :nodoc: all
collector = engine.connection.visitor.accept self, collector
collector.value
end
-
- # Iterate through AST, nodes will be yielded depth-first
- def each(&block)
- return enum_for(:each) unless block_given?
-
- ::Arel::Visitors::DepthFirst.new(block).accept self
- end
end
end
end
diff --git a/activerecord/lib/arel/predications.rb b/activerecord/lib/arel/predications.rb
index 7dafde4952..895d394363 100644
--- a/activerecord/lib/arel/predications.rb
+++ b/activerecord/lib/arel/predications.rb
@@ -37,7 +37,7 @@ module Arel # :nodoc: all
def between(other)
if unboundable?(other.begin) == 1 || unboundable?(other.end) == -1
self.in([])
- elsif open_ended?(other.begin)
+ elsif other.begin.nil? || open_ended?(other.begin)
if other.end.nil? || open_ended?(other.end)
not_in([])
elsif other.exclude_end?
@@ -85,7 +85,7 @@ Passing a range to `#in` is deprecated. Call `#between`, instead.
def not_between(other)
if unboundable?(other.begin) == 1 || unboundable?(other.end) == -1
not_in([])
- elsif open_ended?(other.begin)
+ elsif other.begin.nil? || open_ended?(other.begin)
if other.end.nil? || open_ended?(other.end)
self.in([])
elsif other.exclude_end?
@@ -221,7 +221,6 @@ Passing a range to `#not_in` is deprecated. Call `#not_between`, instead.
end
private
-
def grouping_any(method_id, others, *extras)
nodes = others.map { |expr| send(method_id, expr, *extras) }
Nodes::Grouping.new nodes.inject { |memo, node|
diff --git a/activerecord/lib/arel/visitors.rb b/activerecord/lib/arel/visitors.rb
index e350f52e65..a1097f6750 100644
--- a/activerecord/lib/arel/visitors.rb
+++ b/activerecord/lib/arel/visitors.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require "arel/visitors/visitor"
-require "arel/visitors/depth_first"
require "arel/visitors/to_sql"
require "arel/visitors/sqlite"
require "arel/visitors/postgresql"
diff --git a/activerecord/lib/arel/visitors/depth_first.rb b/activerecord/lib/arel/visitors/depth_first.rb
deleted file mode 100644
index d696edc507..0000000000
--- a/activerecord/lib/arel/visitors/depth_first.rb
+++ /dev/null
@@ -1,204 +0,0 @@
-# frozen_string_literal: true
-
-module Arel # :nodoc: all
- module Visitors
- class DepthFirst < Arel::Visitors::Visitor
- def initialize(block = nil)
- @block = block || Proc.new
- super()
- end
-
- private
-
- def visit(o)
- super
- @block.call o
- end
-
- def unary(o)
- visit o.expr
- end
- alias :visit_Arel_Nodes_Else :unary
- alias :visit_Arel_Nodes_Group :unary
- alias :visit_Arel_Nodes_Cube :unary
- alias :visit_Arel_Nodes_RollUp :unary
- alias :visit_Arel_Nodes_GroupingSet :unary
- alias :visit_Arel_Nodes_GroupingElement :unary
- alias :visit_Arel_Nodes_Grouping :unary
- alias :visit_Arel_Nodes_Having :unary
- alias :visit_Arel_Nodes_Lateral :unary
- alias :visit_Arel_Nodes_Limit :unary
- alias :visit_Arel_Nodes_Not :unary
- alias :visit_Arel_Nodes_Offset :unary
- alias :visit_Arel_Nodes_On :unary
- alias :visit_Arel_Nodes_Ordering :unary
- alias :visit_Arel_Nodes_Ascending :unary
- alias :visit_Arel_Nodes_Descending :unary
- alias :visit_Arel_Nodes_UnqualifiedColumn :unary
- alias :visit_Arel_Nodes_OptimizerHints :unary
- alias :visit_Arel_Nodes_ValuesList :unary
-
- def function(o)
- visit o.expressions
- visit o.alias
- visit o.distinct
- end
- alias :visit_Arel_Nodes_Avg :function
- alias :visit_Arel_Nodes_Exists :function
- alias :visit_Arel_Nodes_Max :function
- alias :visit_Arel_Nodes_Min :function
- alias :visit_Arel_Nodes_Sum :function
-
- def visit_Arel_Nodes_NamedFunction(o)
- visit o.name
- visit o.expressions
- visit o.distinct
- visit o.alias
- end
-
- def visit_Arel_Nodes_Count(o)
- visit o.expressions
- visit o.alias
- visit o.distinct
- end
-
- def visit_Arel_Nodes_Case(o)
- visit o.case
- visit o.conditions
- visit o.default
- end
-
- def nary(o)
- o.children.each { |child| visit child }
- end
- alias :visit_Arel_Nodes_And :nary
-
- def binary(o)
- visit o.left
- visit o.right
- end
- alias :visit_Arel_Nodes_As :binary
- alias :visit_Arel_Nodes_Assignment :binary
- alias :visit_Arel_Nodes_Between :binary
- alias :visit_Arel_Nodes_Concat :binary
- alias :visit_Arel_Nodes_DeleteStatement :binary
- alias :visit_Arel_Nodes_DoesNotMatch :binary
- alias :visit_Arel_Nodes_Equality :binary
- alias :visit_Arel_Nodes_FullOuterJoin :binary
- alias :visit_Arel_Nodes_GreaterThan :binary
- alias :visit_Arel_Nodes_GreaterThanOrEqual :binary
- alias :visit_Arel_Nodes_In :binary
- alias :visit_Arel_Nodes_InfixOperation :binary
- alias :visit_Arel_Nodes_JoinSource :binary
- alias :visit_Arel_Nodes_InnerJoin :binary
- alias :visit_Arel_Nodes_LessThan :binary
- alias :visit_Arel_Nodes_LessThanOrEqual :binary
- alias :visit_Arel_Nodes_Matches :binary
- alias :visit_Arel_Nodes_NotEqual :binary
- alias :visit_Arel_Nodes_NotIn :binary
- alias :visit_Arel_Nodes_NotRegexp :binary
- alias :visit_Arel_Nodes_IsNotDistinctFrom :binary
- alias :visit_Arel_Nodes_IsDistinctFrom :binary
- alias :visit_Arel_Nodes_Or :binary
- alias :visit_Arel_Nodes_OuterJoin :binary
- alias :visit_Arel_Nodes_Regexp :binary
- alias :visit_Arel_Nodes_RightOuterJoin :binary
- alias :visit_Arel_Nodes_TableAlias :binary
- alias :visit_Arel_Nodes_When :binary
-
- def visit_Arel_Nodes_StringJoin(o)
- visit o.left
- end
-
- def visit_Arel_Attribute(o)
- visit o.relation
- visit o.name
- end
- alias :visit_Arel_Attributes_Integer :visit_Arel_Attribute
- alias :visit_Arel_Attributes_Float :visit_Arel_Attribute
- alias :visit_Arel_Attributes_String :visit_Arel_Attribute
- alias :visit_Arel_Attributes_Time :visit_Arel_Attribute
- alias :visit_Arel_Attributes_Boolean :visit_Arel_Attribute
- alias :visit_Arel_Attributes_Attribute :visit_Arel_Attribute
- alias :visit_Arel_Attributes_Decimal :visit_Arel_Attribute
-
- def visit_Arel_Table(o)
- visit o.name
- end
-
- def terminal(o)
- end
- alias :visit_ActiveSupport_Multibyte_Chars :terminal
- alias :visit_ActiveSupport_StringInquirer :terminal
- alias :visit_Arel_Nodes_Lock :terminal
- alias :visit_Arel_Nodes_Node :terminal
- alias :visit_Arel_Nodes_SqlLiteral :terminal
- alias :visit_Arel_Nodes_BindParam :terminal
- alias :visit_Arel_Nodes_Window :terminal
- alias :visit_Arel_Nodes_True :terminal
- alias :visit_Arel_Nodes_False :terminal
- alias :visit_BigDecimal :terminal
- alias :visit_Class :terminal
- alias :visit_Date :terminal
- alias :visit_DateTime :terminal
- alias :visit_FalseClass :terminal
- alias :visit_Float :terminal
- alias :visit_Integer :terminal
- alias :visit_NilClass :terminal
- alias :visit_String :terminal
- alias :visit_Symbol :terminal
- alias :visit_Time :terminal
- alias :visit_TrueClass :terminal
-
- def visit_Arel_Nodes_InsertStatement(o)
- visit o.relation
- visit o.columns
- visit o.values
- end
-
- def visit_Arel_Nodes_SelectCore(o)
- visit o.projections
- visit o.source
- visit o.wheres
- visit o.groups
- visit o.windows
- visit o.havings
- end
-
- def visit_Arel_Nodes_SelectStatement(o)
- visit o.cores
- visit o.orders
- visit o.limit
- visit o.lock
- visit o.offset
- end
-
- def visit_Arel_Nodes_UpdateStatement(o)
- visit o.relation
- visit o.values
- visit o.wheres
- visit o.orders
- visit o.limit
- end
-
- def visit_Arel_Nodes_Comment(o)
- visit o.values
- end
-
- def visit_Array(o)
- o.each { |i| visit i }
- end
- alias :visit_Set :visit_Array
-
- def visit_Hash(o)
- o.each { |k, v| visit(k); visit(v) }
- end
-
- DISPATCH = dispatch_cache
-
- def get_dispatch_cache
- DISPATCH
- end
- end
- end
-end
diff --git a/activerecord/lib/arel/visitors/dot.rb b/activerecord/lib/arel/visitors/dot.rb
index ecc386de07..c4ea07bcfe 100644
--- a/activerecord/lib/arel/visitors/dot.rb
+++ b/activerecord/lib/arel/visitors/dot.rb
@@ -31,7 +31,6 @@ module Arel # :nodoc: all
end
private
-
def visit_Arel_Nodes_Ordering(o)
visit_edge o, "expr"
end
diff --git a/activerecord/lib/arel/visitors/mssql.rb b/activerecord/lib/arel/visitors/mssql.rb
index 8475139870..92eb94f802 100644
--- a/activerecord/lib/arel/visitors/mssql.rb
+++ b/activerecord/lib/arel/visitors/mssql.rb
@@ -11,7 +11,6 @@ module Arel # :nodoc: all
end
private
-
def visit_Arel_Nodes_IsNotDistinctFrom(o, collector)
right = o.right
diff --git a/activerecord/lib/arel/visitors/oracle.rb b/activerecord/lib/arel/visitors/oracle.rb
index f96bf65ee5..aab66301ef 100644
--- a/activerecord/lib/arel/visitors/oracle.rb
+++ b/activerecord/lib/arel/visitors/oracle.rb
@@ -4,7 +4,6 @@ module Arel # :nodoc: all
module Visitors
class Oracle < Arel::Visitors::ToSql
private
-
def visit_Arel_Nodes_SelectStatement(o, collector)
o = order_hacks(o)
diff --git a/activerecord/lib/arel/visitors/oracle12.rb b/activerecord/lib/arel/visitors/oracle12.rb
index 6269bc3907..36783243b5 100644
--- a/activerecord/lib/arel/visitors/oracle12.rb
+++ b/activerecord/lib/arel/visitors/oracle12.rb
@@ -4,7 +4,6 @@ module Arel # :nodoc: all
module Visitors
class Oracle12 < Arel::Visitors::ToSql
private
-
def visit_Arel_Nodes_SelectStatement(o, collector)
# Oracle does not allow LIMIT clause with select for update
if o.limit && o.lock
diff --git a/activerecord/lib/arel/visitors/postgresql.rb b/activerecord/lib/arel/visitors/postgresql.rb
index 8296f1cdc1..d4f21ff93e 100644
--- a/activerecord/lib/arel/visitors/postgresql.rb
+++ b/activerecord/lib/arel/visitors/postgresql.rb
@@ -4,7 +4,6 @@ module Arel # :nodoc: all
module Visitors
class PostgreSQL < Arel::Visitors::ToSql
private
-
def visit_Arel_Nodes_Matches(o, collector)
op = o.case_sensitive ? " LIKE " : " ILIKE "
collector = infix_value o, collector, op
diff --git a/activerecord/lib/arel/visitors/sqlite.rb b/activerecord/lib/arel/visitors/sqlite.rb
index af6f7e856a..62ec74ad82 100644
--- a/activerecord/lib/arel/visitors/sqlite.rb
+++ b/activerecord/lib/arel/visitors/sqlite.rb
@@ -4,7 +4,6 @@ module Arel # :nodoc: all
module Visitors
class SQLite < Arel::Visitors::ToSql
private
-
# Locks are not supported in SQLite
def visit_Arel_Nodes_Lock(o, collector)
collector
diff --git a/activerecord/lib/arel/visitors/to_sql.rb b/activerecord/lib/arel/visitors/to_sql.rb
index 4740e6d94f..eff7a0d036 100644
--- a/activerecord/lib/arel/visitors/to_sql.rb
+++ b/activerecord/lib/arel/visitors/to_sql.rb
@@ -19,7 +19,6 @@ module Arel # :nodoc: all
end
private
-
def visit_Arel_Nodes_DeleteStatement(o, collector)
o = prepare_delete_statement(o)
@@ -52,10 +51,14 @@ module Arel # :nodoc: all
def visit_Arel_Nodes_InsertStatement(o, collector)
collector << "INSERT INTO "
collector = visit o.relation, collector
- if o.columns.any?
- collector << " (#{o.columns.map { |x|
- quote_column_name x.name
- }.join ', '})"
+
+ unless o.columns.empty?
+ collector << " ("
+ o.columns.each_with_index do |x, i|
+ collector << ", " unless i == 0
+ collector << quote_column_name(x.name)
+ end
+ collector << ")"
end
if o.values
@@ -97,22 +100,20 @@ module Arel # :nodoc: all
def visit_Arel_Nodes_ValuesList(o, collector)
collector << "VALUES "
- len = o.rows.length - 1
- o.rows.each_with_index { |row, i|
+ o.rows.each_with_index do |row, i|
+ collector << ", " unless i == 0
collector << "("
- row_len = row.length - 1
row.each_with_index do |value, k|
+ collector << ", " unless k == 0
case value
when Nodes::SqlLiteral, Nodes::BindParam
collector = visit(value, collector)
else
collector << quote(value).to_s
end
- collector << ", " unless k == row_len
end
collector << ")"
- collector << ", " unless i == len
- }
+ end
collector
end
@@ -128,11 +129,10 @@ module Arel # :nodoc: all
unless o.orders.empty?
collector << " ORDER BY "
- len = o.orders.length - 1
- o.orders.each_with_index { |x, i|
+ o.orders.each_with_index do |x, i|
+ collector << ", " unless i == 0
collector = visit(x, collector)
- collector << ", " unless len == i
- }
+ end
end
visit_Arel_Nodes_SelectOptions(o, collector)
@@ -506,7 +506,7 @@ module Arel # :nodoc: all
def visit_Arel_Table(o, collector)
if o.table_alias
- collector << "#{quote_table_name o.name} #{quote_table_name o.table_alias}"
+ collector << quote_table_name(o.name) << " " << quote_table_name(o.table_alias)
else
collector << quote_table_name(o.name)
end
@@ -682,20 +682,13 @@ module Arel # :nodoc: all
end
def visit_Arel_Nodes_UnqualifiedColumn(o, collector)
- collector << "#{quote_column_name o.name}"
- collector
+ collector << quote_column_name(o.name)
end
def visit_Arel_Attributes_Attribute(o, collector)
join_name = o.relation.table_alias || o.relation.name
- collector << "#{quote_table_name join_name}.#{quote_column_name o.name}"
+ collector << quote_table_name(join_name) << "." << quote_column_name(o.name)
end
- alias :visit_Arel_Attributes_Integer :visit_Arel_Attributes_Attribute
- alias :visit_Arel_Attributes_Float :visit_Arel_Attributes_Attribute
- alias :visit_Arel_Attributes_Decimal :visit_Arel_Attributes_Attribute
- alias :visit_Arel_Attributes_String :visit_Arel_Attributes_Attribute
- alias :visit_Arel_Attributes_Time :visit_Arel_Attributes_Attribute
- alias :visit_Arel_Attributes_Boolean :visit_Arel_Attributes_Attribute
def literal(o, collector); collector << o.to_s; end
@@ -785,14 +778,11 @@ module Arel # :nodoc: all
end
def inject_join(list, collector, join_str)
- len = list.length - 1
- list.each_with_index.inject(collector) { |c, (x, i)|
- if i == len
- visit x, c
- else
- visit(x, c) << join_str
- end
- }
+ list.each_with_index do |x, i|
+ collector << join_str unless i == 0
+ collector = visit(x, collector)
+ end
+ collector
end
def unboundable?(value)
diff --git a/activerecord/lib/arel/visitors/visitor.rb b/activerecord/lib/arel/visitors/visitor.rb
index 1c17184e86..9066307aed 100644
--- a/activerecord/lib/arel/visitors/visitor.rb
+++ b/activerecord/lib/arel/visitors/visitor.rb
@@ -7,16 +7,15 @@ module Arel # :nodoc: all
@dispatch = get_dispatch_cache
end
- def accept(object, *args)
- visit object, *args
+ def accept(object, collector = nil)
+ visit object, collector
end
private
-
attr_reader :dispatch
def self.dispatch_cache
- Hash.new do |hash, klass|
+ @dispatch_cache ||= Hash.new do |hash, klass|
hash[klass] = "visit_#{(klass.name || '').gsub('::', '_')}"
end
end
@@ -25,9 +24,13 @@ module Arel # :nodoc: all
self.class.dispatch_cache
end
- def visit(object, *args)
+ def visit(object, collector = nil)
dispatch_method = dispatch[object.class]
- send dispatch_method, object, *args
+ if collector
+ send dispatch_method, object, collector
+ else
+ send dispatch_method, object
+ end
rescue NoMethodError => e
raise e if respond_to?(dispatch_method, true)
superklass = object.class.ancestors.find { |klass|
diff --git a/activerecord/lib/arel/visitors/where_sql.rb b/activerecord/lib/arel/visitors/where_sql.rb
index c6caf5e7c9..8fb299d1c8 100644
--- a/activerecord/lib/arel/visitors/where_sql.rb
+++ b/activerecord/lib/arel/visitors/where_sql.rb
@@ -9,7 +9,6 @@ module Arel # :nodoc: all
end
private
-
def visit_Arel_Nodes_SelectCore(o, collector)
collector << "WHERE "
wheres = o.wheres.map do |where|
diff --git a/activerecord/lib/rails/generators/active_record/application_record/application_record_generator.rb b/activerecord/lib/rails/generators/active_record/application_record/application_record_generator.rb
index 35d5664400..56b9628a92 100644
--- a/activerecord/lib/rails/generators/active_record/application_record/application_record_generator.rb
+++ b/activerecord/lib/rails/generators/active_record/application_record/application_record_generator.rb
@@ -13,7 +13,6 @@ module ActiveRecord
end
private
-
def application_record_file_name
@application_record_file_name ||=
if namespaced?
diff --git a/activerecord/lib/rails/generators/active_record/migration.rb b/activerecord/lib/rails/generators/active_record/migration.rb
index cbb88d571d..af753071a9 100644
--- a/activerecord/lib/rails/generators/active_record/migration.rb
+++ b/activerecord/lib/rails/generators/active_record/migration.rb
@@ -17,7 +17,6 @@ module ActiveRecord
end
private
-
def primary_key_type
key_type = options[:primary_key_type]
", id: :#{key_type}" if key_type
diff --git a/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
index cb2c74f1ca..0620a515bd 100644
--- a/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
+++ b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
@@ -7,6 +7,7 @@ module ActiveRecord
class MigrationGenerator < Base # :nodoc:
argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]"
+ class_option :timestamps, type: :boolean
class_option :primary_key_type, type: :string, desc: "The type for primary key"
class_option :database, type: :string, aliases: %i(--db), desc: "The database for your migration. By default, the current environment's primary database is used."
diff --git a/activerecord/lib/rails/generators/active_record/model/model_generator.rb b/activerecord/lib/rails/generators/active_record/model/model_generator.rb
index c71bbdcab8..d4733f948f 100644
--- a/activerecord/lib/rails/generators/active_record/model/model_generator.rb
+++ b/activerecord/lib/rails/generators/active_record/model/model_generator.rb
@@ -35,7 +35,6 @@ module ActiveRecord
hook_for :test_framework
private
-
def attributes_with_index
attributes.select { |a| !a.reference? && a.has_index? }
end
diff --git a/activerecord/test/active_record/connection_adapters/fake_adapter.rb b/activerecord/test/active_record/connection_adapters/fake_adapter.rb
index f977b2997b..f1f457aedd 100644
--- a/activerecord/test/active_record/connection_adapters/fake_adapter.rb
+++ b/activerecord/test/active_record/connection_adapters/fake_adapter.rb
@@ -32,7 +32,8 @@ module ActiveRecord
name.to_s,
options[:default],
fetch_type_metadata(sql_type),
- options[:null])
+ options[:null],
+ )
end
def columns(table_name)
diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb
index ce2ed06c1d..0bc617edbe 100644
--- a/activerecord/test/cases/adapter_test.rb
+++ b/activerecord/test/cases/adapter_test.rb
@@ -12,6 +12,7 @@ module ActiveRecord
def setup
@connection = ActiveRecord::Base.connection
@connection.materialize_transactions
+ @connection_handler = ActiveRecord::Base.connection_handler
end
##
@@ -166,7 +167,7 @@ module ActiveRecord
def test_preventing_writes_predicate
assert_not_predicate @connection, :preventing_writes?
- @connection.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
assert_predicate @connection, :preventing_writes?
end
@@ -176,7 +177,7 @@ module ActiveRecord
def test_errors_when_an_insert_query_is_called_while_preventing_writes
assert_no_queries do
assert_raises(ActiveRecord::ReadOnlyError) do
- @connection.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
@connection.transaction do
@connection.insert("INSERT INTO subscribers(nick) VALUES ('138853948594')", nil, false)
end
@@ -190,7 +191,7 @@ module ActiveRecord
assert_no_queries do
assert_raises(ActiveRecord::ReadOnlyError) do
- @connection.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
@connection.transaction do
@connection.update("UPDATE subscribers SET nick = '9989' WHERE nick = '138853948594'")
end
@@ -204,7 +205,7 @@ module ActiveRecord
assert_no_queries do
assert_raises(ActiveRecord::ReadOnlyError) do
- @connection.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
@connection.transaction do
@connection.delete("DELETE FROM subscribers WHERE nick = '138853948594'")
end
@@ -216,7 +217,7 @@ module ActiveRecord
def test_doesnt_error_when_a_select_query_is_called_while_preventing_writes
@connection.insert("INSERT INTO subscribers(nick) VALUES ('138853948594')")
- @connection.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
result = @connection.select_all("SELECT subscribers.* FROM subscribers WHERE nick = '138853948594'")
assert_equal 1, result.length
end
@@ -559,7 +560,6 @@ module ActiveRecord
end
private
-
def reset_fixtures(*fixture_names)
ActiveRecord::FixtureSet.reset_cache
diff --git a/activerecord/test/cases/adapters/mysql2/annotate_test.rb b/activerecord/test/cases/adapters/mysql2/annotate_test.rb
deleted file mode 100644
index b512540073..0000000000
--- a/activerecord/test/cases/adapters/mysql2/annotate_test.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# frozen_string_literal: true
-
-require "cases/helper"
-require "models/post"
-
-class Mysql2AnnotateTest < ActiveRecord::Mysql2TestCase
- fixtures :posts
-
- def test_annotate_wraps_content_in_an_inline_comment
- assert_sql(%r{\ASELECT `posts`\.`id` FROM `posts` /\* foo \*/}) do
- posts = Post.select(:id).annotate("foo")
- assert posts.first
- end
- end
-
- def test_annotate_is_sanitized
- assert_sql(%r{\ASELECT `posts`\.`id` FROM `posts` /\* foo \*/}) do
- posts = Post.select(:id).annotate("*/foo/*")
- assert posts.first
- end
-
- assert_sql(%r{\ASELECT `posts`\.`id` FROM `posts` /\* foo \*/}) do
- posts = Post.select(:id).annotate("**//foo//**")
- assert posts.first
- end
-
- assert_sql(%r{\ASELECT `posts`\.`id` FROM `posts` /\* foo \*/ /\* bar \*/}) do
- posts = Post.select(:id).annotate("*/foo/*").annotate("*/bar")
- assert posts.first
- end
-
- assert_sql(%r{\ASELECT `posts`\.`id` FROM `posts` /\* \+ MAX_EXECUTION_TIME\(1\) \*/}) do
- posts = Post.select(:id).annotate("+ MAX_EXECUTION_TIME(1)")
- assert posts.first
- end
- end
-end
diff --git a/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb b/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb
index c32475c683..3756f74c95 100644
--- a/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb
@@ -22,7 +22,7 @@ class Mysql2CaseSensitivityTest < ActiveRecord::Mysql2TestCase
CollationTest.validates_uniqueness_of(:string_ci_column, case_sensitive: false)
CollationTest.create!(string_ci_column: "A")
invalid = CollationTest.new(string_ci_column: "a")
- queries = assert_sql { invalid.save }
+ queries = capture_sql { invalid.save }
ci_uniqueness_query = queries.detect { |q| q.match(/string_ci_column/) }
assert_no_match(/lower/i, ci_uniqueness_query)
end
@@ -31,7 +31,7 @@ class Mysql2CaseSensitivityTest < ActiveRecord::Mysql2TestCase
CollationTest.validates_uniqueness_of(:string_cs_column, case_sensitive: false)
CollationTest.create!(string_cs_column: "A")
invalid = CollationTest.new(string_cs_column: "a")
- queries = assert_sql { invalid.save }
+ queries = capture_sql { invalid.save }
cs_uniqueness_query = queries.detect { |q| q.match(/string_cs_column/) }
assert_match(/lower/i, cs_uniqueness_query)
end
@@ -40,7 +40,7 @@ class Mysql2CaseSensitivityTest < ActiveRecord::Mysql2TestCase
CollationTest.validates_uniqueness_of(:string_ci_column, case_sensitive: true)
CollationTest.create!(string_ci_column: "A")
invalid = CollationTest.new(string_ci_column: "A")
- queries = assert_sql { invalid.save }
+ queries = capture_sql { invalid.save }
ci_uniqueness_query = queries.detect { |q| q.match(/string_ci_column/) }
assert_match(/binary/i, ci_uniqueness_query)
end
@@ -49,7 +49,7 @@ class Mysql2CaseSensitivityTest < ActiveRecord::Mysql2TestCase
CollationTest.validates_uniqueness_of(:string_cs_column, case_sensitive: true)
CollationTest.create!(string_cs_column: "A")
invalid = CollationTest.new(string_cs_column: "A")
- queries = assert_sql { invalid.save }
+ queries = capture_sql { invalid.save }
cs_uniqueness_query = queries.detect { |q| q.match(/string_cs_column/) }
assert_no_match(/binary/i, cs_uniqueness_query)
end
@@ -58,7 +58,7 @@ class Mysql2CaseSensitivityTest < ActiveRecord::Mysql2TestCase
CollationTest.validates_uniqueness_of(:binary_column, case_sensitive: true)
CollationTest.create!(binary_column: "A")
invalid = CollationTest.new(binary_column: "A")
- queries = assert_sql { invalid.save }
+ queries = capture_sql { invalid.save }
bin_uniqueness_query = queries.detect { |q| q.match(/binary_column/) }
assert_no_match(/\bBINARY\b/, bin_uniqueness_query)
end
diff --git a/activerecord/test/cases/adapters/mysql2/connection_test.rb b/activerecord/test/cases/adapters/mysql2/connection_test.rb
index 9c6566106a..cb7461a8d5 100644
--- a/activerecord/test/cases/adapters/mysql2/connection_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/connection_test.rb
@@ -197,7 +197,6 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase
end
private
-
def test_lock_free(lock_name)
@connection.select_value("SELECT IS_FREE_LOCK(#{@connection.quote(lock_name)})") == 1
end
diff --git a/activerecord/test/cases/adapters/mysql2/enum_test.rb b/activerecord/test/cases/adapters/mysql2/enum_test.rb
index 832f5d61d1..1168b3677e 100644
--- a/activerecord/test/cases/adapters/mysql2/enum_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/enum_test.rb
@@ -1,11 +1,20 @@
# frozen_string_literal: true
require "cases/helper"
+require "support/schema_dumping_helper"
class Mysql2EnumTest < ActiveRecord::Mysql2TestCase
+ include SchemaDumpingHelper
+
class EnumTest < ActiveRecord::Base
end
+ def setup
+ EnumTest.connection.create_table :enum_tests, id: false, force: true do |t|
+ t.column :enum_column, "enum('text','blob','tiny','medium','long','unsigned','bigint')"
+ end
+ end
+
def test_enum_limit
column = EnumTest.columns_hash["enum_column"]
assert_equal 8, column.limit
@@ -20,4 +29,9 @@ class Mysql2EnumTest < ActiveRecord::Mysql2TestCase
column = EnumTest.columns_hash["enum_column"]
assert_not_predicate column, :bigint?
end
+
+ def test_schema_dumping
+ schema = dump_table_schema "enum_tests"
+ assert_match %r{t\.column "enum_column", "enum\('text','blob','tiny','medium','long','unsigned','bigint'\)"$}, schema
+ end
end
diff --git a/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb b/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb
index 6ade2eec24..cfc1823773 100644
--- a/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb
@@ -8,6 +8,7 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase
def setup
@conn = ActiveRecord::Base.connection
+ @connection_handler = ActiveRecord::Base.connection_handler
end
def test_exec_query_nothing_raises_with_no_result_queries
@@ -19,6 +20,18 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase
end
end
+ def test_database_exists_returns_false_if_database_does_not_exist
+ config = ActiveRecord::Base.configurations["arunit"].merge(database: "inexistent_activerecord_unittest")
+ assert_not ActiveRecord::ConnectionAdapters::Mysql2Adapter.database_exists?(config),
+ "expected database to not exist"
+ end
+
+ def test_database_exists_returns_true_when_the_database_exists
+ config = ActiveRecord::Base.configurations["arunit"]
+ assert ActiveRecord::ConnectionAdapters::Mysql2Adapter.database_exists?(config),
+ "expected database #{config[:database]} to exist"
+ end
+
def test_columns_for_distinct_zero_orders
assert_equal "posts.id",
@conn.columns_for_distinct("posts.id", [])
@@ -148,7 +161,7 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase
def test_errors_when_an_insert_query_is_called_while_preventing_writes
assert_raises(ActiveRecord::ReadOnlyError) do
- @conn.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
@conn.insert("INSERT INTO `engines` (`car_id`) VALUES ('138853948594')")
end
end
@@ -158,7 +171,7 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase
@conn.insert("INSERT INTO `engines` (`car_id`) VALUES ('138853948594')")
assert_raises(ActiveRecord::ReadOnlyError) do
- @conn.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
@conn.update("UPDATE `engines` SET `engines`.`car_id` = '9989' WHERE `engines`.`car_id` = '138853948594'")
end
end
@@ -168,7 +181,7 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase
@conn.execute("INSERT INTO `engines` (`car_id`) VALUES ('138853948594')")
assert_raises(ActiveRecord::ReadOnlyError) do
- @conn.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
@conn.execute("DELETE FROM `engines` where `engines`.`car_id` = '138853948594'")
end
end
@@ -178,7 +191,7 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase
@conn.execute("INSERT INTO `engines` (`car_id`) VALUES ('138853948594')")
assert_raises(ActiveRecord::ReadOnlyError) do
- @conn.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
@conn.execute("REPLACE INTO `engines` SET `engines`.`car_id` = '249823948'")
end
end
@@ -187,19 +200,19 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase
def test_doesnt_error_when_a_select_query_is_called_while_preventing_writes
@conn.execute("INSERT INTO `engines` (`car_id`) VALUES ('138853948594')")
- @conn.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
assert_equal 1, @conn.execute("SELECT `engines`.* FROM `engines` WHERE `engines`.`car_id` = '138853948594'").entries.count
end
end
def test_doesnt_error_when_a_show_query_is_called_while_preventing_writes
- @conn.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
assert_equal 2, @conn.execute("SHOW FULL FIELDS FROM `engines`").entries.count
end
end
def test_doesnt_error_when_a_set_query_is_called_while_preventing_writes
- @conn.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
assert_nil @conn.execute("SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci")
end
end
@@ -207,13 +220,27 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase
def test_doesnt_error_when_a_read_query_with_leading_chars_is_called_while_preventing_writes
@conn.execute("INSERT INTO `engines` (`car_id`) VALUES ('138853948594')")
- @conn.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
assert_equal 1, @conn.execute("(\n( SELECT `engines`.* FROM `engines` WHERE `engines`.`car_id` = '138853948594' ) )").entries.count
end
end
- private
+ def test_read_timeout_exception
+ ActiveRecord::Base.establish_connection(
+ ActiveRecord::Base.configurations[:arunit].merge("read_timeout" => 1)
+ )
+ error = assert_raises(ActiveRecord::AdapterTimeout) do
+ ActiveRecord::Base.connection.execute("SELECT SLEEP(2)")
+ end
+ assert_kind_of ActiveRecord::QueryAborted, error
+
+ assert_equal Mysql2::Error::TimeoutError, error.cause.class
+ ensure
+ ActiveRecord::Base.establish_connection :arunit
+ end
+
+ private
def with_example_table(definition = "id int auto_increment primary key, number int, data varchar(255)", &block)
super(@conn, "ex", definition, &block)
end
diff --git a/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb b/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb
index d7d9a2d732..182d5a3e58 100644
--- a/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb
@@ -40,7 +40,6 @@ class SchemaMigrationsTest < ActiveRecord::Mysql2TestCase
end
private
-
def with_encoding_utf8mb4
database_name = connection.current_database
database_info = connection.select_one("SELECT * FROM information_schema.schemata WHERE schema_name = '#{database_name}'")
diff --git a/activerecord/test/cases/adapters/mysql2/set_test.rb b/activerecord/test/cases/adapters/mysql2/set_test.rb
new file mode 100644
index 0000000000..89107e142f
--- /dev/null
+++ b/activerecord/test/cases/adapters/mysql2/set_test.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require "cases/helper"
+require "support/schema_dumping_helper"
+
+class Mysql2SetTest < ActiveRecord::Mysql2TestCase
+ include SchemaDumpingHelper
+
+ class SetTest < ActiveRecord::Base
+ end
+
+ def setup
+ SetTest.connection.create_table :set_tests, id: false, force: true do |t|
+ t.column :set_column, "set('text','blob','tiny','medium','long','unsigned','bigint')"
+ end
+ end
+
+ def test_should_not_be_unsigned
+ column = SetTest.columns_hash["set_column"]
+ assert_not_predicate column, :unsigned?
+ end
+
+ def test_should_not_be_bigint
+ column = SetTest.columns_hash["set_column"]
+ assert_not_predicate column, :bigint?
+ end
+
+ def test_schema_dumping
+ schema = dump_table_schema "set_tests"
+ assert_match %r{t\.column "set_column", "set\('text','blob','tiny','medium','long','unsigned','bigint'\)"$}, schema
+ end
+end
diff --git a/activerecord/test/cases/adapters/mysql2/table_options_test.rb b/activerecord/test/cases/adapters/mysql2/table_options_test.rb
index 1c92df940f..13cf1daa08 100644
--- a/activerecord/test/cases/adapters/mysql2/table_options_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/table_options_test.rb
@@ -73,7 +73,7 @@ class Mysql2DefaultEngineOptionSchemaDumpTest < ActiveRecord::Mysql2TestCase
end
end.new
- ActiveRecord::Migrator.new(:up, [migration]).migrate
+ ActiveRecord::Migrator.new(:up, [migration], ActiveRecord::Base.connection.schema_migration).migrate
output = dump_table_schema("mysql_table_options")
options = %r{create_table "mysql_table_options", options: "(?<options>.*)"}.match(output)[:options]
@@ -112,7 +112,7 @@ class Mysql2DefaultEngineOptionSqlOutputTest < ActiveRecord::Mysql2TestCase
end
end.new
- ActiveRecord::Migrator.new(:up, [migration]).migrate
+ ActiveRecord::Migrator.new(:up, [migration], ActiveRecord::Base.connection.schema_migration).migrate
assert_match %r{ENGINE=InnoDB}, @log.string
end
diff --git a/activerecord/test/cases/adapters/mysql2/transaction_test.rb b/activerecord/test/cases/adapters/mysql2/transaction_test.rb
index 52e283f247..2041cc308f 100644
--- a/activerecord/test/cases/adapters/mysql2/transaction_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/transaction_test.rb
@@ -92,7 +92,7 @@ module ActiveRecord
test "raises StatementTimeout when statement timeout exceeded" do
skip unless ActiveRecord::Base.connection.show_variable("max_execution_time")
- assert_raises(ActiveRecord::StatementTimeout) do
+ error = assert_raises(ActiveRecord::StatementTimeout) do
s = Sample.create!(value: 1)
latch1 = Concurrent::CountDownLatch.new
latch2 = Concurrent::CountDownLatch.new
@@ -117,10 +117,11 @@ module ActiveRecord
thread.join
end
end
+ assert_kind_of ActiveRecord::QueryAborted, error
end
test "raises QueryCanceled when canceling statement due to user request" do
- assert_raises(ActiveRecord::QueryCanceled) do
+ error = assert_raises(ActiveRecord::QueryCanceled) do
s = Sample.create!(value: 1)
latch = Concurrent::CountDownLatch.new
@@ -144,6 +145,7 @@ module ActiveRecord
thread.join
end
end
+ assert_kind_of ActiveRecord::QueryAborted, error
end
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/annotate_test.rb b/activerecord/test/cases/adapters/postgresql/annotate_test.rb
deleted file mode 100644
index 42a2861511..0000000000
--- a/activerecord/test/cases/adapters/postgresql/annotate_test.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# frozen_string_literal: true
-
-require "cases/helper"
-require "models/post"
-
-class PostgresqlAnnotateTest < ActiveRecord::PostgreSQLTestCase
- fixtures :posts
-
- def test_annotate_wraps_content_in_an_inline_comment
- assert_sql(%r{\ASELECT "posts"\."id" FROM "posts" /\* foo \*/}) do
- posts = Post.select(:id).annotate("foo")
- assert posts.first
- end
- end
-
- def test_annotate_is_sanitized
- assert_sql(%r{\ASELECT "posts"\."id" FROM "posts" /\* foo \*/}) do
- posts = Post.select(:id).annotate("*/foo/*")
- assert posts.first
- end
-
- assert_sql(%r{\ASELECT "posts"\."id" FROM "posts" /\* foo \*/}) do
- posts = Post.select(:id).annotate("**//foo//**")
- assert posts.first
- end
-
- assert_sql(%r{\ASELECT "posts"\."id" FROM "posts" /\* foo \*/ /\* bar \*/}) do
- posts = Post.select(:id).annotate("*/foo/*").annotate("*/bar")
- assert posts.first
- end
-
- assert_sql(%r{\ASELECT "posts"\."id" FROM "posts" /\* \+ MAX_EXECUTION_TIME\(1\) \*/}) do
- posts = Post.select(:id).annotate("+ MAX_EXECUTION_TIME(1)")
- assert posts.first
- end
- end
-end
diff --git a/activerecord/test/cases/adapters/postgresql/connection_test.rb b/activerecord/test/cases/adapters/postgresql/connection_test.rb
index 9494863a75..dcee4fd22d 100644
--- a/activerecord/test/cases/adapters/postgresql/connection_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/connection_test.rb
@@ -239,7 +239,6 @@ module ActiveRecord
end
private
-
def with_warning_suppression
log_level = @connection.client_min_messages
@connection.client_min_messages = "error"
diff --git a/activerecord/test/cases/adapters/postgresql/extension_migration_test.rb b/activerecord/test/cases/adapters/postgresql/extension_migration_test.rb
index 0fd7b2c6ed..16baa8933d 100644
--- a/activerecord/test/cases/adapters/postgresql/extension_migration_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/extension_migration_test.rb
@@ -27,20 +27,20 @@ class PostgresqlExtensionMigrationTest < ActiveRecord::PostgreSQLTestCase
ActiveRecord::Base.table_name_prefix = "p_"
ActiveRecord::Base.table_name_suffix = "_s"
- ActiveRecord::SchemaMigration.reset_table_name
+ @connection.schema_migration.reset_table_name
ActiveRecord::InternalMetadata.reset_table_name
- ActiveRecord::SchemaMigration.delete_all rescue nil
+ @connection.schema_migration.delete_all rescue nil
ActiveRecord::Migration.verbose = false
end
def teardown
- ActiveRecord::SchemaMigration.delete_all rescue nil
+ @connection.schema_migration.delete_all rescue nil
ActiveRecord::Migration.verbose = true
ActiveRecord::Base.table_name_prefix = @old_table_name_prefix
ActiveRecord::Base.table_name_suffix = @old_table_name_suffix
- ActiveRecord::SchemaMigration.reset_table_name
+ @connection.schema_migration.reset_table_name
ActiveRecord::InternalMetadata.reset_table_name
super
@@ -50,7 +50,7 @@ class PostgresqlExtensionMigrationTest < ActiveRecord::PostgreSQLTestCase
@connection.disable_extension("hstore")
migrations = [EnableHstore.new(nil, 1)]
- ActiveRecord::Migrator.new(:up, migrations).migrate
+ ActiveRecord::Migrator.new(:up, migrations, ActiveRecord::Base.connection.schema_migration).migrate
assert @connection.extension_enabled?("hstore"), "extension hstore should be enabled"
end
@@ -58,7 +58,7 @@ class PostgresqlExtensionMigrationTest < ActiveRecord::PostgreSQLTestCase
@connection.enable_extension("hstore")
migrations = [DisableHstore.new(nil, 1)]
- ActiveRecord::Migrator.new(:up, migrations).migrate
+ ActiveRecord::Migrator.new(:up, migrations, ActiveRecord::Base.connection.schema_migration).migrate
assert_not @connection.extension_enabled?("hstore"), "extension hstore should not be enabled"
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/geometric_test.rb b/activerecord/test/cases/adapters/postgresql/geometric_test.rb
index 14c262f4ce..f312b6e23d 100644
--- a/activerecord/test/cases/adapters/postgresql/geometric_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/geometric_test.rb
@@ -361,7 +361,6 @@ class PostgreSQLGeometricTypesTest < ActiveRecord::PostgreSQLTestCase
end
private
-
def assert_column_exists(column_name)
assert connection.column_exists?(table_name, column_name)
end
diff --git a/activerecord/test/cases/adapters/postgresql/money_test.rb b/activerecord/test/cases/adapters/postgresql/money_test.rb
index 1aa0348879..ff2ab22a80 100644
--- a/activerecord/test/cases/adapters/postgresql/money_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/money_test.rb
@@ -54,8 +54,12 @@ class PostgresqlMoneyTest < ActiveRecord::PostgreSQLTestCase
type = PostgresqlMoney.type_for_attribute("wealth")
assert_equal(12345678.12, type.cast(+"$12,345,678.12"))
assert_equal(12345678.12, type.cast(+"$12.345.678,12"))
+ assert_equal(12345678.12, type.cast(+"12,345,678.12"))
+ assert_equal(12345678.12, type.cast(+"12.345.678,12"))
assert_equal(-1.15, type.cast(+"-$1.15"))
assert_equal(-2.25, type.cast(+"($2.25)"))
+ assert_equal(-1.15, type.cast(+"-1.15"))
+ assert_equal(-2.25, type.cast(+"(2.25)"))
end
def test_schema_dumping
diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
index fbd3cbf90f..830c0892d3 100644
--- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
@@ -13,6 +13,7 @@ module ActiveRecord
def setup
@connection = ActiveRecord::Base.connection
+ @connection_handler = ActiveRecord::Base.connection_handler
end
def test_bad_connection
@@ -23,6 +24,18 @@ module ActiveRecord
end
end
+ def test_database_exists_returns_false_when_the_database_does_not_exist
+ config = { database: "non_extant_database", adapter: "postgresql" }
+ assert_not ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.database_exists?(config),
+ "expected database #{config[:database]} to not exist"
+ end
+
+ def test_database_exists_returns_true_when_the_database_exists
+ config = ActiveRecord::Base.configurations["arunit"]
+ assert ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.database_exists?(config),
+ "expected database #{config[:database]} to exist"
+ end
+
def test_primary_key
with_example_table do
assert_equal "id", @connection.primary_key("ex")
@@ -240,9 +253,11 @@ module ActiveRecord
def test_expression_index
with_example_table do
- @connection.add_index "ex", "mod(id, 10), abs(number)", name: "expression"
+ expr = "mod(id, 10), abs(number)"
+ @connection.add_index "ex", expr, name: "expression"
index = @connection.indexes("ex").find { |idx| idx.name == "expression" }
- assert_equal "mod(id, 10), abs(number)", index.columns
+ assert_equal expr, index.columns
+ assert_equal true, @connection.index_exists?("ex", expr, name: "expression")
end
end
@@ -379,7 +394,7 @@ module ActiveRecord
def test_errors_when_an_insert_query_is_called_while_preventing_writes
with_example_table do
assert_raises(ActiveRecord::ReadOnlyError) do
- @connection.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
@connection.execute("INSERT INTO ex (data) VALUES ('138853948594')")
end
end
@@ -391,7 +406,7 @@ module ActiveRecord
@connection.execute("INSERT INTO ex (data) VALUES ('138853948594')")
assert_raises(ActiveRecord::ReadOnlyError) do
- @connection.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
@connection.execute("UPDATE ex SET data = '9989' WHERE data = '138853948594'")
end
end
@@ -403,7 +418,7 @@ module ActiveRecord
@connection.execute("INSERT INTO ex (data) VALUES ('138853948594')")
assert_raises(ActiveRecord::ReadOnlyError) do
- @connection.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
@connection.execute("DELETE FROM ex where data = '138853948594'")
end
end
@@ -414,20 +429,20 @@ module ActiveRecord
with_example_table do
@connection.execute("INSERT INTO ex (data) VALUES ('138853948594')")
- @connection.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
assert_equal 1, @connection.execute("SELECT * FROM ex WHERE data = '138853948594'").entries.count
end
end
end
def test_doesnt_error_when_a_show_query_is_called_while_preventing_writes
- @connection.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
assert_equal 1, @connection.execute("SHOW TIME ZONE").entries.count
end
end
def test_doesnt_error_when_a_set_query_is_called_while_preventing_writes
- @connection.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
assert_equal [], @connection.execute("SET standard_conforming_strings = on").entries
end
end
@@ -436,14 +451,13 @@ module ActiveRecord
with_example_table do
@connection.execute("INSERT INTO ex (data) VALUES ('138853948594')")
- @connection.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
assert_equal 1, @connection.execute("(\n( SELECT * FROM ex WHERE data = '138853948594' ) )").entries.count
end
end
end
private
-
def with_example_table(definition = "id serial primary key, number integer, data character varying(255)", &block)
super(@connection, "ex", definition, &block)
end
diff --git a/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb b/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb
index ba477c63f4..a4f722c063 100644
--- a/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb
@@ -13,7 +13,7 @@ class PostgreSQLReferentialIntegrityTest < ActiveRecord::PostgreSQLTestCase
end
module MissingSuperuserPrivileges
- def execute(sql)
+ def execute(sql, name = nil)
if IS_REFERENTIAL_INTEGRITY_SQL.call(sql)
super "BROKEN;" rescue nil # put transaction in broken state
raise ActiveRecord::StatementInvalid, "PG::InsufficientPrivilege"
@@ -24,7 +24,7 @@ class PostgreSQLReferentialIntegrityTest < ActiveRecord::PostgreSQLTestCase
end
module ProgrammerMistake
- def execute(sql)
+ def execute(sql, name = nil)
if IS_REFERENTIAL_INTEGRITY_SQL.call(sql)
raise ArgumentError, "something is not right."
else
@@ -106,7 +106,6 @@ class PostgreSQLReferentialIntegrityTest < ActiveRecord::PostgreSQLTestCase
end
private
-
def assert_transaction_is_not_broken
assert_equal 1, @connection.select_value("SELECT 1")
end
diff --git a/activerecord/test/cases/adapters/postgresql/rename_table_test.rb b/activerecord/test/cases/adapters/postgresql/rename_table_test.rb
index 7eccaf4aa2..fae20de086 100644
--- a/activerecord/test/cases/adapters/postgresql/rename_table_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/rename_table_test.rb
@@ -25,7 +25,6 @@ class PostgresqlRenameTableTest < ActiveRecord::PostgreSQLTestCase
end
private
-
def num_indices_named(name)
@connection.execute(<<~SQL).values.length
SELECT 1 FROM "pg_index"
diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb
index 336cec30ca..fe6a3deff4 100644
--- a/activerecord/test/cases/adapters/postgresql/schema_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb
@@ -104,7 +104,11 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase
end
def test_schema_names
- assert_equal ["public", "test_schema", "test_schema2"], @connection.schema_names
+ schema_names = @connection.schema_names
+ assert_includes schema_names, "public"
+ assert_includes schema_names, "test_schema"
+ assert_includes schema_names, "test_schema2"
+ assert_includes schema_names, "hint_plan" if @connection.supports_optimizer_hints?
end
def test_create_schema
diff --git a/activerecord/test/cases/adapters/postgresql/transaction_test.rb b/activerecord/test/cases/adapters/postgresql/transaction_test.rb
index 919ff3d158..311863a418 100644
--- a/activerecord/test/cases/adapters/postgresql/transaction_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/transaction_test.rb
@@ -177,7 +177,6 @@ module ActiveRecord
end
private
-
def with_warning_suppression
log_level = ActiveRecord::Base.connection.client_min_messages
ActiveRecord::Base.connection.client_min_messages = "error"
diff --git a/activerecord/test/cases/adapters/postgresql/uuid_test.rb b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
index d2d8ea8042..a1c985fc71 100644
--- a/activerecord/test/cases/adapters/postgresql/uuid_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
@@ -293,14 +293,16 @@ class PostgresqlUUIDGenerationTest < ActiveRecord::PostgreSQLTestCase
create_table("pg_uuids_4", id: :uuid)
end
end.new
- ActiveRecord::Migrator.new(:up, [migration]).migrate
+ ActiveRecord::Migrator.new(:up, [migration], ActiveRecord::Base.connection.schema_migration).migrate
schema = dump_table_schema "pg_uuids_4"
assert_match(/\bcreate_table "pg_uuids_4", id: :uuid, default: -> { "uuid_generate_v4\(\)" }/, schema)
ensure
drop_table "pg_uuids_4"
ActiveRecord::Migration.verbose = @verbose_was
+ ActiveRecord::Base.connection.schema_migration.delete_all
end
+ uses_transaction :test_schema_dumper_for_uuid_primary_key_default_in_legacy_migration
end
class PostgresqlUUIDTestNilDefault < ActiveRecord::PostgreSQLTestCase
@@ -341,14 +343,16 @@ class PostgresqlUUIDTestNilDefault < ActiveRecord::PostgreSQLTestCase
create_table("pg_uuids_4", id: :uuid, default: nil)
end
end.new
- ActiveRecord::Migrator.new(:up, [migration]).migrate
+ ActiveRecord::Migrator.new(:up, [migration], ActiveRecord::Base.connection.schema_migration).migrate
schema = dump_table_schema "pg_uuids_4"
assert_match(/\bcreate_table "pg_uuids_4", id: :uuid, default: nil/, schema)
ensure
drop_table "pg_uuids_4"
ActiveRecord::Migration.verbose = @verbose_was
+ ActiveRecord::Base.connection.schema_migration.delete_all
end
+ uses_transaction :test_schema_dumper_for_uuid_primary_key_with_default_nil_in_legacy_migration
end
class PostgresqlUUIDTestInverseOf < ActiveRecord::PostgreSQLTestCase
diff --git a/activerecord/test/cases/adapters/sqlite3/annotate_test.rb b/activerecord/test/cases/adapters/sqlite3/annotate_test.rb
deleted file mode 100644
index 6567a5eca3..0000000000
--- a/activerecord/test/cases/adapters/sqlite3/annotate_test.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# frozen_string_literal: true
-
-require "cases/helper"
-require "models/post"
-
-class SQLite3AnnotateTest < ActiveRecord::SQLite3TestCase
- fixtures :posts
-
- def test_annotate_wraps_content_in_an_inline_comment
- assert_sql(%r{\ASELECT "posts"\."id" FROM "posts" /\* foo \*/}) do
- posts = Post.select(:id).annotate("foo")
- assert posts.first
- end
- end
-
- def test_annotate_is_sanitized
- assert_sql(%r{\ASELECT "posts"\."id" FROM "posts" /\* foo \*/}) do
- posts = Post.select(:id).annotate("*/foo/*")
- assert posts.first
- end
-
- assert_sql(%r{\ASELECT "posts"\."id" FROM "posts" /\* foo \*/}) do
- posts = Post.select(:id).annotate("**//foo//**")
- assert posts.first
- end
-
- assert_sql(%r{\ASELECT "posts"\."id" FROM "posts" /\* foo \*/ /\* bar \*/}) do
- posts = Post.select(:id).annotate("*/foo/*").annotate("*/bar")
- assert posts.first
- end
-
- assert_sql(%r{\ASELECT "posts"\."id" FROM "posts" /\* \+ MAX_EXECUTION_TIME\(1\) \*/}) do
- posts = Post.select(:id).annotate("+ MAX_EXECUTION_TIME(1)")
- assert posts.first
- end
- end
-end
diff --git a/activerecord/test/cases/adapters/sqlite3/collation_test.rb b/activerecord/test/cases/adapters/sqlite3/collation_test.rb
index 76c8f7d8dd..d938b5ff2f 100644
--- a/activerecord/test/cases/adapters/sqlite3/collation_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/collation_test.rb
@@ -11,6 +11,10 @@ class SQLite3CollationTest < ActiveRecord::SQLite3TestCase
@connection.create_table :collation_table_sqlite3, force: true do |t|
t.string :string_nocase, collation: "NOCASE"
t.text :text_rtrim, collation: "RTRIM"
+ # The decimal column might interfere with collation parsing.
+ # Thus, add this column type and some other string column afterwards.
+ t.decimal :decimal_col, precision: 6, scale: 2
+ t.string :string_after_decimal_nocase, collation: "NOCASE"
end
end
@@ -22,6 +26,11 @@ class SQLite3CollationTest < ActiveRecord::SQLite3TestCase
column = @connection.columns(:collation_table_sqlite3).find { |c| c.name == "string_nocase" }
assert_equal :string, column.type
assert_equal "NOCASE", column.collation
+
+ # Verify collation of a column behind the decimal column as well.
+ column = @connection.columns(:collation_table_sqlite3).find { |c| c.name == "string_after_decimal_nocase" }
+ assert_equal :string, column.type
+ assert_equal "NOCASE", column.collation
end
test "text column with collation" do
diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
index 806cfbfc00..b6d72c7bcd 100644
--- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
@@ -19,6 +19,8 @@ module ActiveRecord
@conn = Base.sqlite3_connection database: ":memory:",
adapter: "sqlite3",
timeout: 100
+
+ @connection_handler = ActiveRecord::Base.connection_handler
end
def test_bad_connection
@@ -28,6 +30,17 @@ module ActiveRecord
end
end
+ def test_database_exists_returns_false_when_the_database_does_not_exist
+ assert_not SQLite3Adapter.database_exists?(adapter: "sqlite3", database: "non_extant_db"),
+ "expected non_extant_db to not exist"
+ end
+
+ def test_database_exists_returns_true_when_databae_exists
+ config = ActiveRecord::Base.configurations["arunit"]
+ assert SQLite3Adapter.database_exists?(config),
+ "expected #{config[:database]} to exist"
+ end
+
unless in_memory_db?
def test_connect_with_url
original_connection = ActiveRecord::Base.remove_connection
@@ -51,6 +64,11 @@ module ActiveRecord
end
end
+ def test_database_exists_returns_true_for_an_in_memory_db
+ assert SQLite3Adapter.database_exists?(database: ":memory:"),
+ "Expected in memory database to exist"
+ end
+
def test_column_types
owner = Owner.create!(name: "hello".encode("ascii-8bit"))
owner.reload
@@ -572,7 +590,7 @@ module ActiveRecord
def test_errors_when_an_insert_query_is_called_while_preventing_writes
with_example_table "id int, data string" do
assert_raises(ActiveRecord::ReadOnlyError) do
- @conn.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
@conn.execute("INSERT INTO ex (data) VALUES ('138853948594')")
end
end
@@ -584,7 +602,7 @@ module ActiveRecord
@conn.execute("INSERT INTO ex (data) VALUES ('138853948594')")
assert_raises(ActiveRecord::ReadOnlyError) do
- @conn.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
@conn.execute("UPDATE ex SET data = '9989' WHERE data = '138853948594'")
end
end
@@ -596,7 +614,7 @@ module ActiveRecord
@conn.execute("INSERT INTO ex (data) VALUES ('138853948594')")
assert_raises(ActiveRecord::ReadOnlyError) do
- @conn.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
@conn.execute("DELETE FROM ex where data = '138853948594'")
end
end
@@ -608,7 +626,7 @@ module ActiveRecord
@conn.execute("INSERT INTO ex (data) VALUES ('138853948594')")
assert_raises(ActiveRecord::ReadOnlyError) do
- @conn.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
@conn.execute("REPLACE INTO ex (data) VALUES ('249823948')")
end
end
@@ -619,7 +637,7 @@ module ActiveRecord
with_example_table "id int, data string" do
@conn.execute("INSERT INTO ex (data) VALUES ('138853948594')")
- @conn.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
assert_equal 1, @conn.execute("SELECT data from ex WHERE data = '138853948594'").count
end
end
@@ -629,14 +647,13 @@ module ActiveRecord
with_example_table "id int, data string" do
@conn.execute("INSERT INTO ex (data) VALUES ('138853948594')")
- @conn.while_preventing_writes do
+ @connection_handler.while_preventing_writes do
assert_equal 1, @conn.execute(" SELECT data from ex WHERE data = '138853948594'").count
end
end
end
private
-
def assert_logged(logs)
subscriber = SQLSubscriber.new
subscription = ActiveSupport::Notifications.subscribe("sql.active_record", subscriber)
diff --git a/activerecord/test/cases/annotate_test.rb b/activerecord/test/cases/annotate_test.rb
new file mode 100644
index 0000000000..4d71d28f83
--- /dev/null
+++ b/activerecord/test/cases/annotate_test.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require "cases/helper"
+require "models/post"
+
+class AnnotateTest < ActiveRecord::TestCase
+ fixtures :posts
+
+ def test_annotate_wraps_content_in_an_inline_comment
+ quoted_posts_id, quoted_posts = regexp_escape_table_name("posts.id"), regexp_escape_table_name("posts")
+
+ assert_sql(%r{\ASELECT #{quoted_posts_id} FROM #{quoted_posts} /\* foo \*/}i) do
+ posts = Post.select(:id).annotate("foo")
+ assert posts.first
+ end
+ end
+
+ def test_annotate_is_sanitized
+ quoted_posts_id, quoted_posts = regexp_escape_table_name("posts.id"), regexp_escape_table_name("posts")
+
+ assert_sql(%r{\ASELECT #{quoted_posts_id} FROM #{quoted_posts} /\* foo \*/}i) do
+ posts = Post.select(:id).annotate("*/foo/*")
+ assert posts.first
+ end
+
+ assert_sql(%r{\ASELECT #{quoted_posts_id} FROM #{quoted_posts} /\* foo \*/}i) do
+ posts = Post.select(:id).annotate("**//foo//**")
+ assert posts.first
+ end
+
+ assert_sql(%r{\ASELECT #{quoted_posts_id} FROM #{quoted_posts} /\* foo \*/ /\* bar \*/}i) do
+ posts = Post.select(:id).annotate("*/foo/*").annotate("*/bar")
+ assert posts.first
+ end
+
+ assert_sql(%r{\ASELECT #{quoted_posts_id} FROM #{quoted_posts} /\* \+ MAX_EXECUTION_TIME\(1\) \*/}i) do
+ posts = Post.select(:id).annotate("+ MAX_EXECUTION_TIME(1)")
+ assert posts.first
+ end
+ end
+
+ private
+ def regexp_escape_table_name(name)
+ Regexp.escape(Post.connection.quote_table_name(name))
+ end
+end
diff --git a/activerecord/test/cases/ar_schema_test.rb b/activerecord/test/cases/ar_schema_test.rb
index 7aa6d089c5..2d5a06a4ac 100644
--- a/activerecord/test/cases/ar_schema_test.rb
+++ b/activerecord/test/cases/ar_schema_test.rb
@@ -9,7 +9,8 @@ class ActiveRecordSchemaTest < ActiveRecord::TestCase
@original_verbose = ActiveRecord::Migration.verbose
ActiveRecord::Migration.verbose = false
@connection = ActiveRecord::Base.connection
- ActiveRecord::SchemaMigration.drop_table
+ @schema_migration = @connection.schema_migration
+ @schema_migration.drop_table
end
teardown do
@@ -18,21 +19,21 @@ class ActiveRecordSchemaTest < ActiveRecord::TestCase
@connection.drop_table :nep_schema_migrations rescue nil
@connection.drop_table :has_timestamps rescue nil
@connection.drop_table :multiple_indexes rescue nil
- ActiveRecord::SchemaMigration.delete_all rescue nil
+ @schema_migration.delete_all rescue nil
ActiveRecord::Migration.verbose = @original_verbose
end
def test_has_primary_key
old_primary_key_prefix_type = ActiveRecord::Base.primary_key_prefix_type
ActiveRecord::Base.primary_key_prefix_type = :table_name_with_underscore
- assert_equal "version", ActiveRecord::SchemaMigration.primary_key
+ assert_equal "version", @schema_migration.primary_key
- ActiveRecord::SchemaMigration.create_table
- assert_difference "ActiveRecord::SchemaMigration.count", 1 do
- ActiveRecord::SchemaMigration.create version: 12
+ @schema_migration.create_table
+ assert_difference "@schema_migration.count", 1 do
+ @schema_migration.create version: 12
end
ensure
- ActiveRecord::SchemaMigration.drop_table
+ @schema_migration.drop_table
ActiveRecord::Base.primary_key_prefix_type = old_primary_key_prefix_type
end
@@ -54,7 +55,7 @@ class ActiveRecordSchemaTest < ActiveRecord::TestCase
def test_schema_define_with_table_name_prefix
old_table_name_prefix = ActiveRecord::Base.table_name_prefix
ActiveRecord::Base.table_name_prefix = "nep_"
- ActiveRecord::SchemaMigration.reset_table_name
+ @schema_migration.reset_table_name
ActiveRecord::InternalMetadata.reset_table_name
ActiveRecord::Schema.define(version: 7) do
create_table :fruits do |t|
@@ -67,7 +68,7 @@ class ActiveRecordSchemaTest < ActiveRecord::TestCase
assert_equal 7, @connection.migration_context.current_version
ensure
ActiveRecord::Base.table_name_prefix = old_table_name_prefix
- ActiveRecord::SchemaMigration.reset_table_name
+ @schema_migration.reset_table_name
ActiveRecord::InternalMetadata.reset_table_name
end
@@ -89,10 +90,10 @@ class ActiveRecordSchemaTest < ActiveRecord::TestCase
end
def test_normalize_version
- assert_equal "118", ActiveRecord::SchemaMigration.normalize_migration_number("0000118")
- assert_equal "002", ActiveRecord::SchemaMigration.normalize_migration_number("2")
- assert_equal "017", ActiveRecord::SchemaMigration.normalize_migration_number("0017")
- assert_equal "20131219224947", ActiveRecord::SchemaMigration.normalize_migration_number("20131219224947")
+ assert_equal "118", @schema_migration.normalize_migration_number("0000118")
+ assert_equal "002", @schema_migration.normalize_migration_number("2")
+ assert_equal "017", @schema_migration.normalize_migration_number("0017")
+ assert_equal "20131219224947", @schema_migration.normalize_migration_number("20131219224947")
end
def test_schema_load_with_multiple_indexes_for_column_of_different_names
diff --git a/activerecord/test/cases/arel/attributes/attribute_test.rb b/activerecord/test/cases/arel/attributes/attribute_test.rb
index c7bd0a053b..7ebb90c6fd 100644
--- a/activerecord/test/cases/arel/attributes/attribute_test.rb
+++ b/activerecord/test/cases/arel/attributes/attribute_test.rb
@@ -638,6 +638,18 @@ module Arel
)
end
+ if Gem::Version.new("2.7.0") <= Gem::Version.new(RUBY_VERSION)
+ it "can be constructed with a range implicitly starting at Infinity" do
+ attribute = Attribute.new nil, nil
+ node = attribute.between(eval("..0")) # eval for backwards compatibility
+
+ node.must_equal Nodes::LessThanOrEqual.new(
+ attribute,
+ Nodes::Casted.new(0, attribute)
+ )
+ end
+ end
+
if Gem::Version.new("2.6.0") <= Gem::Version.new(RUBY_VERSION)
it "can be constructed with a range implicitly ending at Infinity" do
attribute = Attribute.new nil, nil
@@ -839,6 +851,18 @@ module Arel
)
end
+ if Gem::Version.new("2.7.0") <= Gem::Version.new(RUBY_VERSION)
+ it "can be constructed with a range implicitly starting at Infinity" do
+ attribute = Attribute.new nil, nil
+ node = attribute.not_between(eval("..0")) # eval for backwards compatibility
+
+ node.must_equal Nodes::GreaterThan.new(
+ attribute,
+ Nodes::Casted.new(0, attribute)
+ )
+ end
+ end
+
if Gem::Version.new("2.6.0") <= Gem::Version.new(RUBY_VERSION)
it "can be constructed with a range implicitly ending at Infinity" do
attribute = Attribute.new nil, nil
diff --git a/activerecord/test/cases/arel/attributes_test.rb b/activerecord/test/cases/arel/attributes_test.rb
index b00af4bd29..1712633ae9 100644
--- a/activerecord/test/cases/arel/attributes_test.rb
+++ b/activerecord/test/cases/arel/attributes_test.rb
@@ -23,46 +23,5 @@ module Arel
assert_equal 2, array.uniq.size
end
end
-
- describe "for" do
- it "deals with unknown column types" do
- column = Struct.new(:type).new :crazy
- Attributes.for(column).must_equal Attributes::Undefined
- end
-
- it "returns the correct constant for strings" do
- [:string, :text, :binary].each do |type|
- column = Struct.new(:type).new type
- Attributes.for(column).must_equal Attributes::String
- end
- end
-
- it "returns the correct constant for ints" do
- column = Struct.new(:type).new :integer
- Attributes.for(column).must_equal Attributes::Integer
- end
-
- it "returns the correct constant for floats" do
- column = Struct.new(:type).new :float
- Attributes.for(column).must_equal Attributes::Float
- end
-
- it "returns the correct constant for decimals" do
- column = Struct.new(:type).new :decimal
- Attributes.for(column).must_equal Attributes::Decimal
- end
-
- it "returns the correct constant for boolean" do
- column = Struct.new(:type).new :boolean
- Attributes.for(column).must_equal Attributes::Boolean
- end
-
- it "returns the correct constant for time" do
- [:date, :datetime, :timestamp, :time].each do |type|
- column = Struct.new(:type).new type
- Attributes.for(column).must_equal Attributes::Time
- end
- end
- end
end
end
diff --git a/activerecord/test/cases/arel/nodes/node_test.rb b/activerecord/test/cases/arel/nodes/node_test.rb
index f4f07ef2c5..f1e0ce1ea9 100644
--- a/activerecord/test/cases/arel/nodes/node_test.rb
+++ b/activerecord/test/cases/arel/nodes/node_test.rb
@@ -18,24 +18,5 @@ module Arel
assert klass.ancestors.include?(Nodes::Node), klass.name
end
end
-
- def test_each
- list = []
- node = Nodes::Node.new
- node.each { |n| list << n }
- assert_equal [node], list
- end
-
- def test_generator
- list = []
- node = Nodes::Node.new
- node.each.each { |n| list << n }
- assert_equal [node], list
- end
-
- def test_enumerable
- node = Nodes::Node.new
- assert_kind_of Enumerable, node
- end
end
end
diff --git a/activerecord/test/cases/arel/select_manager_test.rb b/activerecord/test/cases/arel/select_manager_test.rb
index e6c49cd429..526fe6787a 100644
--- a/activerecord/test/cases/arel/select_manager_test.rb
+++ b/activerecord/test/cases/arel/select_manager_test.rb
@@ -369,16 +369,6 @@ module Arel
mgr = table.from
assert mgr.ast
end
-
- it "should allow orders to work when the ast is grepped" do
- table = Table.new :users
- mgr = table.from
- mgr.project Arel.sql "*"
- mgr.from table
- mgr.orders << Arel::Nodes::Ascending.new(Arel.sql("foo"))
- mgr.ast.grep(Arel::Nodes::OuterJoin)
- mgr.to_sql.must_be_like %{ SELECT * FROM "users" ORDER BY foo ASC }
- end
end
describe "taken" do
diff --git a/activerecord/test/cases/arel/visitors/depth_first_test.rb b/activerecord/test/cases/arel/visitors/depth_first_test.rb
deleted file mode 100644
index 106be2311d..0000000000
--- a/activerecord/test/cases/arel/visitors/depth_first_test.rb
+++ /dev/null
@@ -1,276 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "../helper"
-
-module Arel
- module Visitors
- class TestDepthFirst < Arel::Test
- Collector = Struct.new(:calls) do
- def call(object)
- calls << object
- end
- end
-
- def setup
- @collector = Collector.new []
- @visitor = Visitors::DepthFirst.new @collector
- end
-
- def test_raises_with_object
- assert_raises(TypeError) do
- @visitor.accept(Object.new)
- end
- end
-
-
- # unary ops
- [
- Arel::Nodes::Not,
- Arel::Nodes::Group,
- Arel::Nodes::On,
- Arel::Nodes::Grouping,
- Arel::Nodes::Offset,
- Arel::Nodes::Ordering,
- Arel::Nodes::StringJoin,
- Arel::Nodes::UnqualifiedColumn,
- Arel::Nodes::ValuesList,
- Arel::Nodes::Limit,
- Arel::Nodes::Else,
- ].each do |klass|
- define_method("test_#{klass.name.gsub('::', '_')}") do
- op = klass.new(:a)
- @visitor.accept op
- assert_equal [:a, op], @collector.calls
- end
- end
-
- # functions
- [
- Arel::Nodes::Exists,
- Arel::Nodes::Avg,
- Arel::Nodes::Min,
- Arel::Nodes::Max,
- Arel::Nodes::Sum,
- ].each do |klass|
- define_method("test_#{klass.name.gsub('::', '_')}") do
- func = klass.new(:a, "b")
- @visitor.accept func
- assert_equal [:a, "b", false, func], @collector.calls
- end
- end
-
- def test_named_function
- func = Arel::Nodes::NamedFunction.new(:a, :b, "c")
- @visitor.accept func
- assert_equal [:a, :b, false, "c", func], @collector.calls
- end
-
- def test_lock
- lock = Nodes::Lock.new true
- @visitor.accept lock
- assert_equal [lock], @collector.calls
- end
-
- def test_count
- count = Nodes::Count.new :a, :b, "c"
- @visitor.accept count
- assert_equal [:a, "c", :b, count], @collector.calls
- end
-
- def test_inner_join
- join = Nodes::InnerJoin.new :a, :b
- @visitor.accept join
- assert_equal [:a, :b, join], @collector.calls
- end
-
- def test_full_outer_join
- join = Nodes::FullOuterJoin.new :a, :b
- @visitor.accept join
- assert_equal [:a, :b, join], @collector.calls
- end
-
- def test_outer_join
- join = Nodes::OuterJoin.new :a, :b
- @visitor.accept join
- assert_equal [:a, :b, join], @collector.calls
- end
-
- def test_right_outer_join
- join = Nodes::RightOuterJoin.new :a, :b
- @visitor.accept join
- assert_equal [:a, :b, join], @collector.calls
- end
-
- def test_comment
- comment = Nodes::Comment.new ["foo"]
- @visitor.accept comment
- assert_equal ["foo", ["foo"], comment], @collector.calls
- end
-
- [
- Arel::Nodes::Assignment,
- Arel::Nodes::Between,
- Arel::Nodes::Concat,
- Arel::Nodes::DoesNotMatch,
- Arel::Nodes::Equality,
- Arel::Nodes::GreaterThan,
- Arel::Nodes::GreaterThanOrEqual,
- Arel::Nodes::In,
- Arel::Nodes::LessThan,
- Arel::Nodes::LessThanOrEqual,
- Arel::Nodes::Matches,
- Arel::Nodes::NotEqual,
- Arel::Nodes::NotIn,
- Arel::Nodes::Or,
- Arel::Nodes::TableAlias,
- Arel::Nodes::As,
- Arel::Nodes::DeleteStatement,
- Arel::Nodes::JoinSource,
- Arel::Nodes::When,
- ].each do |klass|
- define_method("test_#{klass.name.gsub('::', '_')}") do
- binary = klass.new(:a, :b)
- @visitor.accept binary
- assert_equal [:a, :b, binary], @collector.calls
- end
- end
-
- def test_Arel_Nodes_InfixOperation
- binary = Arel::Nodes::InfixOperation.new(:o, :a, :b)
- @visitor.accept binary
- assert_equal [:a, :b, binary], @collector.calls
- end
-
- # N-ary
- [
- Arel::Nodes::And,
- ].each do |klass|
- define_method("test_#{klass.name.gsub('::', '_')}") do
- binary = klass.new([:a, :b, :c])
- @visitor.accept binary
- assert_equal [:a, :b, :c, binary], @collector.calls
- end
- end
-
- [
- Arel::Attributes::Integer,
- Arel::Attributes::Float,
- Arel::Attributes::String,
- Arel::Attributes::Time,
- Arel::Attributes::Boolean,
- Arel::Attributes::Attribute
- ].each do |klass|
- define_method("test_#{klass.name.gsub('::', '_')}") do
- binary = klass.new(:a, :b)
- @visitor.accept binary
- assert_equal [:a, :b, binary], @collector.calls
- end
- end
-
- def test_table
- relation = Arel::Table.new(:users)
- @visitor.accept relation
- assert_equal ["users", relation], @collector.calls
- end
-
- def test_array
- node = Nodes::Or.new(:a, :b)
- list = [node]
- @visitor.accept list
- assert_equal [:a, :b, node, list], @collector.calls
- end
-
- def test_set
- node = Nodes::Or.new(:a, :b)
- set = Set.new([node])
- @visitor.accept set
- assert_equal [:a, :b, node, set], @collector.calls
- end
-
- def test_hash
- node = Nodes::Or.new(:a, :b)
- hash = { node => node }
- @visitor.accept hash
- assert_equal [:a, :b, node, :a, :b, node, hash], @collector.calls
- end
-
- def test_update_statement
- stmt = Nodes::UpdateStatement.new
- stmt.relation = :a
- stmt.values << :b
- stmt.wheres << :c
- stmt.orders << :d
- stmt.limit = :e
-
- @visitor.accept stmt
- assert_equal [:a, :b, stmt.values, :c, stmt.wheres, :d, stmt.orders,
- :e, stmt], @collector.calls
- end
-
- def test_select_core
- core = Nodes::SelectCore.new
- core.projections << :a
- core.froms = :b
- core.wheres << :c
- core.groups << :d
- core.windows << :e
- core.havings << :f
-
- @visitor.accept core
- assert_equal [
- :a, core.projections,
- :b, [],
- core.source,
- :c, core.wheres,
- :d, core.groups,
- :e, core.windows,
- :f, core.havings,
- core], @collector.calls
- end
-
- def test_select_statement
- ss = Nodes::SelectStatement.new
- ss.cores.replace [:a]
- ss.orders << :b
- ss.limit = :c
- ss.lock = :d
- ss.offset = :e
-
- @visitor.accept ss
- assert_equal [
- :a, ss.cores,
- :b, ss.orders,
- :c,
- :d,
- :e,
- ss], @collector.calls
- end
-
- def test_insert_statement
- stmt = Nodes::InsertStatement.new
- stmt.relation = :a
- stmt.columns << :b
- stmt.values = :c
-
- @visitor.accept stmt
- assert_equal [:a, :b, stmt.columns, :c, stmt], @collector.calls
- end
-
- def test_case
- node = Arel::Nodes::Case.new
- node.case = :a
- node.conditions << :b
- node.default = :c
-
- @visitor.accept node
- assert_equal [:a, :b, node.conditions, :c, node], @collector.calls
- end
-
- def test_node
- node = Nodes::Node.new
- @visitor.accept node
- assert_equal [node], @collector.calls
- end
- end
- end
-end
diff --git a/activerecord/test/cases/arel/visitors/dispatch_contamination_test.rb b/activerecord/test/cases/arel/visitors/dispatch_contamination_test.rb
index a07a1a050a..36f9eb49a2 100644
--- a/activerecord/test/cases/arel/visitors/dispatch_contamination_test.rb
+++ b/activerecord/test/cases/arel/visitors/dispatch_contamination_test.rb
@@ -48,7 +48,13 @@ module Arel
node = Nodes::Union.new(Nodes::True.new, Nodes::False.new)
assert_equal "( TRUE UNION FALSE )", node.to_sql
- node.first # from Nodes::Node's Enumerable mixin
+ visitor = Class.new(Visitor) {
+ def visit_Arel_Nodes_Union(o); end
+ alias :visit_Arel_Nodes_True :visit_Arel_Nodes_Union
+ alias :visit_Arel_Nodes_False :visit_Arel_Nodes_Union
+ }.new
+
+ visitor.accept(node)
assert_equal "( TRUE UNION FALSE )", node.to_sql
end
diff --git a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb
index 49f754be63..cbe48a374f 100644
--- a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb
+++ b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb
@@ -37,8 +37,8 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
def test_eager_association_loading_with_hmt_does_not_table_name_collide_when_joining_associations
authors = Author.joins(:posts).eager_load(:comments).where(posts: { tags_count: 1 }).order(:id).to_a
- assert_equal 3, assert_no_queries { authors.size }
- assert_equal 10, assert_no_queries { authors[0].comments.size }
+ assert_equal 3, assert_queries(0) { authors.size }
+ assert_equal 10, assert_queries(0) { authors[0].comments.size }
end
def test_eager_association_loading_grafts_stashed_associations_to_correct_parent
@@ -103,14 +103,14 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
firms = Firm.all.merge!(includes: { account: { firm: :account } }, order: "companies.id").to_a
assert_equal 2, firms.size
assert_equal firms.first.account, firms.first.account.firm.account
- assert_equal companies(:first_firm).account, assert_no_queries { firms.first.account.firm.account }
- assert_equal companies(:first_firm).account.firm.account, assert_no_queries { firms.first.account.firm.account }
+ assert_equal companies(:first_firm).account, assert_queries(0) { firms.first.account.firm.account }
+ assert_equal companies(:first_firm).account.firm.account, assert_queries(0) { firms.first.account.firm.account }
end
def test_eager_association_loading_with_has_many_sti
topics = Topic.all.merge!(includes: :replies, order: "topics.id").to_a
first, second, = topics(:first).replies.size, topics(:second).replies.size
- assert_no_queries do
+ assert_queries(0) do
assert_equal first, topics[0].replies.size
assert_equal second, topics[1].replies.size
end
@@ -131,13 +131,13 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
replies = Reply.all.merge!(includes: :topic, order: "topics.id").to_a
assert_includes replies, topics(:second)
assert_not_includes replies, topics(:first)
- assert_equal topics(:first), assert_no_queries { replies.first.topic }
+ assert_equal topics(:first), assert_queries(0) { replies.first.topic }
end
def test_eager_association_loading_with_multiple_stis_and_order
author = Author.all.merge!(includes: { posts: [ :special_comments, :very_special_comment ] }, order: ["authors.name", "comments.body", "very_special_comments_posts.body"], where: "posts.id = 4").first
assert_equal authors(:david), author
- assert_no_queries do
+ assert_queries(0) do
author.posts.first.special_comments
author.posts.first.very_special_comment
end
@@ -146,7 +146,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
def test_eager_association_loading_of_stis_with_multiple_references
authors = Author.all.merge!(includes: { posts: { special_comments: { post: [ :special_comments, :very_special_comment ] } } }, order: "comments.body, very_special_comments_posts.body", where: "posts.id = 4").to_a
assert_equal [authors(:david)], authors
- assert_no_queries do
+ assert_queries(0) do
authors.first.posts.first.special_comments.first.post.special_comments
authors.first.posts.first.special_comments.first.post.very_special_comment
end
@@ -155,14 +155,14 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
def test_eager_association_loading_where_first_level_returns_nil
authors = Author.all.merge!(includes: { post_about_thinking: :comments }, order: "authors.id DESC").to_a
assert_equal [authors(:bob), authors(:mary), authors(:david)], authors
- assert_no_queries do
+ assert_queries(0) do
authors[2].post_about_thinking.comments.first
end
end
def test_preload_through_missing_records
post = Post.where.not(author_id: Author.select(:id)).preload(author: { comments: :post }).first!
- assert_no_queries { assert_nil post.author }
+ assert_queries(0) { assert_nil post.author }
end
def test_eager_association_loading_with_missing_first_record
@@ -172,12 +172,12 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
def test_eager_association_loading_with_recursive_cascading_four_levels_has_many_through
source = Vertex.all.merge!(includes: { sinks: { sinks: { sinks: :sinks } } }, order: "vertices.id").first
- assert_equal vertices(:vertex_4), assert_no_queries { source.sinks.first.sinks.first.sinks.first }
+ assert_equal vertices(:vertex_4), assert_queries(0) { source.sinks.first.sinks.first.sinks.first }
end
def test_eager_association_loading_with_recursive_cascading_four_levels_has_and_belongs_to_many
sink = Vertex.all.merge!(includes: { sources: { sources: { sources: :sources } } }, order: "vertices.id DESC").first
- assert_equal vertices(:vertex_1), assert_no_queries { sink.sources.first.sources.first.sources.first.sources.first }
+ assert_equal vertices(:vertex_1), assert_queries(0) { sink.sources.first.sources.first.sources.first.sources.first }
end
def test_eager_association_loading_with_cascaded_interdependent_one_level_and_two_levels
diff --git a/activerecord/test/cases/associations/eager_load_nested_include_test.rb b/activerecord/test/cases/associations/eager_load_nested_include_test.rb
index 849939de75..9be21b23db 100644
--- a/activerecord/test/cases/associations/eager_load_nested_include_test.rb
+++ b/activerecord/test/cases/associations/eager_load_nested_include_test.rb
@@ -14,6 +14,7 @@ module Remembered
included do
after_create :remember
+
private
def remember; self.class.remembered << self; end
end
diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb
index 49bcb1d010..cb46f9e053 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -101,6 +101,17 @@ class EagerAssociationTest < ActiveRecord::TestCase
assert_equal [taggings(:normal_comment_rating)], rating.taggings_without_tag
end
+ def test_loading_association_with_string_joins
+ rating = Rating.first
+ assert_equal [taggings(:normal_comment_rating)], rating.taggings_with_no_tag
+
+ rating = Rating.preload(:taggings_with_no_tag).first
+ assert_equal [taggings(:normal_comment_rating)], rating.taggings_with_no_tag
+
+ rating = Rating.eager_load(:taggings_with_no_tag).first
+ assert_equal [taggings(:normal_comment_rating)], rating.taggings_with_no_tag
+ end
+
def test_loading_with_scope_including_joins
member = Member.first
assert_equal members(:groucho), member
@@ -512,7 +523,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_eager_association_loading_with_belongs_to_and_order_string_with_quoted_table_name
quoted_posts_id = Comment.connection.quote_table_name("posts") + "." + Comment.connection.quote_column_name("id")
assert_nothing_raised do
- Comment.includes(:post).references(:posts).order(Arel.sql(quoted_posts_id))
+ Comment.includes(:post).references(:posts).order(quoted_posts_id)
end
end
@@ -778,7 +789,6 @@ class EagerAssociationTest < ActiveRecord::TestCase
.where("comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'")
.references(:comments)
.scoping do
-
posts = authors(:david).posts.limit(2).to_a
assert_equal 2, posts.size
end
@@ -787,7 +797,6 @@ class EagerAssociationTest < ActiveRecord::TestCase
.where("authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')")
.references(:authors, :comments)
.scoping do
-
count = Post.limit(2).count
assert_equal count, posts.size
end
@@ -959,14 +968,14 @@ class EagerAssociationTest < ActiveRecord::TestCase
posts(:thinking, :sti_comments),
Post.all.merge!(
includes: [:author, :comments], where: { "authors.name" => "David" },
- order: Arel.sql("UPPER(posts.title)"), limit: 2, offset: 1
+ order: "UPPER(posts.title)", limit: 2, offset: 1
).to_a
)
assert_equal(
posts(:sti_post_and_comments, :sti_comments),
Post.all.merge!(
includes: [:author, :comments], where: { "authors.name" => "David" },
- order: Arel.sql("UPPER(posts.title) DESC"), limit: 2, offset: 1
+ order: "UPPER(posts.title) DESC", limit: 2, offset: 1
).to_a
)
end
@@ -976,14 +985,14 @@ class EagerAssociationTest < ActiveRecord::TestCase
posts(:thinking, :sti_comments),
Post.all.merge!(
includes: [:author, :comments], where: { "authors.name" => "David" },
- order: [Arel.sql("UPPER(posts.title)"), "posts.id"], limit: 2, offset: 1
+ order: ["UPPER(posts.title)", "posts.id"], limit: 2, offset: 1
).to_a
)
assert_equal(
posts(:sti_post_and_comments, :sti_comments),
Post.all.merge!(
includes: [:author, :comments], where: { "authors.name" => "David" },
- order: [Arel.sql("UPPER(posts.title) DESC"), "posts.id"], limit: 2, offset: 1
+ order: ["UPPER(posts.title) DESC", "posts.id"], limit: 2, offset: 1
).to_a
)
end
@@ -1234,7 +1243,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
Post.all.merge!(select: "posts.*, authors.name as author_name", includes: :comments, joins: :author, order: "posts.id").to_a
end
assert_equal "David", posts[0].author_name
- assert_equal posts(:welcome).comments, assert_no_queries { posts[0].comments }
+ assert_equal posts(:welcome).comments.sort_by(&:id), assert_no_queries { posts[0].comments.sort_by(&:id) }
end
def test_eager_loading_with_conditions_on_join_model_preloads
@@ -1246,8 +1255,8 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
def test_preload_belongs_to_uses_exclusive_scope
- people = Person.males.merge(includes: :primary_contact).to_a
- assert_not_equal people.length, 0
+ people = Person.males.includes(:primary_contact).to_a
+ assert_equal 2, people.length
people.each do |person|
assert_no_queries { assert_not_nil person.primary_contact }
assert_equal Person.find(person.id).primary_contact, person.primary_contact
@@ -1256,16 +1265,17 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_preload_has_many_uses_exclusive_scope
people = Person.males.includes(:agents).to_a
+ assert_equal 2, people.length
people.each do |person|
- assert_equal Person.find(person.id).agents, person.agents
+ assert_equal Person.find(person.id).agents.sort_by(&:id), person.agents.sort_by(&:id)
end
end
def test_preload_has_many_using_primary_key
- expected = Firm.first.clients_using_primary_key.to_a
+ expected = Firm.first.clients_using_primary_key.sort_by(&:id)
firm = Firm.includes(:clients_using_primary_key).first
assert_no_queries do
- assert_equal expected, firm.clients_using_primary_key
+ assert_equal expected, firm.clients_using_primary_key.sort_by(&:id)
end
end
diff --git a/activerecord/test/cases/associations/extension_test.rb b/activerecord/test/cases/associations/extension_test.rb
index 5e6e3e8ec4..604a52655c 100644
--- a/activerecord/test/cases/associations/extension_test.rb
+++ b/activerecord/test/cases/associations/extension_test.rb
@@ -87,7 +87,6 @@ class AssociationsExtensionsTest < ActiveRecord::TestCase
end
private
-
def extend!(model)
ActiveRecord::Associations::Builder::HasMany.send(:define_extensions, model, :association_name) { }
end
diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
index fe8bdd03ba..25cfa0a723 100644
--- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
@@ -313,10 +313,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
def test_build
devel = Developer.find(1)
- # Load schema information so we don't query below if running just this test.
- Project.define_attribute_methods
-
- proj = assert_no_queries { devel.projects.build("name" => "Projekt") }
+ proj = assert_queries(0) { devel.projects.build("name" => "Projekt") }
assert_not_predicate devel.projects, :loaded?
assert_equal devel.projects.last, proj
@@ -332,10 +329,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
def test_new_aliased_to_build
devel = Developer.find(1)
- # Load schema information so we don't query below if running just this test.
- Project.define_attribute_methods
-
- proj = assert_no_queries { devel.projects.new("name" => "Projekt") }
+ proj = assert_queries(0) { devel.projects.new("name" => "Projekt") }
assert_not_predicate devel.projects, :loaded?
assert_equal devel.projects.last, proj
@@ -556,7 +550,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
developer = project.developers.first
- assert_no_queries do
+ assert_queries(0) do
assert_predicate project.developers, :loaded?
assert_includes project.developers, developer
end
@@ -751,7 +745,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
def test_get_ids_for_loaded_associations
developer = developers(:david)
developer.projects.reload
- assert_no_queries do
+ assert_queries(0) do
developer.project_ids
developer.project_ids
end
@@ -879,7 +873,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
def test_has_and_belongs_to_many_associations_on_new_records_use_null_relations
projects = Developer.new.projects
- assert_no_queries do
+ assert_queries(0) do
assert_equal [], projects
assert_equal [], projects.where(title: "omg")
assert_equal [], projects.pluck(:title)
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index 32285f269a..6c54c2f1cd 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -468,10 +468,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
company = companies(:first_firm)
new_clients = []
- # Load schema information so we don't query below if running just this test.
- Client.define_attribute_methods
-
- assert_no_queries do
+ assert_queries(0) do
new_clients << company.clients_of_firm.build(name: "Another Client")
new_clients << company.clients_of_firm.build(name: "Another Client II")
new_clients << company.clients_of_firm.build(name: "Another Client III")
@@ -492,10 +489,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
company = companies(:first_firm)
new_clients = []
- # Load schema information so we don't query below if running just this test.
- Client.define_attribute_methods
-
- assert_no_queries do
+ assert_queries(0) do
new_clients << company.clients_of_firm.build(name: "Another Client")
new_clients << company.clients_of_firm.build(name: "Another Client II")
new_clients << company.clients_of_firm.build(name: "Another Client III")
@@ -1015,11 +1009,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_transactions_when_adding_to_new_record
- # Load schema information so we don't query below if running just this test.
- Client.define_attribute_methods
-
firm = Firm.new
- assert_no_queries do
+ assert_queries(0) do
firm.clients_of_firm.concat(Client.new("name" => "Natural Company"))
end
end
@@ -1034,10 +1025,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_new_aliased_to_build
company = companies(:first_firm)
- # Load schema information so we don't query below if running just this test.
- Client.define_attribute_methods
-
- new_client = assert_no_queries { company.clients_of_firm.new("name" => "Another Client") }
+ new_client = assert_queries(0) { company.clients_of_firm.new("name" => "Another Client") }
assert_not_predicate company.clients_of_firm, :loaded?
assert_equal "Another Client", new_client.name
@@ -1048,10 +1036,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_build
company = companies(:first_firm)
- # Load schema information so we don't query below if running just this test.
- Client.define_attribute_methods
-
- new_client = assert_no_queries { company.clients_of_firm.build("name" => "Another Client") }
+ new_client = assert_queries(0) { company.clients_of_firm.build("name" => "Another Client") }
assert_not_predicate company.clients_of_firm, :loaded?
assert_equal "Another Client", new_client.name
@@ -1109,10 +1094,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_build_many
company = companies(:first_firm)
- # Load schema information so we don't query below if running just this test.
- Client.define_attribute_methods
-
- new_clients = assert_no_queries { company.clients_of_firm.build([{ "name" => "Another Client" }, { "name" => "Another Client II" }]) }
+ new_clients = assert_queries(0) { company.clients_of_firm.build([{ "name" => "Another Client" }, { "name" => "Another Client II" }]) }
assert_equal 2, new_clients.size
end
@@ -1127,10 +1109,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal 1, first_topic.replies.length
- # Load schema information so we don't query below if running just this test.
- Reply.define_attribute_methods
-
- assert_no_queries do
+ assert_queries(0) do
first_topic.replies.build(title: "Not saved", content: "Superstars")
assert_equal 2, first_topic.replies.size
end
@@ -1141,10 +1120,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_build_via_block
company = companies(:first_firm)
- # Load schema information so we don't query below if running just this test.
- Client.define_attribute_methods
-
- new_client = assert_no_queries { company.clients_of_firm.build { |client| client.name = "Another Client" } }
+ new_client = assert_queries(0) { company.clients_of_firm.build { |client| client.name = "Another Client" } }
assert_not_predicate company.clients_of_firm, :loaded?
assert_equal "Another Client", new_client.name
@@ -1155,10 +1131,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_build_many_via_block
company = companies(:first_firm)
- # Load schema information so we don't query below if running just this test.
- Client.define_attribute_methods
-
- new_clients = assert_no_queries do
+ new_clients = assert_queries(0) do
company.clients_of_firm.build([{ "name" => "Another Client" }, { "name" => "Another Client II" }]) do |client|
client.name = "changed"
end
@@ -1447,11 +1420,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_transaction_when_deleting_new_record
- # Load schema information so we don't query below if running just this test.
- Client.define_attribute_methods
-
firm = Firm.new
- assert_no_queries do
+ assert_queries(0) do
client = Client.new("name" => "New Client")
firm.clients_of_firm << client
firm.clients_of_firm.destroy(client)
@@ -1966,11 +1936,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_transactions_when_replacing_on_new_record
- # Load schema information so we don't query below if running just this test.
- Client.define_attribute_methods
-
firm = Firm.new
- assert_no_queries do
+ assert_queries(0) do
firm.clients_of_firm = [Client.new("name" => "New Client")]
end
end
@@ -2024,11 +1991,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_get_ids_for_association_on_new_record_does_not_try_to_find_records
- # Load schema information so we don't query below if running just this test.
- companies(:first_client).contract_ids
-
company = Company.new
- assert_no_queries do
+ assert_queries(0) do
company.contract_ids
end
@@ -2711,18 +2675,22 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
bulb = Bulb.create!
tyre = Tyre.create!
- car = Car.create! do |c|
+ car = Car.create!(name: "honda") do |c|
c.bulbs << bulb
c.tyres << tyre
end
+ assert_equal [nil, "honda"], car.saved_change_to_name
+
assert_equal 1, car.bulbs.count
assert_equal 1, car.tyres.count
end
test "associations replace in memory when records have the same id" do
bulb = Bulb.create!
- car = Car.create!(bulbs: [bulb])
+ car = Car.create!(name: "honda", bulbs: [bulb])
+
+ assert_equal [nil, "honda"], car.saved_change_to_name
new_bulb = Bulb.find(bulb.id)
new_bulb.name = "foo"
@@ -2733,7 +2701,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
test "in memory replacement executes no queries" do
bulb = Bulb.create!
- car = Car.create!(bulbs: [bulb])
+ car = Car.create!(name: "honda", bulbs: [bulb])
+
+ assert_equal [nil, "honda"], car.saved_change_to_name
new_bulb = Bulb.find(bulb.id)
@@ -2765,7 +2735,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
test "in memory replacements sets inverse instance" do
bulb = Bulb.create!
- car = Car.create!(bulbs: [bulb])
+ car = Car.create!(name: "honda", bulbs: [bulb])
+
+ assert_equal [nil, "honda"], car.saved_change_to_name
new_bulb = Bulb.find(bulb.id)
car.bulbs = [new_bulb]
@@ -2785,7 +2757,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
test "in memory replacement maintains order" do
first_bulb = Bulb.create!
second_bulb = Bulb.create!
- car = Car.create!(bulbs: [first_bulb, second_bulb])
+ car = Car.create!(name: "honda", bulbs: [first_bulb, second_bulb])
+
+ assert_equal [nil, "honda"], car.saved_change_to_name
same_bulb = Bulb.find(first_bulb.id)
car.bulbs = [second_bulb, same_bulb]
@@ -2958,8 +2932,12 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal [], reference.ideal_jobs
end
- private
+ def test_has_many_preloading_with_duplicate_records
+ posts = Post.joins(:comments).preload(:comments).to_a
+ assert_equal [1, 2], posts.first.comments.map(&:id)
+ end
+ private
def force_signal37_to_load_all_clients_of_firm
companies(:first_firm).clients_of_firm.load_target
end
diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb
index 0ab99aa6cd..6faa9664f7 100644
--- a/activerecord/test/cases/associations/has_many_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb
@@ -58,6 +58,14 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
assert_equal preloaded, Marshal.load(Marshal.dump(preloaded))
end
+ def test_through_association_with_joins
+ assert_equal [comments(:eager_other_comment1)], authors(:mary).comments.merge(Post.joins(:comments))
+ end
+
+ def test_through_association_with_left_joins
+ assert_equal [comments(:eager_other_comment1)], authors(:mary).comments.merge(Post.left_joins(:comments))
+ end
+
def test_preload_with_nested_association
posts = Post.preload(:author, :author_favorites_with_scope).to_a
@@ -299,10 +307,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
assert_queries(1) { posts(:thinking) }
new_person = nil # so block binding catches it
- # Load schema information so we don't query below if running just this test.
- Person.define_attribute_methods
-
- assert_no_queries do
+ assert_queries(0) do
new_person = Person.new first_name: "bob"
end
@@ -322,10 +327,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
def test_associate_new_by_building
assert_queries(1) { posts(:thinking) }
- # Load schema information so we don't query below if running just this test.
- Person.define_attribute_methods
-
- assert_no_queries do
+ assert_queries(0) do
posts(:thinking).people.build(first_name: "Bob")
posts(:thinking).people.new(first_name: "Ted")
end
diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb
index fd727757a3..3ef25c7027 100644
--- a/activerecord/test/cases/associations/has_one_associations_test.rb
+++ b/activerecord/test/cases/associations/has_one_associations_test.rb
@@ -256,11 +256,8 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
end
def test_build_association_dont_create_transaction
- # Load schema information so we don't query below if running just this test.
- Account.define_attribute_methods
-
firm = Firm.new
- assert_no_queries do
+ assert_queries(0) do
firm.build_account
end
end
diff --git a/activerecord/test/cases/associations/nested_through_associations_test.rb b/activerecord/test/cases/associations/nested_through_associations_test.rb
index 35da74102d..8d74ae3961 100644
--- a/activerecord/test/cases/associations/nested_through_associations_test.rb
+++ b/activerecord/test/cases/associations/nested_through_associations_test.rb
@@ -626,7 +626,6 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase
end
private
-
def assert_includes_and_joins_equal(query, expected, association)
actual = assert_queries(1) { query.joins(association).to_a.uniq }
assert_equal expected, actual
diff --git a/activerecord/test/cases/associations/required_test.rb b/activerecord/test/cases/associations/required_test.rb
index c7a78e6bc4..db7f945a36 100644
--- a/activerecord/test/cases/associations/required_test.rb
+++ b/activerecord/test/cases/associations/required_test.rb
@@ -117,7 +117,6 @@ class RequiredAssociationsTest < ActiveRecord::TestCase
end
private
-
def subclass_of(klass, &block)
subclass = Class.new(klass, &block)
def subclass.name
diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb
index 5cbe5d796d..71b5407dcc 100644
--- a/activerecord/test/cases/attribute_methods_test.rb
+++ b/activerecord/test/cases/attribute_methods_test.rb
@@ -1087,7 +1087,6 @@ class AttributeMethodsTest < ActiveRecord::TestCase
end
private
-
def new_topic_like_ar_class(&block)
klass = Class.new(ActiveRecord::Base) do
self.table_name = "topics"
diff --git a/activerecord/test/cases/attributes_test.rb b/activerecord/test/cases/attributes_test.rb
index a6fb9f0af7..d6ac5a1057 100644
--- a/activerecord/test/cases/attributes_test.rb
+++ b/activerecord/test/cases/attributes_test.rb
@@ -241,7 +241,7 @@ module ActiveRecord
test "attributes not backed by database columns are always initialized" do
OverloadedType.create!
- model = OverloadedType.first
+ model = OverloadedType.last
assert_nil model.non_existent_decimal
model.non_existent_decimal = "123"
@@ -253,7 +253,7 @@ module ActiveRecord
attribute :non_existent_decimal, :decimal, default: 123
end
child.create!
- model = child.first
+ model = child.last
assert_equal 123, model.non_existent_decimal
end
@@ -264,7 +264,7 @@ module ActiveRecord
attribute :foo, :string, default: "lol"
end
child.create!
- model = child.first
+ model = child.last
assert_equal "lol", model.foo
diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb
index 1a0732c14b..3528ac045f 100644
--- a/activerecord/test/cases/autosave_association_test.rb
+++ b/activerecord/test/cases/autosave_association_test.rb
@@ -2,6 +2,7 @@
require "cases/helper"
require "models/author"
+require "models/book"
require "models/bird"
require "models/post"
require "models/comment"
@@ -12,12 +13,14 @@ require "models/developer"
require "models/computer"
require "models/invoice"
require "models/line_item"
+require "models/mouse"
require "models/order"
require "models/parrot"
require "models/pirate"
require "models/project"
require "models/ship"
require "models/ship_part"
+require "models/squeak"
require "models/tag"
require "models/tagging"
require "models/treasure"
@@ -39,7 +42,6 @@ class TestAutosaveAssociationsInGeneral < ActiveRecord::TestCase
def self.name; "Person"; end
private
-
def should_be_cool
unless first_name == "cool"
errors.add :first_name, "not cool"
@@ -82,7 +84,6 @@ class TestAutosaveAssociationsInGeneral < ActiveRecord::TestCase
end
private
-
def assert_no_difference_when_adding_callbacks_twice_for(model, association_name)
reflection = model.reflect_on_association(association_name)
assert_no_difference "callbacks_for_model(#{model.name}).length" do
@@ -387,6 +388,20 @@ class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::Test
assert_predicate auditlog, :valid?
end
+
+ def test_validation_does_not_validate_non_dirty_association_target
+ mouse = Mouse.create!(name: "Will")
+ Squeak.create!(mouse: mouse)
+
+ mouse.name = nil
+ mouse.save! validate: false
+
+ squeak = Squeak.last
+
+ assert_equal true, squeak.valid?
+ assert_equal true, squeak.mouse.present?
+ assert_equal true, squeak.valid?
+ end
end
class TestDefaultAutosaveAssociationOnAHasManyAssociationWithAcceptsNestedAttributes < ActiveRecord::TestCase
@@ -644,10 +659,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa
def test_build_before_save
company = companies(:first_firm)
- # Load schema information so we don't query below if running just this test.
- Client.define_attribute_methods
-
- new_client = assert_no_queries { company.clients_of_firm.build("name" => "Another Client") }
+ new_client = assert_queries(0) { company.clients_of_firm.build("name" => "Another Client") }
assert_not_predicate company.clients_of_firm, :loaded?
company.name += "-changed"
@@ -659,10 +671,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa
def test_build_many_before_save
company = companies(:first_firm)
- # Load schema information so we don't query below if running just this test.
- Client.define_attribute_methods
-
- assert_no_queries { company.clients_of_firm.build([{ "name" => "Another Client" }, { "name" => "Another Client II" }]) }
+ assert_queries(0) { company.clients_of_firm.build([{ "name" => "Another Client" }, { "name" => "Another Client II" }]) }
company.name += "-changed"
assert_queries(3) { assert company.save }
@@ -672,10 +681,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa
def test_build_via_block_before_save
company = companies(:first_firm)
- # Load schema information so we don't query below if running just this test.
- Client.define_attribute_methods
-
- new_client = assert_no_queries { company.clients_of_firm.build { |client| client.name = "Another Client" } }
+ new_client = assert_queries(0) { company.clients_of_firm.build { |client| client.name = "Another Client" } }
assert_not_predicate company.clients_of_firm, :loaded?
company.name += "-changed"
@@ -687,10 +693,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa
def test_build_many_via_block_before_save
company = companies(:first_firm)
- # Load schema information so we don't query below if running just this test.
- Client.define_attribute_methods
-
- assert_no_queries do
+ assert_queries(0) do
company.clients_of_firm.build([{ "name" => "Another Client" }, { "name" => "Another Client II" }]) do |client|
client.name = "changed"
end
@@ -1685,6 +1688,10 @@ class TestAutosaveAssociationValidationsOnAHasManyAssociation < ActiveRecord::Te
super
@pirate = Pirate.create(catchphrase: "Don' botharrr talkin' like one, savvy?")
@pirate.birds.create(name: "cookoo")
+
+ @author = Author.new(name: "DHH")
+ @author.published_books.build(name: "Rework", isbn: "1234")
+ @author.published_books.build(name: "Remote", isbn: "1234")
end
test "should automatically validate associations" do
@@ -1693,6 +1700,42 @@ class TestAutosaveAssociationValidationsOnAHasManyAssociation < ActiveRecord::Te
assert_not_predicate @pirate, :valid?
end
+
+ test "rollbacks whole transaction and raises ActiveRecord::RecordInvalid when associations fail to #save! due to uniqueness validation failure" do
+ author_count_before_save = Author.count
+ book_count_before_save = Book.count
+
+ assert_no_difference "Author.count" do
+ assert_no_difference "Book.count" do
+ exception = assert_raises(ActiveRecord::RecordInvalid) do
+ @author.save!
+ end
+
+ assert_equal("Validation failed: Published books is invalid", exception.message)
+ end
+ end
+
+ assert_equal(author_count_before_save, Author.count)
+ assert_equal(book_count_before_save, Book.count)
+ end
+
+ test "rollbacks whole transaction when associations fail to #save due to uniqueness validation failure" do
+ author_count_before_save = Author.count
+ book_count_before_save = Book.count
+
+ assert_no_difference "Author.count" do
+ assert_no_difference "Book.count" do
+ assert_nothing_raised do
+ result = @author.save
+
+ assert_not(result)
+ end
+ end
+ end
+
+ assert_equal(author_count_before_save, Author.count)
+ assert_equal(book_count_before_save, Book.count)
+ end
end
class TestAutosaveAssociationValidationsOnAHasOneAssociation < ActiveRecord::TestCase
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index ddafa468ed..1324bdf9b8 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -1141,11 +1141,14 @@ class BasicsTest < ActiveRecord::TestCase
def test_clear_cache!
# preheat cache
c1 = Post.connection.schema_cache.columns("posts")
+ assert_not_equal 0, Post.connection.schema_cache.size
+
ActiveRecord::Base.clear_cache!
+ assert_equal 0, Post.connection.schema_cache.size
+
c2 = Post.connection.schema_cache.columns("posts")
- c1.each_with_index do |v, i|
- assert_not_same v, c2[i]
- end
+ assert_not_equal 0, Post.connection.schema_cache.size
+
assert_equal c1, c2
end
@@ -1412,6 +1415,14 @@ class BasicsTest < ActiveRecord::TestCase
assert_not_includes SymbolIgnoredDeveloper.columns_hash.keys, "first_name"
end
+ test ".columns_hash raises an error if the record has an empty table name" do
+ expected_message = "FirstAbstractClass has no table configured. Set one with FirstAbstractClass.table_name="
+ exception = assert_raises(ActiveRecord::TableNotSpecified) do
+ FirstAbstractClass.columns_hash
+ end
+ assert_equal expected_message, exception.message
+ end
+
test "ignored columns have no attribute methods" do
assert_not_respond_to Developer.new, :first_name
assert_not_respond_to Developer.new, :first_name=
@@ -1496,7 +1507,7 @@ class BasicsTest < ActiveRecord::TestCase
test "creating a record raises if preventing writes" do
error = assert_raises ActiveRecord::ReadOnlyError do
- ActiveRecord::Base.connection.while_preventing_writes do
+ ActiveRecord::Base.connection_handler.while_preventing_writes do
Bird.create! name: "Bluejay"
end
end
@@ -1508,7 +1519,7 @@ class BasicsTest < ActiveRecord::TestCase
bird = Bird.create! name: "Bluejay"
error = assert_raises ActiveRecord::ReadOnlyError do
- ActiveRecord::Base.connection.while_preventing_writes do
+ ActiveRecord::Base.connection_handler.while_preventing_writes do
bird.update! name: "Robin"
end
end
@@ -1520,7 +1531,7 @@ class BasicsTest < ActiveRecord::TestCase
bird = Bird.create! name: "Bluejay"
error = assert_raises ActiveRecord::ReadOnlyError do
- ActiveRecord::Base.connection.while_preventing_writes do
+ ActiveRecord::Base.connection_handler.while_preventing_writes do
bird.destroy!
end
end
@@ -1531,7 +1542,7 @@ class BasicsTest < ActiveRecord::TestCase
test "selecting a record does not raise if preventing writes" do
bird = Bird.create! name: "Bluejay"
- ActiveRecord::Base.connection.while_preventing_writes do
+ ActiveRecord::Base.connection_handler.while_preventing_writes do
assert_equal bird, Bird.where(name: "Bluejay").first
end
end
@@ -1539,13 +1550,13 @@ class BasicsTest < ActiveRecord::TestCase
test "an explain query does not raise if preventing writes" do
Bird.create!(name: "Bluejay")
- ActiveRecord::Base.connection.while_preventing_writes do
+ ActiveRecord::Base.connection_handler.while_preventing_writes do
assert_queries(2) { Bird.where(name: "Bluejay").explain }
end
end
test "an empty transaction does not raise if preventing writes" do
- ActiveRecord::Base.connection.while_preventing_writes do
+ ActiveRecord::Base.connection_handler.while_preventing_writes do
assert_queries(2, ignore_none: true) do
Bird.transaction do
ActiveRecord::Base.connection.materialize_transactions
@@ -1553,4 +1564,59 @@ class BasicsTest < ActiveRecord::TestCase
end
end
end
+
+ test "preventing writes applies to all connections on a handler" do
+ conn1_error = assert_raises ActiveRecord::ReadOnlyError do
+ ActiveRecord::Base.connection_handler.while_preventing_writes do
+ assert_equal ActiveRecord::Base.connection, Bird.connection
+ assert_not_equal ARUnit2Model.connection, Bird.connection
+ Bird.create!(name: "Bluejay")
+ end
+ end
+
+ assert_match %r/\AWrite query attempted while in readonly mode: INSERT /, conn1_error.message
+
+ conn2_error = assert_raises ActiveRecord::ReadOnlyError do
+ ActiveRecord::Base.connection_handler.while_preventing_writes do
+ assert_not_equal ActiveRecord::Base.connection, Professor.connection
+ assert_equal ARUnit2Model.connection, Professor.connection
+ Professor.create!(name: "Professor Bluejay")
+ end
+ end
+
+ assert_match %r/\AWrite query attempted while in readonly mode: INSERT /, conn2_error.message
+ end
+
+ unless in_memory_db?
+ test "preventing writes with multiple handlers" do
+ ActiveRecord::Base.connects_to(database: { writing: :arunit, reading: :arunit })
+
+ conn1_error = assert_raises ActiveRecord::ReadOnlyError do
+ ActiveRecord::Base.connected_to(role: :writing) do
+ assert_equal :writing, ActiveRecord::Base.current_role
+
+ ActiveRecord::Base.connection_handler.while_preventing_writes do
+ Bird.create!(name: "Bluejay")
+ end
+ end
+ end
+
+ assert_match %r/\AWrite query attempted while in readonly mode: INSERT /, conn1_error.message
+
+ conn2_error = assert_raises ActiveRecord::ReadOnlyError do
+ ActiveRecord::Base.connected_to(role: :reading) do
+ assert_equal :reading, ActiveRecord::Base.current_role
+
+ ActiveRecord::Base.connection_handler.while_preventing_writes do
+ Bird.create!(name: "Bluejay")
+ end
+ end
+ end
+
+ assert_match %r/\AWrite query attempted while in readonly mode: INSERT /, conn2_error.message
+ ensure
+ ActiveRecord::Base.connection_handlers = { writing: ActiveRecord::Base.default_connection_handler }
+ ActiveRecord::Base.establish_connection(:arunit)
+ end
+ end
end
diff --git a/activerecord/test/cases/batches_test.rb b/activerecord/test/cases/batches_test.rb
index cf6e280898..0d0bf39f79 100644
--- a/activerecord/test/cases/batches_test.rb
+++ b/activerecord/test/cases/batches_test.rb
@@ -146,7 +146,7 @@ class EachTest < ActiveRecord::TestCase
def test_find_in_batches_should_quote_batch_order
c = Post.connection
- assert_sql(/ORDER BY #{c.quote_table_name('posts')}\.#{c.quote_column_name('id')}/) do
+ assert_sql(/ORDER BY #{Regexp.escape(c.quote_table_name("posts.id"))}/i) do
Post.find_in_batches(batch_size: 1) do |batch|
assert_kind_of Array, batch
assert_kind_of Post, batch.first
diff --git a/activerecord/test/cases/bind_parameter_test.rb b/activerecord/test/cases/bind_parameter_test.rb
index 85685d1d00..720446b39d 100644
--- a/activerecord/test/cases/bind_parameter_test.rb
+++ b/activerecord/test/cases/bind_parameter_test.rb
@@ -93,7 +93,7 @@ if ActiveRecord::Base.connection.prepared_statements
def test_statement_cache_with_in_clause
@connection.clear_cache!
- topics = Topic.where(id: [1, 3])
+ topics = Topic.where(id: [1, 3]).order(:id)
assert_equal [1, 3], topics.map(&:id)
assert_not_includes statement_cache, to_sql_key(topics.arel)
end
diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb
index 16c2a3661d..dbd1d03c4c 100644
--- a/activerecord/test/cases/calculations_test.rb
+++ b/activerecord/test/cases/calculations_test.rb
@@ -139,6 +139,13 @@ class CalculationsTest < ActiveRecord::TestCase
end
end
+ def test_should_not_use_alias_for_grouped_field
+ assert_sql(/GROUP BY #{Regexp.escape(Account.connection.quote_table_name("accounts.firm_id"))}/i) do
+ c = Account.group(:firm_id).order("accounts_firm_id").sum(:credit_limit)
+ assert_equal [1, 2, 6, 9], c.keys.compact
+ end
+ end
+
def test_should_order_by_grouped_field
c = Account.group(:firm_id).order("firm_id").sum(:credit_limit)
assert_equal [1, 2, 6, 9], c.keys.compact
@@ -185,7 +192,7 @@ class CalculationsTest < ActiveRecord::TestCase
def test_limit_is_kept
return if current_adapter?(:OracleAdapter)
- queries = assert_sql { Account.limit(1).count }
+ queries = capture_sql { Account.limit(1).count }
assert_equal 1, queries.length
assert_match(/LIMIT/, queries.first)
end
@@ -193,7 +200,7 @@ class CalculationsTest < ActiveRecord::TestCase
def test_offset_is_kept
return if current_adapter?(:OracleAdapter)
- queries = assert_sql { Account.offset(1).count }
+ queries = capture_sql { Account.offset(1).count }
assert_equal 1, queries.length
assert_match(/OFFSET/, queries.first)
end
@@ -201,14 +208,14 @@ class CalculationsTest < ActiveRecord::TestCase
def test_limit_with_offset_is_kept
return if current_adapter?(:OracleAdapter)
- queries = assert_sql { Account.limit(1).offset(1).count }
+ queries = capture_sql { Account.limit(1).offset(1).count }
assert_equal 1, queries.length
assert_match(/LIMIT/, queries.first)
assert_match(/OFFSET/, queries.first)
end
def test_no_limit_no_offset
- queries = assert_sql { Account.count }
+ queries = capture_sql { Account.count }
assert_equal 1, queries.length
assert_no_match(/LIMIT/, queries.first)
assert_no_match(/OFFSET/, queries.first)
@@ -224,15 +231,12 @@ class CalculationsTest < ActiveRecord::TestCase
end
def test_apply_distinct_in_count
- queries = assert_sql do
+ queries = capture_sql do
Account.distinct.count
Account.group(:firm_id).distinct.count
end
queries.each do |query|
- # `table_alias_length` in `column_alias_for` would execute
- # "SHOW max_identifier_length" statement in PostgreSQL adapter.
- next if query == "SHOW max_identifier_length"
assert_match %r{\ASELECT(?! DISTINCT) COUNT\(DISTINCT\b}, query
end
end
@@ -464,7 +468,7 @@ class CalculationsTest < ActiveRecord::TestCase
def test_should_not_perform_joined_include_by_default
assert_equal Account.count, Account.includes(:firm).count
- queries = assert_sql { Account.includes(:firm).count }
+ queries = capture_sql { Account.includes(:firm).count }
assert_no_match(/join/i, queries.last)
end
@@ -592,11 +596,7 @@ class CalculationsTest < ActiveRecord::TestCase
end
def test_should_sum_expression
- if current_adapter?(:SQLite3Adapter, :Mysql2Adapter, :PostgreSQLAdapter, :OracleAdapter)
- assert_equal 636, Account.sum("2 * credit_limit")
- else
- assert_equal 636, Account.sum("2 * credit_limit").to_i
- end
+ assert_equal 636, Account.sum("2 * credit_limit")
end
def test_sum_expression_returns_zero_when_no_records_to_sum
@@ -774,6 +774,12 @@ class CalculationsTest < ActiveRecord::TestCase
assert_equal [[2, 2], [4, 4]], Reply.includes(:topic).pluck(:id, :"topics.id")
end
+ def test_group_by_with_order_by_virtual_count_attribute
+ expected = { "SpecialPost" => 1, "StiPost" => 2 }
+ actual = Post.group(:type).order(:count).limit(2).maximum(:comments_count)
+ assert_equal expected, actual
+ end if current_adapter?(:PostgreSQLAdapter)
+
def test_group_by_with_limit
expected = { "Post" => 8, "SpecialPost" => 1 }
actual = Post.includes(:comments).group(:type).order(:type).limit(2).count("comments.id")
@@ -840,7 +846,7 @@ class CalculationsTest < ActiveRecord::TestCase
def test_pluck_columns_with_same_name
expected = [["The First Topic", "The Second Topic of the day"], ["The Third Topic of the day", "The Fourth Topic of the day"]]
- actual = Topic.joins(:replies)
+ actual = Topic.joins(:replies).order(:id)
.pluck("topics.title", "replies_topics.title")
assert_equal expected, actual
end
@@ -860,28 +866,25 @@ class CalculationsTest < ActiveRecord::TestCase
end
def test_pluck_loaded_relation
- Company.attribute_names # Load schema information so we don't query below
companies = Company.order(:id).limit(3).load
- assert_no_queries do
+ assert_queries(0) do
assert_equal ["37signals", "Summit", "Microsoft"], companies.pluck(:name)
end
end
def test_pluck_loaded_relation_multiple_columns
- Company.attribute_names # Load schema information so we don't query below
companies = Company.order(:id).limit(3).load
- assert_no_queries do
+ assert_queries(0) do
assert_equal [[1, "37signals"], [2, "Summit"], [3, "Microsoft"]], companies.pluck(:id, :name)
end
end
def test_pluck_loaded_relation_sql_fragment
- Company.attribute_names # Load schema information so we don't query below
companies = Company.order(:name).limit(3).load
- assert_queries 1 do
+ assert_queries(1) do
assert_equal ["37signals", "Apex", "Ex Nihilo"], companies.pluck(Arel.sql("DISTINCT name"))
end
end
diff --git a/activerecord/test/cases/comment_test.rb b/activerecord/test/cases/comment_test.rb
index 584e03d196..25e2f20676 100644
--- a/activerecord/test/cases/comment_test.rb
+++ b/activerecord/test/cases/comment_test.rb
@@ -14,6 +14,9 @@ if ActiveRecord::Base.connection.supports_comments?
class BlankComment < ActiveRecord::Base
end
+ class PkCommented < ActiveRecord::Base
+ end
+
setup do
@connection = ActiveRecord::Base.connection
@@ -35,8 +38,13 @@ if ActiveRecord::Base.connection.supports_comments?
t.index :absent_comment
end
+ @connection.create_table("pk_commenteds", comment: "Table comment", id: false, force: true) do |t|
+ t.integer :id, comment: "Primary key comment", primary_key: true
+ end
+
Commented.reset_column_information
BlankComment.reset_column_information
+ PkCommented.reset_column_information
end
teardown do
@@ -44,6 +52,11 @@ if ActiveRecord::Base.connection.supports_comments?
@connection.drop_table "blank_comments", if_exists: true
end
+ def test_default_primary_key_comment
+ column = Commented.columns_hash["id"]
+ assert_nil column.comment
+ end
+
def test_column_created_in_block
column = Commented.columns_hash["name"]
assert_equal :string, column.type
@@ -164,5 +177,17 @@ if ActiveRecord::Base.connection.supports_comments?
column = Commented.columns_hash["name"]
assert_nil column.comment
end
+
+ def test_comment_on_primary_key
+ column = PkCommented.columns_hash["id"]
+ assert_equal "Primary key comment", column.comment
+ assert_equal "Table comment", @connection.table_comment("pk_commenteds")
+ end
+
+ def test_schema_dump_with_primary_key_comment
+ output = dump_table_schema "pk_commenteds"
+ assert_match %r[create_table "pk_commenteds",.*\s+comment: "Table comment"], output
+ assert_no_match %r[create_table "pk_commenteds",.*\s+comment: "Primary key comment"], output
+ end
end
end
diff --git a/activerecord/test/cases/connection_adapters/connection_handler_test.rb b/activerecord/test/cases/connection_adapters/connection_handler_test.rb
index 6282759a10..843242a897 100644
--- a/activerecord/test/cases/connection_adapters/connection_handler_test.rb
+++ b/activerecord/test/cases/connection_adapters/connection_handler_test.rb
@@ -29,7 +29,7 @@ module ActiveRecord
def test_establish_connection_uses_spec_name
old_config = ActiveRecord::Base.configurations
- config = { "readonly" => { "adapter" => "sqlite3" } }
+ config = { "readonly" => { "adapter" => "sqlite3", "pool" => "5" } }
ActiveRecord::Base.configurations = config
resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new(ActiveRecord::Base.configurations)
spec = resolver.spec(:readonly)
@@ -367,11 +367,24 @@ module ActiveRecord
assert_same klass2.connection, ActiveRecord::Base.connection
end
+ class ApplicationRecord < ActiveRecord::Base
+ self.abstract_class = true
+ end
+
+ class MyClass < ApplicationRecord
+ end
+
def test_connection_specification_name_should_fallback_to_parent
klassA = Class.new(Base)
klassB = Class.new(klassA)
+ klassC = Class.new(MyClass)
assert_equal klassB.connection_specification_name, klassA.connection_specification_name
+ assert_equal klassC.connection_specification_name, klassA.connection_specification_name
+
+ assert_equal "primary", klassA.connection_specification_name
+ assert_equal "primary", klassC.connection_specification_name
+
klassA.connection_specification_name = "readonly"
assert_equal "readonly", klassB.connection_specification_name
end
diff --git a/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb b/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb
index 515bf5df06..95e57f42e3 100644
--- a/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb
+++ b/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb
@@ -244,6 +244,25 @@ module ActiveRecord
assert_equal expected, actual
end
+ def test_no_url_sub_key_with_database_url_doesnt_trample_other_envs
+ ENV["DATABASE_URL"] = "postgres://localhost/baz"
+
+ config = { "default_env" => { "database" => "foo" }, "other_env" => { "url" => "postgres://foohost/bardb" } }
+ actual = resolve_config(config)
+ expected = { "default_env" =>
+ { "database" => "baz",
+ "adapter" => "postgresql",
+ "host" => "localhost"
+ },
+ "other_env" =>
+ { "adapter" => "postgresql",
+ "database" => "bardb",
+ "host" => "foohost"
+ }
+ }
+ assert_equal expected, actual
+ end
+
def test_merge_no_conflicts_with_database_url
ENV["DATABASE_URL"] = "postgres://localhost/foo"
@@ -273,6 +292,77 @@ module ActiveRecord
}
assert_equal expected, actual
end
+
+ def test_merge_no_conflicts_with_database_url_and_adapter
+ ENV["DATABASE_URL"] = "postgres://localhost/foo"
+
+ config = { "default_env" => { "adapter" => "postgresql", "pool" => "5" } }
+ actual = resolve_config(config)
+ expected = { "default_env" =>
+ { "adapter" => "postgresql",
+ "database" => "foo",
+ "host" => "localhost",
+ "pool" => "5"
+ }
+ }
+ assert_equal expected, actual
+ end
+
+ def test_merge_no_conflicts_with_database_url_and_numeric_pool
+ ENV["DATABASE_URL"] = "postgres://localhost/foo"
+
+ config = { "default_env" => { "pool" => 5 } }
+ actual = resolve_config(config)
+ expected = { "default_env" =>
+ { "adapter" => "postgresql",
+ "database" => "foo",
+ "host" => "localhost",
+ "pool" => 5
+ }
+ }
+
+ assert_equal expected, actual
+ end
+
+ def test_tiered_configs_with_database_url
+ ENV["DATABASE_URL"] = "postgres://localhost/foo"
+
+ config = {
+ "default_env" => {
+ "primary" => { "pool" => 5 },
+ "animals" => { "pool" => 5 }
+ }
+ }
+
+ expected = {
+ "adapter" => "postgresql",
+ "database" => "foo",
+ "host" => "localhost",
+ "pool" => 5
+ }
+
+ ["primary", "animals"].each do |spec_name|
+ configs = ActiveRecord::DatabaseConfigurations.new(config)
+ actual = configs.configs_for(env_name: "default_env", spec_name: spec_name).config
+ assert_equal expected, actual
+ end
+ end
+
+ def test_does_not_change_other_environments
+ ENV["DATABASE_URL"] = "postgres://localhost/foo"
+ config = { "production" => { "adapter" => "not_postgres", "database" => "not_foo", "host" => "localhost" }, "default_env" => {} }
+
+ actual = resolve_spec(:production, config)
+ assert_equal config["production"].merge("name" => "production"), actual
+
+ actual = resolve_spec(:default_env, config)
+ assert_equal({
+ "host" => "localhost",
+ "database" => "foo",
+ "adapter" => "postgresql",
+ "name" => "default_env"
+ }, actual)
+ end
end
end
end
diff --git a/activerecord/test/cases/connection_adapters/mysql_type_lookup_test.rb b/activerecord/test/cases/connection_adapters/mysql_type_lookup_test.rb
index 38331aa641..774380d7e0 100644
--- a/activerecord/test/cases/connection_adapters/mysql_type_lookup_test.rb
+++ b/activerecord/test/cases/connection_adapters/mysql_type_lookup_test.rb
@@ -40,7 +40,7 @@ if current_adapter?(:Mysql2Adapter)
end
def test_enum_type_with_value_matching_other_type
- assert_lookup_type :string, "ENUM('unicode', '8bit', 'none')"
+ assert_lookup_type :string, "ENUM('unicode', '8bit', 'none', 'time')"
end
def test_binary_types
@@ -58,7 +58,6 @@ if current_adapter?(:Mysql2Adapter)
end
private
-
def assert_lookup_type(type, lookup)
cast_type = @connection.send(:type_map).lookup(lookup)
assert_equal type, cast_type.type
diff --git a/activerecord/test/cases/connection_adapters/type_lookup_test.rb b/activerecord/test/cases/connection_adapters/type_lookup_test.rb
index 1c79d776f0..e92bb40632 100644
--- a/activerecord/test/cases/connection_adapters/type_lookup_test.rb
+++ b/activerecord/test/cases/connection_adapters/type_lookup_test.rb
@@ -109,7 +109,6 @@ unless current_adapter?(:PostgreSQLAdapter) # PostgreSQL does not use type strin
end
private
-
def assert_lookup_type(type, lookup)
cast_type = @connection.send(:type_map).lookup(lookup)
assert_equal type, cast_type.type
diff --git a/activerecord/test/cases/connection_pool_test.rb b/activerecord/test/cases/connection_pool_test.rb
index a15ad9a45b..ccbb6e16cd 100644
--- a/activerecord/test/cases/connection_pool_test.rb
+++ b/activerecord/test/cases/connection_pool_test.rb
@@ -507,7 +507,6 @@ module ActiveRecord
pool.schema_cache = schema_cache
pool.with_connection do |conn|
- assert_not_same pool.schema_cache, conn.schema_cache
assert_equal pool.schema_cache.size, conn.schema_cache.size
assert_same pool.schema_cache.columns(:posts), conn.schema_cache.columns(:posts)
end
@@ -695,6 +694,28 @@ module ActiveRecord
end
end
+ def test_public_connections_access_threadsafe
+ _conn1 = @pool.checkout
+ conn2 = @pool.checkout
+
+ connections = @pool.connections
+ found_conn = nil
+
+ # Without assuming too much about implementation
+ # details make sure that a concurrent change to
+ # the pool is thread-safe.
+ connections.each_index do |idx|
+ if connections[idx] == conn2
+ Thread.new do
+ @pool.remove(conn2)
+ end.join
+ end
+ found_conn = connections[idx]
+ end
+
+ assert_not_nil found_conn
+ end
+
private
def with_single_connection_pool
one_conn_spec = ActiveRecord::Base.connection_pool.spec.dup
diff --git a/activerecord/test/cases/database_statements_test.rb b/activerecord/test/cases/database_statements_test.rb
index 1c934602ec..119d48b85e 100644
--- a/activerecord/test/cases/database_statements_test.rb
+++ b/activerecord/test/cases/database_statements_test.rb
@@ -23,7 +23,6 @@ class DatabaseStatementsTest < ActiveRecord::TestCase
end
private
-
def return_the_inserted_id(method:)
# Oracle adapter uses prefetched primary key values from sequence and passes them to connection adapter insert method
if current_adapter?(:OracleAdapter)
diff --git a/activerecord/test/cases/enum_test.rb b/activerecord/test/cases/enum_test.rb
index ae0ce195b3..8673a99c45 100644
--- a/activerecord/test/cases/enum_test.rb
+++ b/activerecord/test/cases/enum_test.rb
@@ -3,6 +3,7 @@
require "cases/helper"
require "models/author"
require "models/book"
+require "active_support/log_subscriber/test_helper"
class EnumTest < ActiveRecord::TestCase
fixtures :books, :authors, :author_addresses
@@ -565,4 +566,25 @@ class EnumTest < ActiveRecord::TestCase
assert_raises(NoMethodError) { klass.proposed }
end
+
+ test "enums with a negative condition log a warning" do
+ old_logger = ActiveRecord::Base.logger
+ logger = ActiveSupport::LogSubscriber::TestHelper::MockLogger.new
+
+ ActiveRecord::Base.logger = logger
+
+ expected_message = "An enum element in Book uses the prefix 'not_'."\
+ " This will cause a conflict with auto generated negative scopes."
+
+ Class.new(ActiveRecord::Base) do
+ def self.name
+ "Book"
+ end
+ enum status: [:sent, :not_sent]
+ end
+
+ assert_match(expected_message, logger.logged(:warn).first)
+ ensure
+ ActiveRecord::Base.logger = old_logger
+ end
end
diff --git a/activerecord/test/cases/explain_test.rb b/activerecord/test/cases/explain_test.rb
index a0e75f4e89..edd2c768d3 100644
--- a/activerecord/test/cases/explain_test.rb
+++ b/activerecord/test/cases/explain_test.rb
@@ -72,7 +72,6 @@ if ActiveRecord::Base.connection.supports_explain?
end
private
-
def stub_explain_for_query_plans(query_plans = ["query plan foo", "query plan bar"])
explain_called = 0
diff --git a/activerecord/test/cases/finder_respond_to_test.rb b/activerecord/test/cases/finder_respond_to_test.rb
index 66413a98e4..d9e88b3feb 100644
--- a/activerecord/test/cases/finder_respond_to_test.rb
+++ b/activerecord/test/cases/finder_respond_to_test.rb
@@ -54,7 +54,6 @@ class FinderRespondToTest < ActiveRecord::TestCase
end
private
-
def ensure_topic_method_is_not_cached(method_id)
Topic.singleton_class.remove_method method_id if Topic.public_methods.include? method_id
end
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index ca114d468e..1f2058cc0a 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -245,7 +245,8 @@ class FinderTest < ActiveRecord::TestCase
end
def test_exists_does_not_select_columns_without_alias
- assert_sql(/SELECT\W+1 AS one FROM ["`]topics["`]/i) do
+ c = Topic.connection
+ assert_sql(/SELECT 1 AS one FROM #{Regexp.escape(c.quote_table_name("topics"))}/i) do
Topic.exists?
end
end
@@ -282,6 +283,11 @@ class FinderTest < ActiveRecord::TestCase
assert_not Post.select(:body).distinct.offset(4).exists?
end
+ def test_exists_with_distinct_and_offset_and_eagerload_and_order
+ assert Post.eager_load(:comments).distinct.offset(10).merge(Comment.order(post_id: :asc)).exists?
+ assert_not Post.eager_load(:comments).distinct.offset(11).merge(Comment.order(post_id: :asc)).exists?
+ end
+
# Ensure +exists?+ runs without an error by excluding distinct value.
# See https://github.com/rails/rails/pull/26981.
def test_exists_with_order_and_distinct
@@ -517,6 +523,7 @@ class FinderTest < ActiveRecord::TestCase
expected.touch # PostgreSQL changes the default order if no order clause is used
assert_equal expected, Topic.first
assert_equal expected, Topic.limit(5).first
+ assert_equal expected, Topic.order(nil).first
end
def test_model_class_responds_to_first_bang
@@ -540,6 +547,7 @@ class FinderTest < ActiveRecord::TestCase
expected.touch # PostgreSQL changes the default order if no order clause is used
assert_equal expected, Topic.second
assert_equal expected, Topic.limit(5).second
+ assert_equal expected, Topic.order(nil).second
end
def test_model_class_responds_to_second_bang
@@ -563,6 +571,7 @@ class FinderTest < ActiveRecord::TestCase
expected.touch # PostgreSQL changes the default order if no order clause is used
assert_equal expected, Topic.third
assert_equal expected, Topic.limit(5).third
+ assert_equal expected, Topic.order(nil).third
end
def test_model_class_responds_to_third_bang
@@ -586,6 +595,7 @@ class FinderTest < ActiveRecord::TestCase
expected.touch # PostgreSQL changes the default order if no order clause is used
assert_equal expected, Topic.fourth
assert_equal expected, Topic.limit(5).fourth
+ assert_equal expected, Topic.order(nil).fourth
end
def test_model_class_responds_to_fourth_bang
@@ -609,6 +619,7 @@ class FinderTest < ActiveRecord::TestCase
expected.touch # PostgreSQL changes the default order if no order clause is used
assert_equal expected, Topic.fifth
assert_equal expected, Topic.limit(5).fifth
+ assert_equal expected, Topic.order(nil).fifth
end
def test_model_class_responds_to_fifth_bang
@@ -777,6 +788,7 @@ class FinderTest < ActiveRecord::TestCase
assert_equal expected, clients.first(2)
assert_equal expected, clients.limit(5).first(2)
+ assert_equal expected, clients.order(nil).first(2)
end
def test_implicit_order_column_is_configurable
diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb
index 0cb868da6e..a7f01e898e 100644
--- a/activerecord/test/cases/fixtures_test.rb
+++ b/activerecord/test/cases/fixtures_test.rb
@@ -948,7 +948,6 @@ class TransactionalFixturesOnConnectionNotification < ActiveRecord::TestCase
end
private
-
def fire_connection_notification(connection)
assert_called_with(ActiveRecord::Base.connection_handler, :retrieve_connection, ["book"], returns: connection) do
message_bus = ActiveSupport::Notifications.instrumenter
@@ -1367,7 +1366,6 @@ class MultipleDatabaseFixturesTest < ActiveRecord::TestCase
end
private
-
def with_temporary_connection_pool
old_pool = ActiveRecord::Base.connection_handler.retrieve_connection_pool(ActiveRecord::Base.connection_specification_name)
new_pool = ActiveRecord::ConnectionAdapters::ConnectionPool.new ActiveRecord::Base.connection_pool.spec
diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb
index 543a0aeb39..56c780c4a6 100644
--- a/activerecord/test/cases/helper.rb
+++ b/activerecord/test/cases/helper.rb
@@ -189,7 +189,6 @@ end
module InTimeZone
private
-
def in_time_zone(zone)
old_zone = Time.zone
old_tz = ActiveRecord::Base.time_zone_aware_attributes
diff --git a/activerecord/test/cases/hot_compatibility_test.rb b/activerecord/test/cases/hot_compatibility_test.rb
index 7b388ebc5e..f41aea6125 100644
--- a/activerecord/test/cases/hot_compatibility_test.rb
+++ b/activerecord/test/cases/hot_compatibility_test.rb
@@ -115,7 +115,6 @@ class HotCompatibilityTest < ActiveRecord::TestCase
end
private
-
def get_prepared_statement_cache(connection)
connection.instance_variable_get(:@statements)
.instance_variable_get(:@cache)[Process.pid]
diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb
index 629167e9ed..01e4878c3f 100644
--- a/activerecord/test/cases/inheritance_test.rb
+++ b/activerecord/test/cases/inheritance_test.rb
@@ -471,9 +471,9 @@ class InheritanceTest < ActiveRecord::TestCase
end
def test_eager_load_belongs_to_primary_key_quoting
- con = Account.connection
+ c = Account.connection
bind_param = Arel::Nodes::BindParam.new(nil)
- assert_sql(/#{con.quote_table_name('companies')}\.#{con.quote_column_name('id')} = (?:#{Regexp.quote(bind_param.to_sql)}|1)/) do
+ assert_sql(/#{Regexp.escape(c.quote_table_name("companies.id"))} = (?:#{Regexp.escape(bind_param.to_sql)}|1)/i) do
Account.all.merge!(includes: :firm).find(1)
end
end
diff --git a/activerecord/test/cases/insert_all_test.rb b/activerecord/test/cases/insert_all_test.rb
index f24c63031c..d086d77081 100644
--- a/activerecord/test/cases/insert_all_test.rb
+++ b/activerecord/test/cases/insert_all_test.rb
@@ -262,7 +262,6 @@ class InsertAllTest < ActiveRecord::TestCase
end
private
-
def capture_log_output
output = StringIO.new
old_logger, ActiveRecord::Base.logger = ActiveRecord::Base.logger, ActiveSupport::Logger.new(output)
diff --git a/activerecord/test/cases/json_serialization_test.rb b/activerecord/test/cases/json_serialization_test.rb
index 82cf281cff..d68e208617 100644
--- a/activerecord/test/cases/json_serialization_test.rb
+++ b/activerecord/test/cases/json_serialization_test.rb
@@ -10,7 +10,6 @@ require "models/comment"
module JsonSerializationHelpers
private
-
def set_include_root_in_json(value)
original_root_in_json = ActiveRecord::Base.include_root_in_json
ActiveRecord::Base.include_root_in_json = value
@@ -24,7 +23,7 @@ class JsonSerializationTest < ActiveRecord::TestCase
include JsonSerializationHelpers
class NamespacedContact < Contact
- column :name, :string
+ column :name, "string"
end
def setup
diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb
index 04f9b26960..b468da7c76 100644
--- a/activerecord/test/cases/locking_test.rb
+++ b/activerecord/test/cases/locking_test.rb
@@ -593,7 +593,6 @@ class OptimisticLockingWithSchemaChangeTest < ActiveRecord::TestCase
end
private
-
def add_counter_column_to(model, col = "test_count")
model.connection.add_column model.table_name, col, :integer, null: false, default: 0
model.reset_column_information
diff --git a/activerecord/test/cases/migration/compatibility_test.rb b/activerecord/test/cases/migration/compatibility_test.rb
index 726ccf925e..ff2a694e66 100644
--- a/activerecord/test/cases/migration/compatibility_test.rb
+++ b/activerecord/test/cases/migration/compatibility_test.rb
@@ -12,6 +12,7 @@ module ActiveRecord
def setup
super
@connection = ActiveRecord::Base.connection
+ @schema_migration = @connection.schema_migration
@verbose_was = ActiveRecord::Migration.verbose
ActiveRecord::Migration.verbose = false
@@ -38,7 +39,7 @@ module ActiveRecord
}.new
assert connection.index_exists?(:testings, :foo, name: "custom_index_name")
- assert_raise(StandardError) { ActiveRecord::Migrator.new(:up, [migration]).migrate }
+ assert_raise(StandardError) { ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate }
assert connection.index_exists?(:testings, :foo, name: "custom_index_name")
end
@@ -53,7 +54,7 @@ module ActiveRecord
}.new
assert connection.index_exists?(:testings, :bar)
- ActiveRecord::Migrator.new(:up, [migration]).migrate
+ ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate
assert_not connection.index_exists?(:testings, :bar)
end
@@ -67,7 +68,7 @@ module ActiveRecord
end
}.new
- ActiveRecord::Migrator.new(:up, [migration]).migrate
+ ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate
assert_not connection.index_exists?(:more_testings, :foo_id)
assert_not connection.index_exists?(:more_testings, :bar_id)
@@ -84,7 +85,7 @@ module ActiveRecord
end
}.new
- ActiveRecord::Migrator.new(:up, [migration]).migrate
+ ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate
assert connection.column_exists?(:more_testings, :created_at, null: true)
assert connection.column_exists?(:more_testings, :updated_at, null: true)
@@ -101,7 +102,7 @@ module ActiveRecord
end
}.new
- ActiveRecord::Migrator.new(:up, [migration]).migrate
+ ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate
assert connection.column_exists?(:testings, :created_at, null: true)
assert connection.column_exists?(:testings, :updated_at, null: true)
@@ -117,7 +118,7 @@ module ActiveRecord
end
}.new
- ActiveRecord::Migrator.new(:up, [migration]).migrate
+ ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate
assert connection.column_exists?(:testings, :created_at, null: true)
assert connection.column_exists?(:testings, :updated_at, null: true)
@@ -131,7 +132,7 @@ module ActiveRecord
end
}.new
- ActiveRecord::Migrator.new(:up, [migration]).migrate
+ ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate
assert connection.column_exists?(:testings, :created_at, null: true)
assert connection.column_exists?(:testings, :updated_at, null: true)
@@ -146,7 +147,7 @@ module ActiveRecord
end
}.new
- ActiveRecord::Migrator.new(:up, [migration]).migrate
+ ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate
assert connection.column_exists?(:more_testings, :created_at, null: false, **precision_implicit_default)
assert connection.column_exists?(:more_testings, :updated_at, null: false, **precision_implicit_default)
@@ -163,7 +164,7 @@ module ActiveRecord
end
}.new
- ActiveRecord::Migrator.new(:up, [migration]).migrate
+ ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate
assert connection.column_exists?(:testings, :created_at, null: false, **precision_implicit_default)
assert connection.column_exists?(:testings, :updated_at, null: false, **precision_implicit_default)
@@ -179,7 +180,7 @@ module ActiveRecord
end
}.new
- ActiveRecord::Migrator.new(:up, [migration]).migrate
+ ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate
assert connection.column_exists?(:testings, :created_at, null: false, **precision_implicit_default)
assert connection.column_exists?(:testings, :updated_at, null: false, **precision_implicit_default)
@@ -193,7 +194,7 @@ module ActiveRecord
end
}.new
- ActiveRecord::Migrator.new(:up, [migration]).migrate
+ ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate
assert connection.column_exists?(:testings, :created_at, null: false, **precision_implicit_default)
assert connection.column_exists?(:testings, :updated_at, null: false, **precision_implicit_default)
@@ -230,7 +231,7 @@ module ActiveRecord
end
}.new
- ActiveRecord::Migrator.new(:up, [migration]).migrate
+ ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate
assert connection.column_exists?(:testings, :foo, comment: "comment")
end
@@ -243,7 +244,7 @@ module ActiveRecord
end
}.new
- ActiveRecord::Migrator.new(:up, [migration]).migrate
+ ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate
assert_equal "comment", connection.table_comment("testings")
end
@@ -261,7 +262,7 @@ module ActiveRecord
}.new
Testing.create!
- ActiveRecord::Migrator.new(:up, [migration]).migrate
+ ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate
assert_equal ["foobar"], Testing.all.map(&:foo)
ensure
ActiveRecord::Base.clear_cache!
diff --git a/activerecord/test/cases/migration/create_join_table_test.rb b/activerecord/test/cases/migration/create_join_table_test.rb
index e0cbb29dcf..0257545330 100644
--- a/activerecord/test/cases/migration/create_join_table_test.rb
+++ b/activerecord/test/cases/migration/create_join_table_test.rb
@@ -151,7 +151,6 @@ module ActiveRecord
end
private
-
def with_table_cleanup
tables_before = connection.data_sources
diff --git a/activerecord/test/cases/migration/helper.rb b/activerecord/test/cases/migration/helper.rb
index c056199140..da8bdc472a 100644
--- a/activerecord/test/cases/migration/helper.rb
+++ b/activerecord/test/cases/migration/helper.rb
@@ -34,7 +34,6 @@ module ActiveRecord
end
private
-
delegate(*CONNECTION_METHODS, to: :connection)
end
end
diff --git a/activerecord/test/cases/migration/logger_test.rb b/activerecord/test/cases/migration/logger_test.rb
index 28f4cc124b..431047f957 100644
--- a/activerecord/test/cases/migration/logger_test.rb
+++ b/activerecord/test/cases/migration/logger_test.rb
@@ -17,19 +17,20 @@ module ActiveRecord
def setup
super
- ActiveRecord::SchemaMigration.create_table
- ActiveRecord::SchemaMigration.delete_all
+ @schema_migration = ActiveRecord::Base.connection.schema_migration
+ @schema_migration.create_table
+ @schema_migration.delete_all
end
teardown do
- ActiveRecord::SchemaMigration.drop_table
+ @schema_migration.drop_table
end
def test_migration_should_be_run_without_logger
previous_logger = ActiveRecord::Base.logger
ActiveRecord::Base.logger = nil
migrations = [Migration.new("a", 1), Migration.new("b", 2), Migration.new("c", 3)]
- ActiveRecord::Migrator.new(:up, migrations).migrate
+ ActiveRecord::Migrator.new(:up, migrations, @schema_migration).migrate
ensure
ActiveRecord::Base.logger = previous_logger
end
diff --git a/activerecord/test/cases/migration/references_statements_test.rb b/activerecord/test/cases/migration/references_statements_test.rb
index 769241ba12..451894fc54 100644
--- a/activerecord/test/cases/migration/references_statements_test.rb
+++ b/activerecord/test/cases/migration/references_statements_test.rb
@@ -126,7 +126,6 @@ module ActiveRecord
end
private
-
def with_polymorphic_column
add_column table_name, :supplier_type, :string
add_index table_name, [:supplier_id, :supplier_type]
diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
index 255885b599..20f577b2c5 100644
--- a/activerecord/test/cases/migration_test.rb
+++ b/activerecord/test/cases/migration_test.rb
@@ -38,6 +38,7 @@ class MigrationTest < ActiveRecord::TestCase
end
Reminder.reset_column_information
@verbose_was, ActiveRecord::Migration.verbose = ActiveRecord::Migration.verbose, false
+ @schema_migration = ActiveRecord::Base.connection.schema_migration
ActiveRecord::Base.connection.schema_cache.clear!
end
@@ -84,7 +85,7 @@ class MigrationTest < ActiveRecord::TestCase
def test_migrator_versions
migrations_path = MIGRATIONS_ROOT + "/valid"
- migrator = ActiveRecord::MigrationContext.new(migrations_path)
+ migrator = ActiveRecord::MigrationContext.new(migrations_path, @schema_migration)
migrator.up
assert_equal 3, migrator.current_version
@@ -102,23 +103,23 @@ class MigrationTest < ActiveRecord::TestCase
ActiveRecord::Base.connection.drop_table "schema_migrations", if_exists: true
migrations_path = MIGRATIONS_ROOT + "/valid"
- migrator = ActiveRecord::MigrationContext.new(migrations_path)
+ migrator = ActiveRecord::MigrationContext.new(migrations_path, @schema_migration)
assert_equal true, migrator.needs_migration?
end
def test_any_migrations
- migrator = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/valid")
+ migrator = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/valid", @schema_migration)
assert_predicate migrator, :any_migrations?
- migrator_empty = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/empty")
+ migrator_empty = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/empty", @schema_migration)
assert_not_predicate migrator_empty, :any_migrations?
end
def test_migration_version
- migrator = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/version_check")
+ migrator = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/version_check", @schema_migration)
assert_equal 0, migrator.current_version
migrator.up(20131219224947)
assert_equal 20131219224947, migrator.current_version
@@ -190,6 +191,7 @@ class MigrationTest < ActiveRecord::TestCase
assert_not_predicate BigNumber, :table_exists?
GiveMeBigNumbers.up
+ assert_predicate BigNumber, :table_exists?
BigNumber.reset_column_information
assert BigNumber.create(
@@ -248,7 +250,7 @@ class MigrationTest < ActiveRecord::TestCase
assert_not_predicate Reminder, :table_exists?
name_filter = lambda { |migration| migration.name == "ValidPeopleHaveLastNames" }
- migrator = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/valid")
+ migrator = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/valid", @schema_migration)
migrator.up(&name_filter)
assert_column Person, :last_name
@@ -310,7 +312,7 @@ class MigrationTest < ActiveRecord::TestCase
end
}.new
- migrator = ActiveRecord::Migrator.new(:up, [migration], 100)
+ migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 100)
e = assert_raise(StandardError) { migrator.migrate }
@@ -331,7 +333,7 @@ class MigrationTest < ActiveRecord::TestCase
end
}.new
- migrator = ActiveRecord::Migrator.new(:up, [migration], 100)
+ migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 100)
e = assert_raise(StandardError) { migrator.run }
@@ -354,7 +356,7 @@ class MigrationTest < ActiveRecord::TestCase
end
}.new
- migrator = ActiveRecord::Migrator.new(:up, [migration], 101)
+ migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 101)
e = assert_raise(StandardError) { migrator.migrate }
assert_equal "An error has occurred, all later migrations canceled:\n\nSomething broke", e.message
@@ -413,7 +415,7 @@ class MigrationTest < ActiveRecord::TestCase
def test_internal_metadata_stores_environment
current_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
migrations_path = MIGRATIONS_ROOT + "/valid"
- migrator = ActiveRecord::MigrationContext.new(migrations_path)
+ migrator = ActiveRecord::MigrationContext.new(migrations_path, @schema_migration)
migrator.up
assert_equal current_env, ActiveRecord::InternalMetadata[:environment]
@@ -441,7 +443,7 @@ class MigrationTest < ActiveRecord::TestCase
current_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
migrations_path = MIGRATIONS_ROOT + "/valid"
- migrator = ActiveRecord::MigrationContext.new(migrations_path)
+ migrator = ActiveRecord::MigrationContext.new(migrations_path, @schema_migration)
migrator.up
assert_equal current_env, ActiveRecord::InternalMetadata[:environment]
assert_equal "bar", ActiveRecord::InternalMetadata[:foo]
@@ -482,6 +484,7 @@ class MigrationTest < ActiveRecord::TestCase
Thing.reset_table_name
Thing.reset_sequence_name
WeNeedThings.up
+ assert_predicate Thing, :table_exists?
Thing.reset_column_information
assert Thing.create("content" => "hello world")
@@ -502,8 +505,9 @@ class MigrationTest < ActiveRecord::TestCase
ActiveRecord::Base.table_name_suffix = "_suffix"
Reminder.reset_table_name
Reminder.reset_sequence_name
- Reminder.reset_column_information
WeNeedReminders.up
+ assert_predicate Reminder, :table_exists?
+ Reminder.reset_column_information
assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
assert_equal "hello world", Reminder.first.content
@@ -636,7 +640,7 @@ class MigrationTest < ActiveRecord::TestCase
if ActiveRecord::Base.connection.supports_advisory_locks?
def test_migrator_generates_valid_lock_id
migration = Class.new(ActiveRecord::Migration::Current).new
- migrator = ActiveRecord::Migrator.new(:up, [migration], 100)
+ migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 100)
lock_id = migrator.send(:generate_migrator_advisory_lock_id)
@@ -650,7 +654,7 @@ class MigrationTest < ActiveRecord::TestCase
# It is important we are consistent with how we generate this so that
# exclusive locking works across migrator versions
migration = Class.new(ActiveRecord::Migration::Current).new
- migrator = ActiveRecord::Migrator.new(:up, [migration], 100)
+ migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 100)
lock_id = migrator.send(:generate_migrator_advisory_lock_id)
@@ -672,7 +676,7 @@ class MigrationTest < ActiveRecord::TestCase
end
}.new
- migrator = ActiveRecord::Migrator.new(:up, [migration], 100)
+ migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 100)
lock_id = migrator.send(:generate_migrator_advisory_lock_id)
with_another_process_holding_lock(lock_id) do
@@ -693,7 +697,7 @@ class MigrationTest < ActiveRecord::TestCase
end
}.new
- migrator = ActiveRecord::Migrator.new(:up, [migration], 100)
+ migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 100)
lock_id = migrator.send(:generate_migrator_advisory_lock_id)
with_another_process_holding_lock(lock_id) do
@@ -706,7 +710,7 @@ class MigrationTest < ActiveRecord::TestCase
def test_with_advisory_lock_raises_the_right_error_when_it_fails_to_release_lock
migration = Class.new(ActiveRecord::Migration::Current).new
- migrator = ActiveRecord::Migrator.new(:up, [migration], 100)
+ migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 100)
lock_id = migrator.send(:generate_migrator_advisory_lock_id)
e = assert_raises(ActiveRecord::ConcurrentMigrationError) do
@@ -935,7 +939,6 @@ if ActiveRecord::Base.connection.supports_bulk_alter?
end
private
-
def with_bulk_change_table
# Reset columns/indexes cache as we're changing the table
@columns = @indexes = nil
diff --git a/activerecord/test/cases/migrator_test.rb b/activerecord/test/cases/migrator_test.rb
index 30e199f1c5..aeba8e1d14 100644
--- a/activerecord/test/cases/migrator_test.rb
+++ b/activerecord/test/cases/migrator_test.rb
@@ -23,8 +23,9 @@ class MigratorTest < ActiveRecord::TestCase
def setup
super
- ActiveRecord::SchemaMigration.create_table
- ActiveRecord::SchemaMigration.delete_all rescue nil
+ @schema_migration = ActiveRecord::Base.connection.schema_migration
+ @schema_migration.create_table
+ @schema_migration.delete_all rescue nil
@verbose_was = ActiveRecord::Migration.verbose
ActiveRecord::Migration.message_count = 0
ActiveRecord::Migration.class_eval do
@@ -36,7 +37,7 @@ class MigratorTest < ActiveRecord::TestCase
end
teardown do
- ActiveRecord::SchemaMigration.delete_all rescue nil
+ @schema_migration.delete_all rescue nil
ActiveRecord::Migration.verbose = @verbose_was
ActiveRecord::Migration.class_eval do
undef :puts
@@ -49,7 +50,7 @@ class MigratorTest < ActiveRecord::TestCase
def test_migrator_with_duplicate_names
e = assert_raises(ActiveRecord::DuplicateMigrationNameError) do
list = [ActiveRecord::Migration.new("Chunky"), ActiveRecord::Migration.new("Chunky")]
- ActiveRecord::Migrator.new(:up, list)
+ ActiveRecord::Migrator.new(:up, list, @schema_migration)
end
assert_match(/Multiple migrations have the name Chunky/, e.message)
end
@@ -57,39 +58,40 @@ class MigratorTest < ActiveRecord::TestCase
def test_migrator_with_duplicate_versions
assert_raises(ActiveRecord::DuplicateMigrationVersionError) do
list = [ActiveRecord::Migration.new("Foo", 1), ActiveRecord::Migration.new("Bar", 1)]
- ActiveRecord::Migrator.new(:up, list)
+ ActiveRecord::Migrator.new(:up, list, @schema_migration)
end
end
def test_migrator_with_missing_version_numbers
assert_raises(ActiveRecord::UnknownMigrationVersionError) do
list = [ActiveRecord::Migration.new("Foo", 1), ActiveRecord::Migration.new("Bar", 2)]
- ActiveRecord::Migrator.new(:up, list, 3).run
+ ActiveRecord::Migrator.new(:up, list, @schema_migration, 3).run
end
assert_raises(ActiveRecord::UnknownMigrationVersionError) do
list = [ActiveRecord::Migration.new("Foo", 1), ActiveRecord::Migration.new("Bar", 2)]
- ActiveRecord::Migrator.new(:up, list, -1).run
+ ActiveRecord::Migrator.new(:up, list, @schema_migration, -1).run
end
assert_raises(ActiveRecord::UnknownMigrationVersionError) do
list = [ActiveRecord::Migration.new("Foo", 1), ActiveRecord::Migration.new("Bar", 2)]
- ActiveRecord::Migrator.new(:up, list, 0).run
+ ActiveRecord::Migrator.new(:up, list, @schema_migration, 0).run
end
assert_raises(ActiveRecord::UnknownMigrationVersionError) do
list = [ActiveRecord::Migration.new("Foo", 1), ActiveRecord::Migration.new("Bar", 2)]
- ActiveRecord::Migrator.new(:up, list, 3).migrate
+ ActiveRecord::Migrator.new(:up, list, @schema_migration, 3).migrate
end
assert_raises(ActiveRecord::UnknownMigrationVersionError) do
list = [ActiveRecord::Migration.new("Foo", 1), ActiveRecord::Migration.new("Bar", 2)]
- ActiveRecord::Migrator.new(:up, list, -1).migrate
+ ActiveRecord::Migrator.new(:up, list, @schema_migration, -1).migrate
end
end
def test_finds_migrations
- migrations = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/valid").migrations
+ schema_migration = ActiveRecord::Base.connection.schema_migration
+ migrations = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/valid", schema_migration).migrations
[[1, "ValidPeopleHaveLastNames"], [2, "WeNeedReminders"], [3, "InnocentJointable"]].each_with_index do |pair, i|
assert_equal migrations[i].version, pair.first
@@ -98,7 +100,8 @@ class MigratorTest < ActiveRecord::TestCase
end
def test_finds_migrations_in_subdirectories
- migrations = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/valid_with_subdirectories").migrations
+ schema_migration = ActiveRecord::Base.connection.schema_migration
+ migrations = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/valid_with_subdirectories", schema_migration).migrations
[[1, "ValidPeopleHaveLastNames"], [2, "WeNeedReminders"], [3, "InnocentJointable"]].each_with_index do |pair, i|
assert_equal migrations[i].version, pair.first
@@ -107,8 +110,9 @@ class MigratorTest < ActiveRecord::TestCase
end
def test_finds_migrations_from_two_directories
+ schema_migration = ActiveRecord::Base.connection.schema_migration
directories = [MIGRATIONS_ROOT + "/valid_with_timestamps", MIGRATIONS_ROOT + "/to_copy_with_timestamps"]
- migrations = ActiveRecord::MigrationContext.new(directories).migrations
+ migrations = ActiveRecord::MigrationContext.new(directories, schema_migration).migrations
[[20090101010101, "PeopleHaveHobbies"],
[20090101010202, "PeopleHaveDescriptions"],
@@ -121,14 +125,16 @@ class MigratorTest < ActiveRecord::TestCase
end
def test_finds_migrations_in_numbered_directory
- migrations = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/10_urban").migrations
+ schema_migration = ActiveRecord::Base.connection.schema_migration
+ migrations = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/10_urban", schema_migration).migrations
assert_equal 9, migrations[0].version
assert_equal "AddExpressions", migrations[0].name
end
def test_relative_migrations
+ schema_migration = ActiveRecord::Base.connection.schema_migration
list = Dir.chdir(MIGRATIONS_ROOT) do
- ActiveRecord::MigrationContext.new("valid").migrations
+ ActiveRecord::MigrationContext.new("valid", schema_migration).migrations
end
migration_proxy = list.find { |item|
@@ -138,9 +144,9 @@ class MigratorTest < ActiveRecord::TestCase
end
def test_finds_pending_migrations
- ActiveRecord::SchemaMigration.create!(version: "1")
+ @schema_migration.create!(version: "1")
migration_list = [ActiveRecord::Migration.new("foo", 1), ActiveRecord::Migration.new("bar", 3)]
- migrations = ActiveRecord::Migrator.new(:up, migration_list).pending_migrations
+ migrations = ActiveRecord::Migrator.new(:up, migration_list, @schema_migration).pending_migrations
assert_equal 1, migrations.size
assert_equal migration_list.last, migrations.first
@@ -148,35 +154,38 @@ class MigratorTest < ActiveRecord::TestCase
def test_migrations_status
path = MIGRATIONS_ROOT + "/valid"
+ schema_migration = ActiveRecord::Base.connection.schema_migration
- ActiveRecord::SchemaMigration.create(version: 2)
- ActiveRecord::SchemaMigration.create(version: 10)
+ @schema_migration.create(version: 2)
+ @schema_migration.create(version: 10)
assert_equal [
["down", "001", "Valid people have last names"],
["up", "002", "We need reminders"],
["down", "003", "Innocent jointable"],
["up", "010", "********** NO FILE **********"],
- ], ActiveRecord::MigrationContext.new(path).migrations_status
+ ], ActiveRecord::MigrationContext.new(path, schema_migration).migrations_status
end
def test_migrations_status_in_subdirectories
path = MIGRATIONS_ROOT + "/valid_with_subdirectories"
+ schema_migration = ActiveRecord::Base.connection.schema_migration
- ActiveRecord::SchemaMigration.create(version: 2)
- ActiveRecord::SchemaMigration.create(version: 10)
+ @schema_migration.create(version: 2)
+ @schema_migration.create(version: 10)
assert_equal [
["down", "001", "Valid people have last names"],
["up", "002", "We need reminders"],
["down", "003", "Innocent jointable"],
["up", "010", "********** NO FILE **********"],
- ], ActiveRecord::MigrationContext.new(path).migrations_status
+ ], ActiveRecord::MigrationContext.new(path, schema_migration).migrations_status
end
def test_migrations_status_with_schema_define_in_subdirectories
path = MIGRATIONS_ROOT + "/valid_with_subdirectories"
prev_paths = ActiveRecord::Migrator.migrations_paths
+ schema_migration = ActiveRecord::Base.connection.schema_migration
ActiveRecord::Migrator.migrations_paths = path
ActiveRecord::Schema.define(version: 3) do
@@ -186,16 +195,17 @@ class MigratorTest < ActiveRecord::TestCase
["up", "001", "Valid people have last names"],
["up", "002", "We need reminders"],
["up", "003", "Innocent jointable"],
- ], ActiveRecord::MigrationContext.new(path).migrations_status
+ ], ActiveRecord::MigrationContext.new(path, schema_migration).migrations_status
ensure
ActiveRecord::Migrator.migrations_paths = prev_paths
end
def test_migrations_status_from_two_directories
paths = [MIGRATIONS_ROOT + "/valid_with_timestamps", MIGRATIONS_ROOT + "/to_copy_with_timestamps"]
+ schema_migration = ActiveRecord::Base.connection.schema_migration
- ActiveRecord::SchemaMigration.create(version: "20100101010101")
- ActiveRecord::SchemaMigration.create(version: "20160528010101")
+ @schema_migration.create(version: "20100101010101")
+ @schema_migration.create(version: "20160528010101")
assert_equal [
["down", "20090101010101", "People have hobbies"],
@@ -204,18 +214,18 @@ class MigratorTest < ActiveRecord::TestCase
["down", "20100201010101", "Valid with timestamps we need reminders"],
["down", "20100301010101", "Valid with timestamps innocent jointable"],
["up", "20160528010101", "********** NO FILE **********"],
- ], ActiveRecord::MigrationContext.new(paths).migrations_status
+ ], ActiveRecord::MigrationContext.new(paths, schema_migration).migrations_status
end
def test_migrator_interleaved_migrations
pass_one = [Sensor.new("One", 1)]
- ActiveRecord::Migrator.new(:up, pass_one).migrate
+ ActiveRecord::Migrator.new(:up, pass_one, @schema_migration).migrate
assert pass_one.first.went_up
assert_not pass_one.first.went_down
pass_two = [Sensor.new("One", 1), Sensor.new("Three", 3)]
- ActiveRecord::Migrator.new(:up, pass_two).migrate
+ ActiveRecord::Migrator.new(:up, pass_two, @schema_migration).migrate
assert_not pass_two[0].went_up
assert pass_two[1].went_up
assert pass_two.all? { |x| !x.went_down }
@@ -224,7 +234,7 @@ class MigratorTest < ActiveRecord::TestCase
Sensor.new("Two", 2),
Sensor.new("Three", 3)]
- ActiveRecord::Migrator.new(:down, pass_three).migrate
+ ActiveRecord::Migrator.new(:down, pass_three, @schema_migration).migrate
assert pass_three[0].went_down
assert_not pass_three[1].went_down
assert pass_three[2].went_down
@@ -232,7 +242,7 @@ class MigratorTest < ActiveRecord::TestCase
def test_up_calls_up
migrations = [Sensor.new(nil, 0), Sensor.new(nil, 1), Sensor.new(nil, 2)]
- migrator = ActiveRecord::Migrator.new(:up, migrations)
+ migrator = ActiveRecord::Migrator.new(:up, migrations, @schema_migration)
migrator.migrate
assert migrations.all?(&:went_up)
assert migrations.all? { |m| !m.went_down }
@@ -243,7 +253,7 @@ class MigratorTest < ActiveRecord::TestCase
test_up_calls_up
migrations = [Sensor.new(nil, 0), Sensor.new(nil, 1), Sensor.new(nil, 2)]
- migrator = ActiveRecord::Migrator.new(:down, migrations)
+ migrator = ActiveRecord::Migrator.new(:down, migrations, @schema_migration)
migrator.migrate
assert migrations.all? { |m| !m.went_up }
assert migrations.all?(&:went_down)
@@ -251,30 +261,31 @@ class MigratorTest < ActiveRecord::TestCase
end
def test_current_version
- ActiveRecord::SchemaMigration.create!(version: "1000")
- migrator = ActiveRecord::MigrationContext.new("db/migrate")
+ @schema_migration.create!(version: "1000")
+ schema_migration = ActiveRecord::Base.connection.schema_migration
+ migrator = ActiveRecord::MigrationContext.new("db/migrate", schema_migration)
assert_equal 1000, migrator.current_version
end
def test_migrator_one_up
calls, migrations = sensors(3)
- ActiveRecord::Migrator.new(:up, migrations, 1).migrate
+ ActiveRecord::Migrator.new(:up, migrations, @schema_migration, 1).migrate
assert_equal [[:up, 1]], calls
calls.clear
- ActiveRecord::Migrator.new(:up, migrations, 2).migrate
+ ActiveRecord::Migrator.new(:up, migrations, @schema_migration, 2).migrate
assert_equal [[:up, 2]], calls
end
def test_migrator_one_down
calls, migrations = sensors(3)
- ActiveRecord::Migrator.new(:up, migrations).migrate
+ ActiveRecord::Migrator.new(:up, migrations, @schema_migration).migrate
assert_equal [[:up, 1], [:up, 2], [:up, 3]], calls
calls.clear
- ActiveRecord::Migrator.new(:down, migrations, 1).migrate
+ ActiveRecord::Migrator.new(:down, migrations, @schema_migration, 1).migrate
assert_equal [[:down, 3], [:down, 2]], calls
end
@@ -282,17 +293,17 @@ class MigratorTest < ActiveRecord::TestCase
def test_migrator_one_up_one_down
calls, migrations = sensors(3)
- ActiveRecord::Migrator.new(:up, migrations, 1).migrate
+ ActiveRecord::Migrator.new(:up, migrations, @schema_migration, 1).migrate
assert_equal [[:up, 1]], calls
calls.clear
- ActiveRecord::Migrator.new(:down, migrations, 0).migrate
+ ActiveRecord::Migrator.new(:down, migrations, @schema_migration, 0).migrate
assert_equal [[:down, 1]], calls
end
def test_migrator_double_up
calls, migrations = sensors(3)
- migrator = ActiveRecord::Migrator.new(:up, migrations, 1)
+ migrator = ActiveRecord::Migrator.new(:up, migrations, @schema_migration, 1)
assert_equal(0, migrator.current_version)
migrator.migrate
@@ -305,7 +316,7 @@ class MigratorTest < ActiveRecord::TestCase
def test_migrator_double_down
calls, migrations = sensors(3)
- migrator = ActiveRecord::Migrator.new(:up, migrations, 1)
+ migrator = ActiveRecord::Migrator.new(:up, migrations, @schema_migration, 1)
assert_equal 0, migrator.current_version
@@ -313,7 +324,7 @@ class MigratorTest < ActiveRecord::TestCase
assert_equal [[:up, 1]], calls
calls.clear
- migrator = ActiveRecord::Migrator.new(:down, migrations, 1)
+ migrator = ActiveRecord::Migrator.new(:down, migrations, @schema_migration, 1)
migrator.run
assert_equal [[:down, 1]], calls
calls.clear
@@ -328,12 +339,12 @@ class MigratorTest < ActiveRecord::TestCase
_, migrations = sensors(3)
ActiveRecord::Migration.verbose = true
- ActiveRecord::Migrator.new(:up, migrations, 1).migrate
+ ActiveRecord::Migrator.new(:up, migrations, @schema_migration, 1).migrate
assert_not_equal 0, ActiveRecord::Migration.message_count
ActiveRecord::Migration.message_count = 0
- ActiveRecord::Migrator.new(:down, migrations, 0).migrate
+ ActiveRecord::Migrator.new(:down, migrations, @schema_migration, 0).migrate
assert_not_equal 0, ActiveRecord::Migration.message_count
end
@@ -341,9 +352,9 @@ class MigratorTest < ActiveRecord::TestCase
_, migrations = sensors(3)
ActiveRecord::Migration.verbose = false
- ActiveRecord::Migrator.new(:up, migrations, 1).migrate
+ ActiveRecord::Migrator.new(:up, migrations, @schema_migration, 1).migrate
assert_equal 0, ActiveRecord::Migration.message_count
- ActiveRecord::Migrator.new(:down, migrations, 0).migrate
+ ActiveRecord::Migrator.new(:down, migrations, @schema_migration, 0).migrate
assert_equal 0, ActiveRecord::Migration.message_count
end
@@ -351,23 +362,24 @@ class MigratorTest < ActiveRecord::TestCase
calls, migrations = sensors(3)
# migrate up to 1
- ActiveRecord::Migrator.new(:up, migrations, 1).migrate
+ ActiveRecord::Migrator.new(:up, migrations, @schema_migration, 1).migrate
assert_equal [[:up, 1]], calls
calls.clear
# migrate down to 0
- ActiveRecord::Migrator.new(:down, migrations, 0).migrate
+ ActiveRecord::Migrator.new(:down, migrations, @schema_migration, 0).migrate
assert_equal [[:down, 1]], calls
calls.clear
# migrate down to 0 again
- ActiveRecord::Migrator.new(:down, migrations, 0).migrate
+ ActiveRecord::Migrator.new(:down, migrations, @schema_migration, 0).migrate
assert_equal [], calls
end
def test_migrator_going_down_due_to_version_target
+ schema_migration = ActiveRecord::Base.connection.schema_migration
calls, migrator = migrator_class(3)
- migrator = migrator.new("valid")
+ migrator = migrator.new("valid", schema_migration)
migrator.up(1)
assert_equal [[:up, 1]], calls
@@ -382,8 +394,9 @@ class MigratorTest < ActiveRecord::TestCase
end
def test_migrator_output_when_running_multiple_migrations
+ schema_migration = ActiveRecord::Base.connection.schema_migration
_, migrator = migrator_class(3)
- migrator = migrator.new("valid")
+ migrator = migrator.new("valid", schema_migration)
result = migrator.migrate
assert_equal(3, result.count)
@@ -397,8 +410,9 @@ class MigratorTest < ActiveRecord::TestCase
end
def test_migrator_output_when_running_single_migration
+ schema_migration = ActiveRecord::Base.connection.schema_migration
_, migrator = migrator_class(1)
- migrator = migrator.new("valid")
+ migrator = migrator.new("valid", schema_migration)
result = migrator.run(:up, 1)
@@ -406,8 +420,9 @@ class MigratorTest < ActiveRecord::TestCase
end
def test_migrator_rollback
+ schema_migration = ActiveRecord::Base.connection.schema_migration
_, migrator = migrator_class(3)
- migrator = migrator.new("valid")
+ migrator = migrator.new("valid", schema_migration)
migrator.migrate
assert_equal(3, migrator.current_version)
@@ -426,18 +441,20 @@ class MigratorTest < ActiveRecord::TestCase
end
def test_migrator_db_has_no_schema_migrations_table
+ schema_migration = ActiveRecord::Base.connection.schema_migration
_, migrator = migrator_class(3)
- migrator = migrator.new("valid")
+ migrator = migrator.new("valid", schema_migration)
- ActiveRecord::Base.connection.drop_table "schema_migrations", if_exists: true
- assert_not ActiveRecord::Base.connection.table_exists?("schema_migrations")
+ ActiveRecord::SchemaMigration.drop_table
+ assert_not_predicate ActiveRecord::SchemaMigration, :table_exists?
migrator.migrate(1)
- assert ActiveRecord::Base.connection.table_exists?("schema_migrations")
+ assert_predicate ActiveRecord::SchemaMigration, :table_exists?
end
def test_migrator_forward
+ schema_migration = ActiveRecord::Base.connection.schema_migration
_, migrator = migrator_class(3)
- migrator = migrator.new("/valid")
+ migrator = migrator.new("/valid", schema_migration)
migrator.migrate(1)
assert_equal(1, migrator.current_version)
@@ -450,18 +467,20 @@ class MigratorTest < ActiveRecord::TestCase
def test_only_loads_pending_migrations
# migrate up to 1
- ActiveRecord::SchemaMigration.create!(version: "1")
+ @schema_migration.create!(version: "1")
+ schema_migration = ActiveRecord::Base.connection.schema_migration
calls, migrator = migrator_class(3)
- migrator = migrator.new("valid")
+ migrator = migrator.new("valid", schema_migration)
migrator.migrate
assert_equal [[:up, 2], [:up, 3]], calls
end
def test_get_all_versions
+ schema_migration = ActiveRecord::Base.connection.schema_migration
_, migrator = migrator_class(3)
- migrator = migrator.new("valid")
+ migrator = migrator.new("valid", schema_migration)
migrator.migrate
assert_equal([1, 2, 3], migrator.get_all_versions)
diff --git a/activerecord/test/cases/multi_db_migrator_test.rb b/activerecord/test/cases/multi_db_migrator_test.rb
new file mode 100644
index 0000000000..650b3af6f0
--- /dev/null
+++ b/activerecord/test/cases/multi_db_migrator_test.rb
@@ -0,0 +1,218 @@
+# frozen_string_literal: true
+
+require "cases/helper"
+require "cases/migration/helper"
+
+class MultiDbMigratorTest < ActiveRecord::TestCase
+ self.use_transactional_tests = false
+
+ # Use this class to sense if migrations have gone
+ # up or down.
+ class Sensor < ActiveRecord::Migration::Current
+ attr_reader :went_up, :went_down
+
+ def initialize(name = self.class.name, version = nil)
+ super
+ @went_up = false
+ @went_down = false
+ end
+
+ def up; @went_up = true; end
+ def down; @went_down = true; end
+ end
+
+ def setup
+ super
+ @connection_a = ActiveRecord::Base.connection
+ @connection_b = ARUnit2Model.connection
+
+ @connection_a.schema_migration.create_table
+ @connection_b.schema_migration.create_table
+
+ @connection_a.schema_migration.delete_all rescue nil
+ @connection_b.schema_migration.delete_all rescue nil
+
+ @path_a = MIGRATIONS_ROOT + "/valid"
+ @path_b = MIGRATIONS_ROOT + "/to_copy"
+
+ @schema_migration_a = @connection_a.schema_migration
+ @migrations_a = ActiveRecord::MigrationContext.new(@path_a, @schema_migration_a).migrations
+ @schema_migration_b = @connection_b.schema_migration
+ @migrations_b = ActiveRecord::MigrationContext.new(@path_b, @schema_migration_b).migrations
+
+ @migrations_a_list = [[1, "ValidPeopleHaveLastNames"], [2, "WeNeedReminders"], [3, "InnocentJointable"]]
+ @migrations_b_list = [[1, "PeopleHaveHobbies"], [2, "PeopleHaveDescriptions"]]
+
+ @verbose_was = ActiveRecord::Migration.verbose
+
+ ActiveRecord::Migration.message_count = 0
+ ActiveRecord::Migration.class_eval do
+ undef :puts
+ def puts(*)
+ ActiveRecord::Migration.message_count += 1
+ end
+ end
+ end
+
+ teardown do
+ @connection_a.schema_migration.delete_all rescue nil
+ @connection_b.schema_migration.delete_all rescue nil
+
+ ActiveRecord::Migration.verbose = @verbose_was
+ ActiveRecord::Migration.class_eval do
+ undef :puts
+ def puts(*)
+ super
+ end
+ end
+ end
+
+ def test_finds_migrations
+ @migrations_a_list.each_with_index do |pair, i|
+ assert_equal @migrations_a[i].version, pair.first
+ assert_equal @migrations_a[i].name, pair.last
+ end
+
+ @migrations_b_list.each_with_index do |pair, i|
+ assert_equal @migrations_b[i].version, pair.first
+ assert_equal @migrations_b[i].name, pair.last
+ end
+ end
+
+ def test_migrations_status
+ @schema_migration_a.create(version: 2)
+ @schema_migration_a.create(version: 10)
+
+ assert_equal [
+ ["down", "001", "Valid people have last names"],
+ ["up", "002", "We need reminders"],
+ ["down", "003", "Innocent jointable"],
+ ["up", "010", "********** NO FILE **********"],
+ ], ActiveRecord::MigrationContext.new(@path_a, @schema_migration_a).migrations_status
+
+ @schema_migration_b.create(version: 4)
+
+ assert_equal [
+ ["down", "001", "People have hobbies"],
+ ["down", "002", "People have descriptions"],
+ ["up", "004", "********** NO FILE **********"]
+ ], ActiveRecord::MigrationContext.new(@path_b, @schema_migration_b).migrations_status
+ end
+
+ def test_get_all_versions
+ _, migrator_a = migrator_class(3)
+ migrator_a = migrator_a.new(@path_a, @schema_migration_a)
+
+ migrator_a.migrate
+ assert_equal([1, 2, 3], migrator_a.get_all_versions)
+
+ migrator_a.rollback
+ assert_equal([1, 2], migrator_a.get_all_versions)
+
+ migrator_a.rollback
+ assert_equal([1], migrator_a.get_all_versions)
+
+ migrator_a.rollback
+ assert_equal([], migrator_a.get_all_versions)
+
+ _, migrator_b = migrator_class(2)
+ migrator_b = migrator_b.new(@path_b, @schema_migration_b)
+
+ migrator_b.migrate
+ assert_equal([1, 2], migrator_b.get_all_versions)
+
+ migrator_b.rollback
+ assert_equal([1], migrator_b.get_all_versions)
+
+ migrator_b.rollback
+ assert_equal([], migrator_b.get_all_versions)
+ end
+
+ def test_finds_pending_migrations
+ @schema_migration_a.create!(version: "1")
+ migration_list_a = [ActiveRecord::Migration.new("foo", 1), ActiveRecord::Migration.new("bar", 3)]
+ migrations_a = ActiveRecord::Migrator.new(:up, migration_list_a, @schema_migration_a).pending_migrations
+
+ assert_equal 1, migrations_a.size
+ assert_equal migration_list_a.last, migrations_a.first
+
+ @schema_migration_b.create!(version: "1")
+ migration_list_b = [ActiveRecord::Migration.new("foo", 1), ActiveRecord::Migration.new("bar", 3)]
+ migrations_b = ActiveRecord::Migrator.new(:up, migration_list_b, @schema_migration_b).pending_migrations
+
+ assert_equal 1, migrations_b.size
+ assert_equal migration_list_b.last, migrations_b.first
+ end
+
+ def test_migrator_db_has_no_schema_migrations_table
+ _, migrator = migrator_class(3)
+ migrator = migrator.new(@path_a, @schema_migration_a)
+
+ @schema_migration_a.drop_table
+ assert_not @connection_a.table_exists?("schema_migrations")
+ migrator.migrate(1)
+ assert @connection_a.table_exists?("schema_migrations")
+
+ _, migrator = migrator_class(3)
+ migrator = migrator.new(@path_b, @schema_migration_b)
+
+ @schema_migration_b.drop_table
+ assert_not @connection_b.table_exists?("schema_migrations")
+ migrator.migrate(1)
+ assert @connection_b.table_exists?("schema_migrations")
+ end
+
+ def test_migrator_forward
+ _, migrator = migrator_class(3)
+ migrator = migrator.new(@path_a, @schema_migration_a)
+ migrator.migrate(1)
+ assert_equal(1, migrator.current_version)
+
+ migrator.forward(2)
+ assert_equal(3, migrator.current_version)
+
+ migrator.forward
+ assert_equal(3, migrator.current_version)
+
+ _, migrator_b = migrator_class(3)
+ migrator_b = migrator_b.new(@path_b, @schema_migration_b)
+ migrator_b.migrate(1)
+ assert_equal(1, migrator_b.current_version)
+
+ migrator_b.forward(2)
+ assert_equal(3, migrator_b.current_version)
+
+ migrator_b.forward
+ assert_equal(3, migrator_b.current_version)
+ end
+
+ private
+ def m(name, version)
+ x = Sensor.new name, version
+ x.extend(Module.new {
+ define_method(:up) { yield(:up, x); super() }
+ define_method(:down) { yield(:down, x); super() }
+ }) if block_given?
+ end
+
+ def sensors(count)
+ calls = []
+ migrations = count.times.map { |i|
+ m(nil, i + 1) { |c, migration|
+ calls << [c, migration.version]
+ }
+ }
+ [calls, migrations]
+ end
+
+ def migrator_class(count)
+ calls, migrations = sensors(count)
+
+ migrator = Class.new(ActiveRecord::MigrationContext) {
+ define_method(:migrations) { |*|
+ migrations
+ }
+ }
+ [calls, migrator]
+ end
+end
diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb
index bb1c1ea17d..b49e62bee6 100644
--- a/activerecord/test/cases/nested_attributes_test.rb
+++ b/activerecord/test/cases/nested_attributes_test.rb
@@ -851,7 +851,6 @@ module NestedAttributesOnACollectionAssociationTests
end
private
-
def association_setter
@association_setter ||= "#{@association_name}_attributes=".to_sym
end
diff --git a/activerecord/test/cases/pooled_connections_test.rb b/activerecord/test/cases/pooled_connections_test.rb
index 080aeb0989..d783b2945d 100644
--- a/activerecord/test/cases/pooled_connections_test.rb
+++ b/activerecord/test/cases/pooled_connections_test.rb
@@ -72,7 +72,6 @@ class PooledConnectionsTest < ActiveRecord::TestCase
end
private
-
def add_record(name)
ActiveRecord::Base.connection_pool.with_connection { Project.create! name: name }
end
diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb
index eb32b690aa..79bd6906d1 100644
--- a/activerecord/test/cases/query_cache_test.rb
+++ b/activerecord/test/cases/query_cache_test.rb
@@ -335,11 +335,7 @@ class QueryCacheTest < ActiveRecord::TestCase
def test_cache_does_not_wrap_results_in_arrays
Task.cache do
- if current_adapter?(:SQLite3Adapter, :Mysql2Adapter, :PostgreSQLAdapter, :OracleAdapter)
- assert_equal 2, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
- else
- assert_instance_of String, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
- end
+ assert_equal 2, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
end
end
@@ -540,8 +536,24 @@ class QueryCacheTest < ActiveRecord::TestCase
ActiveRecord::Base.connection_handlers = { writing: ActiveRecord::Base.default_connection_handler }
end
- private
+ test "query cache is enabled in threads with shared connection" do
+ ActiveRecord::Base.connection_pool.lock_thread = true
+
+ assert_cache :off
+ thread_a = Thread.new do
+ middleware { |env|
+ assert_cache :clean
+ [200, {}, nil]
+ }.call({})
+ end
+
+ thread_a.join
+
+ ActiveRecord::Base.connection_pool.lock_thread = false
+ end
+
+ private
def with_temporary_connection_pool
old_pool = ActiveRecord::Base.connection_handler.retrieve_connection_pool(ActiveRecord::Base.connection_specification_name)
new_pool = ActiveRecord::ConnectionAdapters::ConnectionPool.new ActiveRecord::Base.connection_pool.spec
diff --git a/activerecord/test/cases/relation/where_clause_test.rb b/activerecord/test/cases/relation/where_clause_test.rb
index b26a1a1d80..35db3d1175 100644
--- a/activerecord/test/cases/relation/where_clause_test.rb
+++ b/activerecord/test/cases/relation/where_clause_test.rb
@@ -233,7 +233,6 @@ class ActiveRecord::Relation
end
private
-
def table
Arel::Table.new("table")
end
diff --git a/activerecord/test/cases/relation/where_test.rb b/activerecord/test/cases/relation/where_test.rb
index 6c1e3e7fec..aad30ddea0 100644
--- a/activerecord/test/cases/relation/where_test.rb
+++ b/activerecord/test/cases/relation/where_test.rb
@@ -18,7 +18,7 @@ require "support/stubs/strong_parameters"
module ActiveRecord
class WhereTest < ActiveRecord::TestCase
- fixtures :posts, :edges, :authors, :author_addresses, :binaries, :essays, :cars, :treasures, :price_estimates, :topics
+ fixtures :posts, :comments, :edges, :authors, :author_addresses, :binaries, :essays, :cars, :treasures, :price_estimates, :topics
def test_in_clause_is_correctly_sliced
assert_called(Author.connection, :in_clause_length, returns: 1) do
@@ -27,6 +27,11 @@ module ActiveRecord
end
end
+ def test_type_casting_nested_joins
+ comment = comments(:eager_other_comment1)
+ assert_equal [comment], Comment.joins(post: :author).where(authors: { id: "2-foo" })
+ end
+
def test_where_copies_bind_params
author = authors(:david)
posts = author.posts.where("posts.id != 1")
diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb
index 3f370e5ede..e74fb1a098 100644
--- a/activerecord/test/cases/relation_test.rb
+++ b/activerecord/test/cases/relation_test.rb
@@ -363,6 +363,13 @@ module ActiveRecord
assert_match %r{/\*\+ BADHINT \*/}, post_with_hint.to_sql
end
+ def test_does_not_duplicate_optimizer_hints_on_merge
+ escaped_table = Post.connection.quote_table_name("posts")
+ expected = "SELECT /*+ OMGHINT */ #{escaped_table}.* FROM #{escaped_table}"
+ query = Post.optimizer_hints("OMGHINT").merge(Post.optimizer_hints("OMGHINT")).to_sql
+ assert_equal expected, query
+ end
+
class EnsureRoundTripTypeCasting < ActiveRecord::Type::Value
def type
:string
@@ -405,7 +412,6 @@ module ActiveRecord
end
private
-
def skip_if_sqlite3_version_includes_quoting_bug
if sqlite3_version_includes_quoting_bug?
skip <<-ERROR.squish
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index 2417775ef1..1a20fe5dc2 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -298,7 +298,7 @@ class RelationTest < ActiveRecord::TestCase
end
def test_reverse_order_with_function
- topics = Topic.order(Arel.sql("length(title)")).reverse_order
+ topics = Topic.order("length(title)").reverse_order
assert_equal topics(:second).title, topics.first.title
end
@@ -308,9 +308,9 @@ class RelationTest < ActiveRecord::TestCase
end
def test_reverse_order_with_function_other_predicates
- topics = Topic.order(Arel.sql("author_name, length(title), id")).reverse_order
+ topics = Topic.order("author_name, length(title), id").reverse_order
assert_equal topics(:second).title, topics.first.title
- topics = Topic.order(Arel.sql("length(author_name), id, length(title)")).reverse_order
+ topics = Topic.order("length(author_name), id, length(title)").reverse_order
assert_equal topics(:fifth).title, topics.first.title
end
@@ -337,21 +337,21 @@ class RelationTest < ActiveRecord::TestCase
def test_reverse_order_with_nulls_first_or_last
assert_raises(ActiveRecord::IrreversibleOrderError) do
- Topic.order(Arel.sql("title NULLS FIRST")).reverse_order
+ Topic.order("title NULLS FIRST").reverse_order
end
assert_raises(ActiveRecord::IrreversibleOrderError) do
- Topic.order(Arel.sql("title NULLS FIRST")).reverse_order
+ Topic.order("title NULLS FIRST").reverse_order
end
assert_raises(ActiveRecord::IrreversibleOrderError) do
- Topic.order(Arel.sql("title nulls last")).reverse_order
+ Topic.order("title nulls last").reverse_order
end
assert_raises(ActiveRecord::IrreversibleOrderError) do
- Topic.order(Arel.sql("title NULLS FIRST, author_name")).reverse_order
+ Topic.order("title NULLS FIRST, author_name").reverse_order
end
assert_raises(ActiveRecord::IrreversibleOrderError) do
- Topic.order(Arel.sql("author_name, title nulls last")).reverse_order
+ Topic.order("author_name, title nulls last").reverse_order
end
- end
+ end if current_adapter?(:PostgreSQLAdapter, :OracleAdapter)
def test_default_reverse_order_on_table_without_primary_key
assert_raises(ActiveRecord::IrreversibleOrderError) do
@@ -706,7 +706,7 @@ class RelationTest < ActiveRecord::TestCase
end
def test_to_sql_on_eager_join
- expected = assert_sql {
+ expected = capture_sql {
Post.eager_load(:last_comment).order("comments.id DESC").to_a
}.first
actual = Post.eager_load(:last_comment).order("comments.id DESC").to_sql
@@ -1679,7 +1679,7 @@ class RelationTest < ActiveRecord::TestCase
scope = Post.order("comments.body")
assert_equal ["comments"], scope.references_values
- scope = Post.order(Arel.sql("#{Comment.quoted_table_name}.#{Comment.quoted_primary_key}"))
+ scope = Post.order("#{Comment.quoted_table_name}.#{Comment.quoted_primary_key}")
if current_adapter?(:OracleAdapter)
assert_equal ["COMMENTS"], scope.references_values
else
@@ -1696,7 +1696,7 @@ class RelationTest < ActiveRecord::TestCase
scope = Post.order("comments.body asc")
assert_equal ["comments"], scope.references_values
- scope = Post.order(Arel.sql("foo(comments.body)"))
+ scope = Post.order("foo(comments.body)")
assert_equal [], scope.references_values
end
@@ -1704,7 +1704,7 @@ class RelationTest < ActiveRecord::TestCase
scope = Post.reorder("comments.body")
assert_equal %w(comments), scope.references_values
- scope = Post.reorder(Arel.sql("#{Comment.quoted_table_name}.#{Comment.quoted_primary_key}"))
+ scope = Post.reorder("#{Comment.quoted_table_name}.#{Comment.quoted_primary_key}")
if current_adapter?(:OracleAdapter)
assert_equal ["COMMENTS"], scope.references_values
else
@@ -1721,7 +1721,7 @@ class RelationTest < ActiveRecord::TestCase
scope = Post.reorder("comments.body asc")
assert_equal %w(comments), scope.references_values
- scope = Post.reorder(Arel.sql("foo(comments.body)"))
+ scope = Post.reorder("foo(comments.body)")
assert_equal [], scope.references_values
end
@@ -1955,8 +1955,8 @@ class RelationTest < ActiveRecord::TestCase
test "joins with order by custom attribute" do
companies = Company.create!([{ name: "test1" }, { name: "test2" }])
companies.each { |company| company.contracts.create! }
- assert_equal companies, Company.joins(:contracts).order(:metadata)
- assert_equal companies.reverse, Company.joins(:contracts).order(metadata: :desc)
+ assert_equal companies, Company.joins(:contracts).order(:metadata, :count)
+ assert_equal companies.reverse, Company.joins(:contracts).order(metadata: :desc, count: :desc)
end
test "delegations do not leak to other classes" do
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index 49e9be9565..bb7184c5fc 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -33,6 +33,7 @@ class SchemaDumperTest < ActiveRecord::TestCase
schema_info = ActiveRecord::Base.connection.dump_schema_information
assert_match(/20100201010101.*20100301010101/m, schema_info)
+ assert_includes schema_info, "20100101010101"
ensure
ActiveRecord::SchemaMigration.delete_all
end
diff --git a/activerecord/test/cases/schema_loading_test.rb b/activerecord/test/cases/schema_loading_test.rb
index f539156466..5da2d9e08f 100644
--- a/activerecord/test/cases/schema_loading_test.rb
+++ b/activerecord/test/cases/schema_loading_test.rb
@@ -43,7 +43,6 @@ class SchemaLoadingTest < ActiveRecord::TestCase
end
private
-
def define_model
Class.new(ActiveRecord::Base) do
include SchemaLoadCounter
diff --git a/activerecord/test/cases/tasks/database_tasks_test.rb b/activerecord/test/cases/tasks/database_tasks_test.rb
index ffe94eee0f..6b6861465b 100644
--- a/activerecord/test/cases/tasks/database_tasks_test.rb
+++ b/activerecord/test/cases/tasks/database_tasks_test.rb
@@ -835,7 +835,6 @@ module ActiveRecord
end
private
-
def capture_migration_status
capture(:stdout) do
ActiveRecord::Tasks::DatabaseTasks.migrate_status
diff --git a/activerecord/test/cases/tasks/mysql_rake_test.rb b/activerecord/test/cases/tasks/mysql_rake_test.rb
index 552e623fd4..ac3c5bc26e 100644
--- a/activerecord/test/cases/tasks/mysql_rake_test.rb
+++ b/activerecord/test/cases/tasks/mysql_rake_test.rb
@@ -7,7 +7,10 @@ if current_adapter?(:Mysql2Adapter)
module ActiveRecord
class MysqlDBCreateTest < ActiveRecord::TestCase
def setup
- @connection = Class.new { def create_database(*); end }.new
+ @connection = Class.new do
+ def create_database(*); end
+ def error_number(_); end
+ end.new
@configuration = {
"adapter" => "mysql2",
"database" => "my-app-db"
@@ -90,9 +93,11 @@ if current_adapter?(:Mysql2Adapter)
with_stubbed_connection_establish_connection do
ActiveRecord::Base.connection.stub(
:create_database,
- proc { raise ActiveRecord::Tasks::DatabaseAlreadyExists }
+ proc { raise ActiveRecord::StatementInvalid }
) do
- ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ ActiveRecord::Base.connection.stub(:error_number, 1007) do
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
assert_equal "Database 'my-app-db' already exists\n", $stderr.string
end
@@ -100,7 +105,6 @@ if current_adapter?(:Mysql2Adapter)
end
private
-
def with_stubbed_connection_establish_connection
ActiveRecord::Base.stub(:establish_connection, nil) do
ActiveRecord::Base.stub(:connection, @connection) do
@@ -180,7 +184,6 @@ if current_adapter?(:Mysql2Adapter)
end
private
-
def with_stubbed_connection_establish_connection
ActiveRecord::Base.stub(:establish_connection, nil) do
ActiveRecord::Base.stub(:connection, @connection) do
@@ -233,7 +236,6 @@ if current_adapter?(:Mysql2Adapter)
end
private
-
def with_stubbed_connection_establish_connection
ActiveRecord::Base.stub(:establish_connection, nil) do
ActiveRecord::Base.stub(:connection, @connection) do
diff --git a/activerecord/test/cases/tasks/postgresql_rake_test.rb b/activerecord/test/cases/tasks/postgresql_rake_test.rb
index 065ba7734c..f9df650687 100644
--- a/activerecord/test/cases/tasks/postgresql_rake_test.rb
+++ b/activerecord/test/cases/tasks/postgresql_rake_test.rb
@@ -139,7 +139,6 @@ if current_adapter?(:PostgreSQLAdapter)
end
private
-
def with_stubbed_connection_establish_connection
ActiveRecord::Base.stub(:connection, @connection) do
ActiveRecord::Base.stub(:establish_connection, nil) do
@@ -201,7 +200,6 @@ if current_adapter?(:PostgreSQLAdapter)
end
private
-
def with_stubbed_connection_establish_connection
ActiveRecord::Base.stub(:connection, @connection) do
ActiveRecord::Base.stub(:establish_connection, nil) do
@@ -301,7 +299,6 @@ if current_adapter?(:PostgreSQLAdapter)
end
private
-
def with_stubbed_connection
ActiveRecord::Base.stub(:connection, @connection) do
yield
diff --git a/activerecord/test/cases/test_case.rb b/activerecord/test/cases/test_case.rb
index 78dc0a6d9f..1b8bad32a4 100644
--- a/activerecord/test/cases/test_case.rb
+++ b/activerecord/test/cases/test_case.rb
@@ -34,7 +34,7 @@ module ActiveRecord
ActiveRecord::Base.connection.materialize_transactions
SQLCounter.clear_log
yield
- SQLCounter.log_all.dup
+ SQLCounter.log.dup
end
def assert_sql(*patterns_to_match)
@@ -107,20 +107,12 @@ module ActiveRecord
clear_log
- self.ignored_sql = [/^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/]
-
- attr_reader :ignore
-
- def initialize(ignore = Regexp.union(self.class.ignored_sql))
- @ignore = ignore
- end
-
def call(name, start, finish, message_id, values)
return if values[:cached]
sql = values[:sql]
self.class.log_all << sql
- self.class.log << sql unless values[:name] == "SCHEMA" || ignore.match?(sql)
+ self.class.log << sql unless ["SCHEMA", "TRANSACTION"].include? values[:name]
end
end
diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb
index 135e2cb382..19b89ab08c 100644
--- a/activerecord/test/cases/transaction_callbacks_test.rb
+++ b/activerecord/test/cases/transaction_callbacks_test.rb
@@ -460,7 +460,6 @@ class TransactionCallbacksTest < ActiveRecord::TestCase
end
private
-
def add_transaction_execution_blocks(record)
record.after_commit_block(:create) { |r| r.history << :commit_on_create }
record.after_commit_block(:update) { |r| r.history << :commit_on_update }
@@ -551,6 +550,8 @@ class CallbacksOnMultipleActionsTest < ActiveRecord::TestCase
end
class CallbacksOnDestroyUpdateActionRaceTest < ActiveRecord::TestCase
+ self.use_transactional_tests = false
+
class TopicWithHistory < ActiveRecord::Base
self.table_name = :topics
@@ -564,11 +565,22 @@ class CallbacksOnDestroyUpdateActionRaceTest < ActiveRecord::TestCase
end
class TopicWithCallbacksOnDestroy < TopicWithHistory
- after_commit(on: :destroy) { |record| record.class.history << :destroy }
+ after_commit(on: :destroy) { |record| record.class.history << :commit_on_destroy }
+ after_rollback(on: :destroy) { |record| record.class.history << :rollback_on_destroy }
+
+ before_destroy :before_destroy_for_transaction
+
+ private
+ def before_destroy_for_transaction; end
end
class TopicWithCallbacksOnUpdate < TopicWithHistory
- after_commit(on: :update) { |record| record.class.history << :update }
+ after_commit(on: :update) { |record| record.class.history << :commit_on_update }
+
+ before_save :before_save_for_transaction
+
+ private
+ def before_save_for_transaction; end
end
def test_trigger_once_on_multiple_deletions
@@ -576,10 +588,39 @@ class CallbacksOnDestroyUpdateActionRaceTest < ActiveRecord::TestCase
topic = TopicWithCallbacksOnDestroy.new
topic.save
topic_clone = TopicWithCallbacksOnDestroy.find(topic.id)
+
+ topic.define_singleton_method(:before_destroy_for_transaction) do
+ topic_clone.destroy
+ end
+
topic.destroy
- topic_clone.destroy
- assert_equal [:destroy], TopicWithCallbacksOnDestroy.history
+ assert_equal [:commit_on_destroy], TopicWithCallbacksOnDestroy.history
+ end
+
+ def test_rollback_on_multiple_deletions
+ TopicWithCallbacksOnDestroy.clear_history
+ topic = TopicWithCallbacksOnDestroy.new
+ topic.save
+ topic_clone = TopicWithCallbacksOnDestroy.find(topic.id)
+
+ topic.define_singleton_method(:before_destroy_for_transaction) do
+ topic_clone.update!(author_name: "Test Author Clone")
+ topic_clone.destroy
+ end
+
+ TopicWithCallbacksOnDestroy.transaction do
+ topic.update!(author_name: "Test Author")
+ topic.destroy
+ raise ActiveRecord::Rollback
+ end
+
+ assert_not_predicate topic, :destroyed?
+ assert_not_predicate topic_clone, :destroyed?
+ assert_equal [nil, "Test Author"], topic.author_name_change_to_be_saved
+ assert_equal [nil, "Test Author Clone"], topic_clone.author_name_change_to_be_saved
+
+ assert_equal [:rollback_on_destroy], TopicWithCallbacksOnDestroy.history
end
def test_trigger_on_update_where_row_was_deleted
@@ -587,7 +628,11 @@ class CallbacksOnDestroyUpdateActionRaceTest < ActiveRecord::TestCase
topic = TopicWithCallbacksOnUpdate.new
topic.save
topic_clone = TopicWithCallbacksOnUpdate.find(topic.id)
- topic.destroy
+
+ topic_clone.define_singleton_method(:before_save_for_transaction) do
+ topic.destroy
+ end
+
topic_clone.author_name = "Test Author"
topic_clone.save
diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb
index 6795996cca..b5c1cac3d9 100644
--- a/activerecord/test/cases/transactions_test.rb
+++ b/activerecord/test/cases/transactions_test.rb
@@ -1077,7 +1077,6 @@ class TransactionTest < ActiveRecord::TestCase
end
private
-
%w(validation save destroy).each do |filter|
define_method("add_cancelling_before_#{filter}_with_db_side_effect_to_topic") do |topic|
meta = class << topic; self; end
diff --git a/activerecord/test/cases/unsafe_raw_sql_test.rb b/activerecord/test/cases/unsafe_raw_sql_test.rb
index d5d8f2a09a..87edb163f2 100644
--- a/activerecord/test/cases/unsafe_raw_sql_test.rb
+++ b/activerecord/test/cases/unsafe_raw_sql_test.rb
@@ -77,7 +77,7 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
assert_equal ids_expected, ids_disabled
end
- test "order: allows table and column name" do
+ test "order: allows table and column names" do
ids_expected = Post.order(Arel.sql("title")).pluck(:id)
ids_depr = with_unsafe_raw_sql_deprecated { Post.order("posts.title").pluck(:id) }
@@ -87,6 +87,17 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
assert_equal ids_expected, ids_disabled
end
+ test "order: allows quoted table and column names" do
+ ids_expected = Post.order(Arel.sql("title")).pluck(:id)
+
+ quoted_title = Post.connection.quote_table_name("posts.title")
+ ids_depr = with_unsafe_raw_sql_deprecated { Post.order(quoted_title).pluck(:id) }
+ ids_disabled = with_unsafe_raw_sql_disabled { Post.order(quoted_title).pluck(:id) }
+
+ assert_equal ids_expected, ids_depr
+ assert_equal ids_expected, ids_disabled
+ end
+
test "order: allows column name and direction in string" do
ids_expected = Post.order(Arel.sql("title desc")).pluck(:id)
@@ -116,10 +127,10 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
["asc", "desc", ""].each do |direction|
%w(first last).each do |position|
- ids_expected = Post.order(Arel.sql("type #{direction} nulls #{position}")).pluck(:id)
+ ids_expected = Post.order(Arel.sql("type::text #{direction} nulls #{position}")).pluck(:id)
- ids_depr = with_unsafe_raw_sql_deprecated { Post.order("type #{direction} nulls #{position}").pluck(:id) }
- ids_disabled = with_unsafe_raw_sql_disabled { Post.order("type #{direction} nulls #{position}").pluck(:id) }
+ ids_depr = with_unsafe_raw_sql_deprecated { Post.order("type::text #{direction} nulls #{position}").pluck(:id) }
+ ids_disabled = with_unsafe_raw_sql_disabled { Post.order("type::text #{direction} nulls #{position}").pluck(:id) }
assert_equal ids_expected, ids_depr
assert_equal ids_expected, ids_disabled
@@ -130,7 +141,7 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
test "order: disallows invalid column name" do
with_unsafe_raw_sql_disabled do
assert_raises(ActiveRecord::UnknownAttributeReference) do
- Post.order("len(title) asc").pluck(:id)
+ Post.order("REPLACE(title, 'misc', 'zzzz') asc").pluck(:id)
end
end
end
@@ -146,7 +157,7 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
test "order: disallows invalid column with direction" do
with_unsafe_raw_sql_disabled do
assert_raises(ActiveRecord::UnknownAttributeReference) do
- Post.order("len(title)" => :asc).pluck(:id)
+ Post.order("REPLACE(title, 'misc', 'zzzz')" => :asc).pluck(:id)
end
end
end
@@ -179,7 +190,7 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
test "order: disallows invalid Array arguments" do
with_unsafe_raw_sql_disabled do
assert_raises(ActiveRecord::UnknownAttributeReference) do
- Post.order(["author_id", "length(title)"]).pluck(:id)
+ Post.order(["author_id", "REPLACE(title, 'misc', 'zzzz')"]).pluck(:id)
end
end
end
@@ -187,8 +198,8 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
test "order: allows valid Array arguments" do
ids_expected = Post.order(Arel.sql("author_id, length(title)")).pluck(:id)
- ids_depr = with_unsafe_raw_sql_deprecated { Post.order(["author_id", Arel.sql("length(title)")]).pluck(:id) }
- ids_disabled = with_unsafe_raw_sql_disabled { Post.order(["author_id", Arel.sql("length(title)")]).pluck(:id) }
+ ids_depr = with_unsafe_raw_sql_deprecated { Post.order(["author_id", "length(title)"]).pluck(:id) }
+ ids_disabled = with_unsafe_raw_sql_disabled { Post.order(["author_id", "length(title)"]).pluck(:id) }
assert_equal ids_expected, ids_depr
assert_equal ids_expected, ids_disabled
@@ -197,7 +208,7 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
test "order: logs deprecation warning for unrecognized column" do
with_unsafe_raw_sql_deprecated do
assert_deprecated(/Dangerous query method/) do
- Post.order("length(title)")
+ Post.order("REPLACE(title, 'misc', 'zzzz')")
end
end
end
@@ -212,6 +223,16 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
assert_equal titles_expected, titles_disabled
end
+ test "pluck: allows string column name with function and alias" do
+ titles_expected = Post.pluck(Arel.sql("UPPER(title)"))
+
+ titles_depr = with_unsafe_raw_sql_deprecated { Post.pluck("UPPER(title) AS title") }
+ titles_disabled = with_unsafe_raw_sql_disabled { Post.pluck("UPPER(title) AS title") }
+
+ assert_equal titles_expected, titles_depr
+ assert_equal titles_expected, titles_disabled
+ end
+
test "pluck: allows symbol column name" do
titles_expected = Post.pluck(Arel.sql("title"))
@@ -262,10 +283,21 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
assert_equal titles_expected, titles_disabled
end
+ test "pluck: allows quoted table and column names" do
+ titles_expected = Post.pluck(Arel.sql("title"))
+
+ quoted_title = Post.connection.quote_table_name("posts.title")
+ titles_depr = with_unsafe_raw_sql_deprecated { Post.pluck(quoted_title) }
+ titles_disabled = with_unsafe_raw_sql_disabled { Post.pluck(quoted_title) }
+
+ assert_equal titles_expected, titles_depr
+ assert_equal titles_expected, titles_disabled
+ end
+
test "pluck: disallows invalid column name" do
with_unsafe_raw_sql_disabled do
assert_raises(ActiveRecord::UnknownAttributeReference) do
- Post.pluck("length(title)")
+ Post.pluck("REPLACE(title, 'misc', 'zzzz')")
end
end
end
@@ -273,7 +305,7 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
test "pluck: disallows invalid column name amongst valid names" do
with_unsafe_raw_sql_disabled do
assert_raises(ActiveRecord::UnknownAttributeReference) do
- Post.pluck(:title, "length(title)")
+ Post.pluck(:title, "REPLACE(title, 'misc', 'zzzz')")
end
end
end
@@ -281,7 +313,7 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
test "pluck: disallows invalid column names with includes" do
with_unsafe_raw_sql_disabled do
assert_raises(ActiveRecord::UnknownAttributeReference) do
- Post.includes(:comments).pluck(:title, "length(title)")
+ Post.includes(:comments).pluck(:title, "REPLACE(title, 'misc', 'zzzz')")
end
end
end
@@ -296,24 +328,25 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
test "pluck: logs deprecation warning" do
with_unsafe_raw_sql_deprecated do
assert_deprecated(/Dangerous query method/) do
- Post.includes(:comments).pluck(:title, "length(title)")
+ Post.includes(:comments).pluck(:title, "REPLACE(title, 'misc', 'zzzz')")
end
end
end
- def with_unsafe_raw_sql_disabled(&blk)
- with_config(:disabled, &blk)
- end
+ private
+ def with_unsafe_raw_sql_disabled(&block)
+ with_config(:disabled, &block)
+ end
- def with_unsafe_raw_sql_deprecated(&blk)
- with_config(:deprecated, &blk)
- end
+ def with_unsafe_raw_sql_deprecated(&block)
+ with_config(:deprecated, &block)
+ end
- def with_config(new_value, &blk)
- old_value = ActiveRecord::Base.allow_unsafe_raw_sql
- ActiveRecord::Base.allow_unsafe_raw_sql = new_value
- blk.call
- ensure
- ActiveRecord::Base.allow_unsafe_raw_sql = old_value
- end
+ def with_config(new_value, &block)
+ old_value = ActiveRecord::Base.allow_unsafe_raw_sql
+ ActiveRecord::Base.allow_unsafe_raw_sql = new_value
+ yield
+ ensure
+ ActiveRecord::Base.allow_unsafe_raw_sql = old_value
+ end
end
diff --git a/activerecord/test/cases/validations/i18n_validation_test.rb b/activerecord/test/cases/validations/i18n_validation_test.rb
index 2645776ab7..4dd8a4a82b 100644
--- a/activerecord/test/cases/validations/i18n_validation_test.rb
+++ b/activerecord/test/cases/validations/i18n_validation_test.rb
@@ -51,7 +51,7 @@ class I18nValidationTest < ActiveRecord::TestCase
test "validates_uniqueness_of on generated message #{name}" do
Topic.validates_uniqueness_of :title, validation_options
@topic.title = unique_topic.title
- assert_called_with(@topic.errors, :generate_message, [:title, :taken, generate_message_options.merge(value: "unique!")]) do
+ assert_called_with(ActiveModel::Error, :generate_message, [:title, :taken, @topic, generate_message_options.merge(value: "unique!")]) do
@topic.valid?
@topic.errors.messages
end
@@ -61,7 +61,7 @@ class I18nValidationTest < ActiveRecord::TestCase
COMMON_CASES.each do |name, validation_options, generate_message_options|
test "validates_associated on generated message #{name}" do
Topic.validates_associated :replies, validation_options
- assert_called_with(replied_topic.errors, :generate_message, [:replies, :invalid, generate_message_options.merge(value: replied_topic.replies)]) do
+ assert_called_with(ActiveModel::Error, :generate_message, [:replies, :invalid, replied_topic, generate_message_options.merge(value: replied_topic.replies)]) do
replied_topic.save
replied_topic.errors.messages
end
diff --git a/activerecord/test/cases/yaml_serialization_test.rb b/activerecord/test/cases/yaml_serialization_test.rb
index 60ebdce178..7003afa33a 100644
--- a/activerecord/test/cases/yaml_serialization_test.rb
+++ b/activerecord/test/cases/yaml_serialization_test.rb
@@ -130,7 +130,6 @@ class YamlSerializationTest < ActiveRecord::TestCase
end
private
-
def yaml_fixture(file_name)
path = File.expand_path(
"../support/yaml_compatibility_fixtures/#{file_name}.yml",
diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb
index b52b643ad7..da7e4139b1 100644
--- a/activerecord/test/models/author.rb
+++ b/activerecord/test/models/author.rb
@@ -116,6 +116,7 @@ class Author < ActiveRecord::Base
has_many :tags_with_primary_key, through: :posts
has_many :books
+ has_many :published_books, class_name: "PublishedBook"
has_many :unpublished_books, -> { where(status: [:proposed, :written]) }, class_name: "Book"
has_many :subscriptions, through: :books
has_many :subscribers, -> { order("subscribers.nick") }, through: :subscriptions
diff --git a/activerecord/test/models/book.rb b/activerecord/test/models/book.rb
index afdda1a81e..43b82e6047 100644
--- a/activerecord/test/models/book.rb
+++ b/activerecord/test/models/book.rb
@@ -24,3 +24,9 @@ class Book < ActiveRecord::Base
"do publish work..."
end
end
+
+class PublishedBook < ActiveRecord::Base
+ self.table_name = "books"
+
+ validates_uniqueness_of :isbn
+end
diff --git a/activerecord/test/models/club.rb b/activerecord/test/models/club.rb
index bb49fb300c..890e427616 100644
--- a/activerecord/test/models/club.rb
+++ b/activerecord/test/models/club.rb
@@ -15,7 +15,6 @@ class Club < ActiveRecord::Base
accepts_nested_attributes_for :membership
private
-
def private_method
"I'm sorry sir, this is a *private* club, not a *pirate* club"
end
diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb
index a0f48d23f1..339b5c8ca8 100644
--- a/activerecord/test/models/company.rb
+++ b/activerecord/test/models/company.rb
@@ -25,7 +25,6 @@ class Company < AbstractCompany
end
private
-
def private_method
"I am Jack's innermost fears and aspirations"
end
diff --git a/activerecord/test/models/company_in_module.rb b/activerecord/test/models/company_in_module.rb
index 52b7e06a63..320b26b950 100644
--- a/activerecord/test/models/company_in_module.rb
+++ b/activerecord/test/models/company_in_module.rb
@@ -91,7 +91,6 @@ module MyApplication
validate :check_empty_credit_limit
private
-
def check_empty_credit_limit
errors.add("credit_card", :blank) if credit_card.blank?
end
diff --git a/activerecord/test/models/contact.rb b/activerecord/test/models/contact.rb
index 6e02ff199b..d5f6f00691 100644
--- a/activerecord/test/models/contact.rb
+++ b/activerecord/test/models/contact.rb
@@ -10,14 +10,14 @@ module ContactFakeColumns
table_name => "id"
}
- column :id, :integer
- column :name, :string
- column :age, :integer
- column :avatar, :binary
- column :created_at, :datetime
- column :awesome, :boolean
- column :preferences, :string
- column :alternative_id, :integer
+ column :id, "integer"
+ column :name, "string"
+ column :age, "integer"
+ column :avatar, "binary"
+ column :created_at, "datetime"
+ column :awesome, "boolean"
+ column :preferences, "string"
+ column :alternative_id, "integer"
serialize :preferences
@@ -37,7 +37,7 @@ end
class ContactSti < ActiveRecord::Base
extend ContactFakeColumns
- column :type, :string
+ column :type, "string"
def type; "ContactSti" end
end
diff --git a/activerecord/test/models/face.rb b/activerecord/test/models/face.rb
index e900fd40fb..45ccc442ba 100644
--- a/activerecord/test/models/face.rb
+++ b/activerecord/test/models/face.rb
@@ -6,7 +6,7 @@ class Face < ActiveRecord::Base
belongs_to :polymorphic_man, polymorphic: true, inverse_of: :polymorphic_face
# Oracle identifier length is limited to 30 bytes or less, `polymorphic` renamed `poly`
belongs_to :poly_man_without_inverse, polymorphic: true
- # These is a "broken" inverse_of for the purposes of testing
+ # These are "broken" inverse_of associations for the purposes of testing
belongs_to :horrible_man, class_name: "Man", inverse_of: :horrible_face
belongs_to :horrible_polymorphic_man, polymorphic: true, inverse_of: :horrible_polymorphic_face
diff --git a/activerecord/test/models/mouse.rb b/activerecord/test/models/mouse.rb
new file mode 100644
index 0000000000..75a55c125d
--- /dev/null
+++ b/activerecord/test/models/mouse.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+class Mouse < ActiveRecord::Base
+ has_many :squeaks, autosave: true
+ validates :name, presence: true
+end
diff --git a/activerecord/test/models/person.rb b/activerecord/test/models/person.rb
index c3d15a571a..0dfd29e45e 100644
--- a/activerecord/test/models/person.rb
+++ b/activerecord/test/models/person.rb
@@ -101,7 +101,6 @@ class RichPerson < ActiveRecord::Base
before_validation :run_before_validation
private
-
def run_before_create
self.first_name = first_name.to_s + "run_before_create"
end
diff --git a/activerecord/test/models/rating.rb b/activerecord/test/models/rating.rb
index 49aa38285f..2a18ea45ac 100644
--- a/activerecord/test/models/rating.rb
+++ b/activerecord/test/models/rating.rb
@@ -4,4 +4,5 @@ class Rating < ActiveRecord::Base
belongs_to :comment
has_many :taggings, as: :taggable
has_many :taggings_without_tag, -> { left_joins(:tag).where("tags.id": nil) }, as: :taggable, class_name: "Tagging"
+ has_many :taggings_with_no_tag, -> { joins("LEFT OUTER JOIN tags ON tags.id = taggings.tag_id").where("tags.id": nil) }, as: :taggable, class_name: "Tagging"
end
diff --git a/activerecord/test/models/ship.rb b/activerecord/test/models/ship.rb
index 7973219a79..6bab7a1eb9 100644
--- a/activerecord/test/models/ship.rb
+++ b/activerecord/test/models/ship.rb
@@ -27,7 +27,8 @@ class ShipWithoutNestedAttributes < ActiveRecord::Base
has_many :prisoners, inverse_of: :ship, foreign_key: :ship_id
has_many :parts, class_name: "ShipPart", foreign_key: :ship_id
- validates :name, presence: true
+ validates :name, presence: true, if: -> { true }
+ validates :name, presence: true, if: -> { true }
end
class Prisoner < ActiveRecord::Base
diff --git a/activerecord/test/models/squeak.rb b/activerecord/test/models/squeak.rb
new file mode 100644
index 0000000000..e0a643c238
--- /dev/null
+++ b/activerecord/test/models/squeak.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+class Squeak < ActiveRecord::Base
+ belongs_to :mouse
+ accepts_nested_attributes_for :mouse
+end
diff --git a/activerecord/test/models/topic.rb b/activerecord/test/models/topic.rb
index 77101090f2..7a864c728c 100644
--- a/activerecord/test/models/topic.rb
+++ b/activerecord/test/models/topic.rb
@@ -93,7 +93,6 @@ class Topic < ActiveRecord::Base
end
private
-
def default_written_on
self.written_on = Time.now unless attribute_present?("written_on")
end
diff --git a/activerecord/test/schema/mysql2_specific_schema.rb b/activerecord/test/schema/mysql2_specific_schema.rb
index b143035213..911ac808c6 100644
--- a/activerecord/test/schema/mysql2_specific_schema.rb
+++ b/activerecord/test/schema/mysql2_specific_schema.rb
@@ -62,10 +62,6 @@ ActiveRecord::Schema.define do
t.binary :binary_column, limit: 1
end
- create_table :enum_tests, id: false, force: true do |t|
- t.column :enum_column, "ENUM('text','blob','tiny','medium','long','unsigned','bigint')"
- end
-
execute "DROP PROCEDURE IF EXISTS ten"
execute <<~SQL
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 41920b3719..dd0ff759b6 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -115,7 +115,7 @@ ActiveRecord::Schema.define do
t.column :font_size, :integer, **default_zero
t.column :difficulty, :integer, **default_zero
t.column :cover, :string, default: "hard"
- t.string :isbn
+ t.string :isbn, **case_sensitive_options
t.datetime :published_on
t.index [:author_id, :name], unique: true
t.index :isbn, where: "published_on IS NOT NULL", unique: true
@@ -261,6 +261,7 @@ ActiveRecord::Schema.define do
t.references :developer, index: false
t.references :company, index: false
t.string :metadata
+ t.integer :count
end
create_table :customers, force: true do |t|
@@ -562,6 +563,10 @@ ActiveRecord::Schema.define do
t.string :type
end
+ create_table :mice, force: true do |t|
+ t.string :name
+ end
+
create_table :movies, force: true, id: false do |t|
t.primary_key :movieid
t.string :name
@@ -842,6 +847,10 @@ ActiveRecord::Schema.define do
end
end
+ create_table :squeaks, force: true do |t|
+ t.integer :mouse_id
+ end
+
create_table :prisoners, force: true do |t|
t.belongs_to :ship
end
diff --git a/activerecord/test/support/config.rb b/activerecord/test/support/config.rb
index de0d90a18f..66ae57b382 100644
--- a/activerecord/test/support/config.rb
+++ b/activerecord/test/support/config.rb
@@ -12,7 +12,6 @@ module ARTest
end
private
-
def config_file
Pathname.new(ENV["ARCONFIG"] || TEST_ROOT + "/config.yml")
end
diff --git a/activestorage/CHANGELOG.md b/activestorage/CHANGELOG.md
index 957591ec0a..1475a7a786 100644
--- a/activestorage/CHANGELOG.md
+++ b/activestorage/CHANGELOG.md
@@ -1,3 +1,64 @@
+* Add `config.active_storage.draw_routes` to disable Active Storage routes.
+
+ *Gannon McGibbon*
+
+* Image analysis is skipped if ImageMagick returns an error.
+
+ `ActiveStorage::Analyzer::ImageAnalyzer#metadata` would previously raise a
+ `MiniMagick::Error`, which caused persistent `ActiveStorage::AnalyzeJob`
+ failures. It now logs the error and returns `{}`, resulting in no metadata
+ being added to the offending image blob.
+
+ *George Claghorn*
+
+* Method calls on singular attachments return `nil` when no file is attached.
+
+ Previously, assuming the following User model, `user.avatar.filename` would
+ raise a `Module::DelegationError` if no avatar was attached:
+
+ ```ruby
+ class User < ApplicationRecord
+ has_one_attached :avatar
+ end
+ ```
+
+ They now return `nil`.
+
+ *Matthew Tanous*
+
+* The mirror service supports direct uploads.
+
+ New files are directly uploaded to the primary service. When a
+ directly-uploaded file is attached to a record, a background job is enqueued
+ to copy it to each secondary service.
+
+ Configure the queue used to process mirroring jobs by setting
+ `config.active_storage.queues.mirror`. The default is `:active_storage_mirror`.
+
+ *George Claghorn*
+
+* The S3 service now permits uploading files larger than 5 gigabytes.
+
+ When uploading a file greater than 100 megabytes in size, the service
+ transparently switches to [multipart uploads](https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuoverview.html)
+ using a part size computed from the file's total size and S3's part count limit.
+
+ No application changes are necessary to take advantage of this feature. You
+ can customize the default 100 MB multipart upload threshold in your S3
+ service's configuration:
+
+ ```yaml
+ production:
+ service: s3
+ access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
+ secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
+ region: us-east-1
+ bucket: my-bucket
+ upload:
+ multipart_threshold: <%= 250.megabytes %>
+ ```
+
+ *George Claghorn*
Please check [6-0-stable](https://github.com/rails/rails/blob/6-0-stable/activestorage/CHANGELOG.md) for previous changes.
diff --git a/activestorage/app/jobs/active_storage/mirror_job.rb b/activestorage/app/jobs/active_storage/mirror_job.rb
new file mode 100644
index 0000000000..e34faedb56
--- /dev/null
+++ b/activestorage/app/jobs/active_storage/mirror_job.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+# Provides asynchronous mirroring of directly-uploaded blobs.
+class ActiveStorage::MirrorJob < ActiveStorage::BaseJob
+ queue_as { ActiveStorage.queues[:mirror] }
+
+ discard_on ActiveStorage::FileNotFoundError
+ retry_on ActiveStorage::IntegrityError, attempts: 10, wait: :exponentially_longer
+
+ def perform(key, checksum:)
+ ActiveStorage::Blob.service.try(:mirror, key, checksum: checksum)
+ end
+end
diff --git a/activestorage/app/models/active_storage/attachment.rb b/activestorage/app/models/active_storage/attachment.rb
index 874ba80ca8..1ee43b1cd5 100644
--- a/activestorage/app/models/active_storage/attachment.rb
+++ b/activestorage/app/models/active_storage/attachment.rb
@@ -13,7 +13,7 @@ class ActiveStorage::Attachment < ActiveRecord::Base
delegate_missing_to :blob
- after_create_commit :analyze_blob_later, :identify_blob
+ after_create_commit :mirror_blob_later, :analyze_blob_later, :identify_blob
after_destroy_commit :purge_dependent_blob_later
# Synchronously deletes the attachment and {purges the blob}[rdoc-ref:ActiveStorage::Blob#purge].
@@ -37,6 +37,10 @@ class ActiveStorage::Attachment < ActiveRecord::Base
blob.analyze_later unless blob.analyzed?
end
+ def mirror_blob_later
+ blob.mirror_later
+ end
+
def purge_dependent_blob_later
blob&.purge_later if dependent == :purge_later
end
diff --git a/activestorage/app/models/active_storage/blob.rb b/activestorage/app/models/active_storage/blob.rb
index c9fbafad1f..6a486dd899 100644
--- a/activestorage/app/models/active_storage/blob.rb
+++ b/activestorage/app/models/active_storage/blob.rb
@@ -207,6 +207,9 @@ class ActiveStorage::Blob < ActiveRecord::Base
name: [ "ActiveStorage-#{id}-", filename.extension_with_delimiter ], tmpdir: tmpdir, &block
end
+ def mirror_later #:nodoc:
+ ActiveStorage::MirrorJob.perform_later(key, checksum: checksum) if service.respond_to?(:mirror)
+ end
# Deletes the files on the service associated with the blob. This should only be done if the blob is going to be
# deleted as well or you will essentially have a dead reference. It's recommended to use #purge and #purge_later
diff --git a/activestorage/app/models/active_storage/variant.rb b/activestorage/app/models/active_storage/variant.rb
index bc0058967a..1859b8482e 100644
--- a/activestorage/app/models/active_storage/variant.rb
+++ b/activestorage/app/models/active_storage/variant.rb
@@ -96,19 +96,13 @@ class ActiveStorage::Variant
end
def process
- blob.open do |image|
- transform(image) { |output| upload(output) }
+ blob.open do |input|
+ variation.transform(input, format: format) do |output|
+ service.upload(key, output)
+ end
end
end
- def transform(image, &block)
- variation.transform(image, format: format, &block)
- end
-
- def upload(file)
- service.upload(key, file)
- end
-
def specification
@specification ||=
diff --git a/activestorage/config/routes.rb b/activestorage/config/routes.rb
index 3af7361cff..bde53e72f3 100644
--- a/activestorage/config/routes.rb
+++ b/activestorage/config/routes.rb
@@ -29,4 +29,4 @@ Rails.application.routes.draw do
resolve("ActiveStorage::Blob") { |blob, options| route_for(:rails_blob, blob, options) }
resolve("ActiveStorage::Attachment") { |attachment, options| route_for(:rails_blob, attachment.blob, options) }
-end
+end if ActiveStorage.draw_routes
diff --git a/activestorage/lib/active_storage.rb b/activestorage/lib/active_storage.rb
index 5c5da551ae..c35a9920d6 100644
--- a/activestorage/lib/active_storage.rb
+++ b/activestorage/lib/active_storage.rb
@@ -43,17 +43,26 @@ module ActiveStorage
mattr_accessor :logger
mattr_accessor :verifier
+ mattr_accessor :variant_processor, default: :mini_magick
+
mattr_accessor :queues, default: {}
+
mattr_accessor :previewers, default: []
- mattr_accessor :analyzers, default: []
- mattr_accessor :variant_processor, default: :mini_magick
+ mattr_accessor :analyzers, default: []
+
mattr_accessor :paths, default: {}
- mattr_accessor :variable_content_types, default: []
+
+ mattr_accessor :variable_content_types, default: []
+ mattr_accessor :binary_content_type, default: "application/octet-stream"
mattr_accessor :content_types_to_serve_as_binary, default: []
- mattr_accessor :content_types_allowed_inline, default: []
- mattr_accessor :binary_content_type, default: "application/octet-stream"
+ mattr_accessor :content_types_allowed_inline, default: []
+
mattr_accessor :service_urls_expire_in, default: 5.minutes
+
mattr_accessor :routes_prefix, default: "/rails/active_storage"
+ mattr_accessor :draw_routes, default: true
+
+ mattr_accessor :replace_on_assign_to_many, default: false
module Transformers
extend ActiveSupport::Autoload
diff --git a/activestorage/lib/active_storage/analyzer/image_analyzer.rb b/activestorage/lib/active_storage/analyzer/image_analyzer.rb
index c8bc8fe953..bd1bef3076 100644
--- a/activestorage/lib/active_storage/analyzer/image_analyzer.rb
+++ b/activestorage/lib/active_storage/analyzer/image_analyzer.rb
@@ -43,6 +43,9 @@ module ActiveStorage
rescue LoadError
logger.info "Skipping image analysis because the mini_magick gem isn't installed"
{}
+ rescue MiniMagick::Error => error
+ logger.error "Skipping image analysis due to an ImageMagick error: #{error.message}"
+ {}
end
def rotated_image?(image)
diff --git a/activestorage/lib/active_storage/attached/model.rb b/activestorage/lib/active_storage/attached/model.rb
index ae7f0685f2..06864a846f 100644
--- a/activestorage/lib/active_storage/attached/model.rb
+++ b/activestorage/lib/active_storage/attached/model.rb
@@ -93,12 +93,19 @@ module ActiveStorage
end
def #{name}=(attachables)
- attachment_changes["#{name}"] =
- if attachables.nil? || Array(attachables).none?
- ActiveStorage::Attached::Changes::DeleteMany.new("#{name}", self)
- else
- ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, attachables)
+ if ActiveStorage.replace_on_assign_to_many
+ attachment_changes["#{name}"] =
+ if attachables.nil? || Array(attachables).none?
+ ActiveStorage::Attached::Changes::DeleteMany.new("#{name}", self)
+ else
+ ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, attachables)
+ end
+ else
+ if !attachables.nil? || Array(attachables).any?
+ attachment_changes["#{name}"] =
+ ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, #{name}.blobs + attachables)
end
+ end
end
CODE
diff --git a/activestorage/lib/active_storage/attached/one.rb b/activestorage/lib/active_storage/attached/one.rb
index c039226fcd..003be1cb43 100644
--- a/activestorage/lib/active_storage/attached/one.rb
+++ b/activestorage/lib/active_storage/attached/one.rb
@@ -3,7 +3,7 @@
module ActiveStorage
# Representation of a single attachment to a model.
class Attached::One < Attached
- delegate_missing_to :attachment
+ delegate_missing_to :attachment, allow_nil: true
# Returns the associated attachment record.
#
diff --git a/activestorage/lib/active_storage/engine.rb b/activestorage/lib/active_storage/engine.rb
index cbb205627e..9d9cd02d12 100644
--- a/activestorage/lib/active_storage/engine.rb
+++ b/activestorage/lib/active_storage/engine.rb
@@ -24,7 +24,7 @@ module ActiveStorage
config.active_storage.previewers = [ ActiveStorage::Previewer::PopplerPDFPreviewer, ActiveStorage::Previewer::MuPDFPreviewer, ActiveStorage::Previewer::VideoPreviewer ]
config.active_storage.analyzers = [ ActiveStorage::Analyzer::ImageAnalyzer, ActiveStorage::Analyzer::VideoAnalyzer ]
config.active_storage.paths = ActiveSupport::OrderedOptions.new
- config.active_storage.queues = ActiveSupport::OrderedOptions.new
+ config.active_storage.queues = ActiveSupport::InheritableOptions.new(mirror: :active_storage_mirror)
config.active_storage.variable_content_types = %w(
image/png
@@ -73,12 +73,15 @@ module ActiveStorage
ActiveStorage.analyzers = app.config.active_storage.analyzers || []
ActiveStorage.paths = app.config.active_storage.paths || {}
ActiveStorage.routes_prefix = app.config.active_storage.routes_prefix || "/rails/active_storage"
+ ActiveStorage.draw_routes = app.config.active_storage.draw_routes != false
ActiveStorage.variable_content_types = app.config.active_storage.variable_content_types || []
ActiveStorage.content_types_to_serve_as_binary = app.config.active_storage.content_types_to_serve_as_binary || []
ActiveStorage.service_urls_expire_in = app.config.active_storage.service_urls_expire_in || 5.minutes
ActiveStorage.content_types_allowed_inline = app.config.active_storage.content_types_allowed_inline || []
ActiveStorage.binary_content_type = app.config.active_storage.binary_content_type || "application/octet-stream"
+
+ ActiveStorage.replace_on_assign_to_many = app.config.active_storage.replace_on_assign_to_many || false
end
end
@@ -130,7 +133,7 @@ module ActiveStorage
"config.active_storage.queue is deprecated and will be removed in Rails 6.1. " \
"Set config.active_storage.queues.purge and config.active_storage.queues.analysis instead."
- ActiveStorage.queues = { purge: queue, analysis: queue }
+ ActiveStorage.queues = { purge: queue, analysis: queue, mirror: queue }
else
ActiveStorage.queues = app.config.active_storage.queues || {}
end
diff --git a/activestorage/lib/active_storage/log_subscriber.rb b/activestorage/lib/active_storage/log_subscriber.rb
index 6c0b4c30e7..f823f31093 100644
--- a/activestorage/lib/active_storage/log_subscriber.rb
+++ b/activestorage/lib/active_storage/log_subscriber.rb
@@ -32,6 +32,12 @@ module ActiveStorage
debug event, color("Generated URL for file at key: #{key_in(event)} (#{event.payload[:url]})", BLUE)
end
+ def service_mirror(event)
+ message = "Mirrored file at key: #{key_in(event)}"
+ message += " (checksum: #{event.payload[:checksum]})" if event.payload[:checksum]
+ debug event, color(message, GREEN)
+ end
+
def logger
ActiveStorage.logger
end
diff --git a/activestorage/lib/active_storage/service/azure_storage_service.rb b/activestorage/lib/active_storage/service/azure_storage_service.rb
index 993cc0e5f7..8d77e9b20f 100644
--- a/activestorage/lib/active_storage/service/azure_storage_service.rb
+++ b/activestorage/lib/active_storage/service/azure_storage_service.rb
@@ -17,10 +17,10 @@ module ActiveStorage
@container = container
end
- def upload(key, io, checksum: nil, **)
+ def upload(key, io, checksum: nil, content_type: nil, **)
instrument :upload, key: key, checksum: checksum do
handle_errors do
- blobs.create_block_blob(container, key, IO.try_convert(io) || io, content_md5: checksum)
+ blobs.create_block_blob(container, key, IO.try_convert(io) || io, content_md5: checksum, content_type: content_type)
end
end
end
diff --git a/activestorage/lib/active_storage/service/disk_service.rb b/activestorage/lib/active_storage/service/disk_service.rb
index 67892d43b2..764a447c69 100644
--- a/activestorage/lib/active_storage/service/disk_service.rb
+++ b/activestorage/lib/active_storage/service/disk_service.rb
@@ -84,8 +84,12 @@ module ActiveStorage
purpose: :blob_key }
)
+ current_uri = URI.parse(current_host)
+
generated_url = url_helpers.rails_disk_service_url(verified_key_with_expiration,
- host: current_host,
+ protocol: current_uri.scheme,
+ host: current_uri.host,
+ port: current_uri.port,
disposition: content_disposition,
content_type: content_type,
filename: filename
diff --git a/activestorage/lib/active_storage/service/mirror_service.rb b/activestorage/lib/active_storage/service/mirror_service.rb
index aa41df304e..c44bd1f360 100644
--- a/activestorage/lib/active_storage/service/mirror_service.rb
+++ b/activestorage/lib/active_storage/service/mirror_service.rb
@@ -4,12 +4,17 @@ require "active_support/core_ext/module/delegation"
module ActiveStorage
# Wraps a set of mirror services and provides a single ActiveStorage::Service object that will all
- # have the files uploaded to them. A +primary+ service is designated to answer calls to +download+, +exists?+,
- # and +url+.
+ # have the files uploaded to them. A +primary+ service is designated to answer calls to:
+ # * +download+
+ # * +exists?+
+ # * +url+
+ # * +url_for_direct_upload+
+ # * +headers_for_direct_upload+
class Service::MirrorService < Service
attr_reader :primary, :mirrors
- delegate :download, :download_chunk, :exist?, :url, :path_for, to: :primary
+ delegate :download, :download_chunk, :exist?, :url,
+ :url_for_direct_upload, :headers_for_direct_upload, :path_for, to: :primary
# Stitch together from named services.
def self.build(primary:, mirrors:, configurator:, **options) #:nodoc:
@@ -26,7 +31,8 @@ module ActiveStorage
# ensure a match when the upload has completed or raise an ActiveStorage::IntegrityError.
def upload(key, io, checksum: nil, **options)
each_service.collect do |service|
- service.upload key, io.tap(&:rewind), checksum: checksum, **options
+ io.rewind
+ service.upload key, io, checksum: checksum, **options
end
end
@@ -40,6 +46,21 @@ module ActiveStorage
perform_across_services :delete_prefixed, prefix
end
+
+ # Copy the file at the +key+ from the primary service to each of the mirrors where it doesn't already exist.
+ def mirror(key, checksum:)
+ instrument :mirror, key: key, checksum: checksum do
+ if (mirrors_in_need_of_mirroring = mirrors.select { |service| !service.exist?(key) }).any?
+ primary.open(key, checksum: checksum) do |io|
+ mirrors_in_need_of_mirroring.each do |service|
+ io.rewind
+ service.upload key, io, checksum: checksum
+ end
+ end
+ end
+ end
+ end
+
private
def each_service(&block)
[ primary, *mirrors ].each(&block)
diff --git a/activestorage/lib/active_storage/service/s3_service.rb b/activestorage/lib/active_storage/service/s3_service.rb
index c7e4ec96a2..e4bd57048a 100644
--- a/activestorage/lib/active_storage/service/s3_service.rb
+++ b/activestorage/lib/active_storage/service/s3_service.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+gem "aws-sdk-s3", "~> 1.14"
+
require "aws-sdk-s3"
require "active_support/core_ext/numeric/bytes"
@@ -7,20 +9,24 @@ module ActiveStorage
# Wraps the Amazon Simple Storage Service (S3) as an Active Storage service.
# See ActiveStorage::Service for the generic API documentation that applies to all services.
class Service::S3Service < Service
- attr_reader :client, :bucket, :upload_options
+ attr_reader :client, :bucket
+ attr_reader :multipart_upload_threshold, :upload_options
def initialize(bucket:, upload: {}, **options)
@client = Aws::S3::Resource.new(**options)
@bucket = @client.bucket(bucket)
+ @multipart_upload_threshold = upload.fetch(:multipart_threshold, 100.megabytes)
@upload_options = upload
end
def upload(key, io, checksum: nil, content_type: nil, **)
instrument :upload, key: key, checksum: checksum do
- object_for(key).put(upload_options.merge(body: io, content_md5: checksum, content_type: content_type))
- rescue Aws::S3::Errors::BadDigest
- raise ActiveStorage::IntegrityError
+ if io.size < multipart_upload_threshold
+ upload_with_single_part key, io, checksum: checksum, content_type: content_type
+ else
+ upload_with_multipart key, io, content_type: content_type
+ end
end
end
@@ -94,6 +100,24 @@ module ActiveStorage
end
private
+ MAXIMUM_UPLOAD_PARTS_COUNT = 10000
+ MINIMUM_UPLOAD_PART_SIZE = 5.megabytes
+
+ def upload_with_single_part(key, io, checksum: nil, content_type: nil)
+ object_for(key).put(body: io, content_md5: checksum, content_type: content_type, **upload_options)
+ rescue Aws::S3::Errors::BadDigest
+ raise ActiveStorage::IntegrityError
+ end
+
+ def upload_with_multipart(key, io, content_type: nil)
+ part_size = [ io.size.fdiv(MAXIMUM_UPLOAD_PARTS_COUNT).ceil, MINIMUM_UPLOAD_PART_SIZE ].max
+
+ object_for(key).upload_stream(content_type: content_type, part_size: part_size, **upload_options) do |out|
+ IO.copy_stream(io, out)
+ end
+ end
+
+
def object_for(key)
bucket.object(key)
end
diff --git a/activestorage/test/analyzer/video_analyzer_test.rb b/activestorage/test/analyzer/video_analyzer_test.rb
index d30f49315a..172a2f0aae 100644
--- a/activestorage/test/analyzer/video_analyzer_test.rb
+++ b/activestorage/test/analyzer/video_analyzer_test.rb
@@ -24,7 +24,6 @@ class ActiveStorage::Analyzer::VideoAnalyzerTest < ActiveSupport::TestCase
assert_equal 480, metadata[:width]
assert_equal 640, metadata[:height]
assert_equal [4, 3], metadata[:display_aspect_ratio]
- assert_equal 5.227975, metadata[:duration]
assert_equal 90, metadata[:angle]
end
diff --git a/activestorage/test/controllers/blobs_controller_test.rb b/activestorage/test/controllers/blobs_controller_test.rb
index 9bf2641de6..9c811df895 100644
--- a/activestorage/test/controllers/blobs_controller_test.rb
+++ b/activestorage/test/controllers/blobs_controller_test.rb
@@ -20,28 +20,3 @@ class ActiveStorage::BlobsControllerTest < ActionDispatch::IntegrationTest
assert_equal "max-age=300, private", @response.headers["Cache-Control"]
end
end
-
-if SERVICE_CONFIGURATIONS[:s3] && SERVICE_CONFIGURATIONS[:s3][:access_key_id].present?
- class ActiveStorage::S3BlobsControllerTest < ActionDispatch::IntegrationTest
- setup do
- @old_service = ActiveStorage::Blob.service
- ActiveStorage::Blob.service = ActiveStorage::Service.configure(:s3, SERVICE_CONFIGURATIONS)
- end
-
- teardown do
- ActiveStorage::Blob.service = @old_service
- end
-
- test "allow redirection to the different host" do
- blob = create_file_blob filename: "racecar.jpg"
-
- assert_nothing_raised { get rails_blob_url(blob) }
- assert_response :redirect
- assert_no_match @request.host, @response.headers["Location"]
- ensure
- blob.purge
- end
- end
-else
- puts "Skipping S3 redirection tests because no S3 configuration was supplied"
-end
diff --git a/activestorage/test/controllers/representations_controller_test.rb b/activestorage/test/controllers/representations_controller_test.rb
index 4ae0ff877e..2662cc5283 100644
--- a/activestorage/test/controllers/representations_controller_test.rb
+++ b/activestorage/test/controllers/representations_controller_test.rb
@@ -59,33 +59,3 @@ class ActiveStorage::RepresentationsControllerWithPreviewsTest < ActionDispatch:
assert_response :not_found
end
end
-
-if SERVICE_CONFIGURATIONS[:s3] && SERVICE_CONFIGURATIONS[:s3][:access_key_id].present?
- class ActiveStorage::S3RepresentationsControllerWithVariantsTest < ActionDispatch::IntegrationTest
- setup do
- @old_service = ActiveStorage::Blob.service
- ActiveStorage::Blob.service = ActiveStorage::Service.configure(:s3, SERVICE_CONFIGURATIONS)
- end
-
- teardown do
- ActiveStorage::Blob.service = @old_service
- end
-
- test "allow redirection to the different host" do
- blob = create_file_blob filename: "racecar.jpg"
-
- assert_nothing_raised do
- get rails_blob_representation_url(
- filename: blob.filename,
- signed_blob_id: blob.signed_id,
- variation_key: ActiveStorage::Variation.encode(resize: "100x100"))
- end
- assert_response :redirect
- assert_no_match @request.host, @response.headers["Location"]
- ensure
- blob.purge
- end
- end
-else
- puts "Skipping S3 redirection tests because no S3 configuration was supplied"
-end
diff --git a/activestorage/test/models/attached/many_test.rb b/activestorage/test/models/attached/many_test.rb
index e826109874..39ddecb041 100644
--- a/activestorage/test/models/attached/many_test.rb
+++ b/activestorage/test/models/attached/many_test.rb
@@ -269,44 +269,22 @@ class ActiveStorage::ManyAttachedTest < ActiveSupport::TestCase
end
end
- test "analyzing a new blob from an uploaded file after attaching it to an existing record" do
- perform_enqueued_jobs do
- @user.highlights.attach fixture_file_upload("racecar.jpg")
- end
-
- assert @user.highlights.reload.first.analyzed?
- assert_equal 4104, @user.highlights.first.metadata[:width]
- assert_equal 2736, @user.highlights.first.metadata[:height]
- end
-
- test "analyzing a new blob from an uploaded file after attaching it to an existing record via update" do
- perform_enqueued_jobs do
- @user.update! highlights: [ fixture_file_upload("racecar.jpg") ]
- end
-
- assert @user.highlights.reload.first.analyzed?
- assert_equal 4104, @user.highlights.first.metadata[:width]
- assert_equal 2736, @user.highlights.first.metadata[:height]
- end
+ test "updating an existing record with attachments when appending on assign" do
+ append_on_assign do
+ @user.highlights.attach create_blob(filename: "funky.jpg"), create_blob(filename: "town.jpg")
- test "analyzing a directly-uploaded blob after attaching it to an existing record" do
- perform_enqueued_jobs do
- @user.highlights.attach directly_upload_file_blob(filename: "racecar.jpg")
- end
+ assert_difference -> { @user.reload.highlights.count }, +2 do
+ @user.update! highlights: [ create_blob(filename: "whenever.jpg"), create_blob(filename: "wherever.jpg") ]
+ end
- assert @user.highlights.reload.first.analyzed?
- assert_equal 4104, @user.highlights.first.metadata[:width]
- assert_equal 2736, @user.highlights.first.metadata[:height]
- end
+ assert_no_difference -> { @user.reload.highlights.count } do
+ @user.update! highlights: [ ]
+ end
- test "analyzing a directly-uploaded blob after attaching it to an existing record via update" do
- perform_enqueued_jobs do
- @user.update! highlights: [ directly_upload_file_blob(filename: "racecar.jpg") ]
+ assert_no_difference -> { @user.reload.highlights.count } do
+ @user.update! highlights: nil
+ end
end
-
- assert @user.highlights.reload.first.analyzed?
- assert_equal 4104, @user.highlights.first.metadata[:width]
- assert_equal 2736, @user.highlights.first.metadata[:height]
end
test "attaching existing blobs to a new record" do
@@ -422,24 +400,6 @@ class ActiveStorage::ManyAttachedTest < ActiveSupport::TestCase
assert_equal "Could not find or build blob: expected attachable, got :foo", error.message
end
- test "analyzing a new blob from an uploaded file after attaching it to a new record" do
- perform_enqueued_jobs do
- user = User.create!(name: "Jason", highlights: [ fixture_file_upload("racecar.jpg") ])
- assert user.highlights.reload.first.analyzed?
- assert_equal 4104, user.highlights.first.metadata[:width]
- assert_equal 2736, user.highlights.first.metadata[:height]
- end
- end
-
- test "analyzing a directly-uploaded blob after attaching it to a new record" do
- perform_enqueued_jobs do
- user = User.create!(name: "Jason", highlights: [ directly_upload_file_blob(filename: "racecar.jpg") ])
- assert user.highlights.reload.first.analyzed?
- assert_equal 4104, user.highlights.first.metadata[:width]
- assert_equal 2736, user.highlights.first.metadata[:height]
- end
- end
-
test "detaching" do
[ create_blob(filename: "funky.jpg"), create_blob(filename: "town.jpg") ].tap do |blobs|
@user.highlights.attach blobs
@@ -596,4 +556,12 @@ class ActiveStorage::ManyAttachedTest < ActiveSupport::TestCase
User.remove_method :highlights
end
end
+
+ private
+ def append_on_assign
+ ActiveStorage.replace_on_assign_to_many, previous = false, ActiveStorage.replace_on_assign_to_many
+ yield
+ ensure
+ ActiveStorage.replace_on_assign_to_many = previous
+ end
end
diff --git a/activestorage/test/models/attachment_test.rb b/activestorage/test/models/attachment_test.rb
new file mode 100644
index 0000000000..94f354d116
--- /dev/null
+++ b/activestorage/test/models/attachment_test.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+require "test_helper"
+require "database/setup"
+
+class ActiveStorage::AttachmentTest < ActiveSupport::TestCase
+ include ActiveJob::TestHelper
+
+ setup do
+ @user = User.create!(name: "Josh")
+ end
+
+ teardown { ActiveStorage::Blob.all.each(&:delete) }
+
+ test "analyzing a directly-uploaded blob after attaching it" do
+ blob = directly_upload_file_blob(filename: "racecar.jpg")
+ assert_not blob.analyzed?
+
+ perform_enqueued_jobs do
+ @user.highlights.attach(blob)
+ end
+
+ assert blob.reload.analyzed?
+ assert_equal 4104, blob.metadata[:width]
+ assert_equal 2736, blob.metadata[:height]
+ end
+
+ test "mirroring a directly-uploaded blob after attaching it" do
+ previous_service, ActiveStorage::Blob.service = ActiveStorage::Blob.service, build_mirror_service
+
+ blob = directly_upload_file_blob
+ assert_not ActiveStorage::Blob.service.mirrors.second.exist?(blob.key)
+
+ perform_enqueued_jobs do
+ @user.highlights.attach(blob)
+ end
+
+ assert ActiveStorage::Blob.service.mirrors.second.exist?(blob.key)
+ ensure
+ ActiveStorage::Blob.service = previous_service
+ end
+
+ private
+ def build_mirror_service
+ ActiveStorage::Service::MirrorService.new \
+ primary: build_disk_service("primary"),
+ mirrors: 3.times.collect { |i| build_disk_service("mirror_#{i + 1}") }
+ end
+
+ def build_disk_service(purpose)
+ ActiveStorage::Service::DiskService.new(root: Dir.mktmpdir("active_storage_tests_#{purpose}"))
+ end
+end
diff --git a/activestorage/test/service/azure_storage_service_test.rb b/activestorage/test/service/azure_storage_service_test.rb
index 2b07902d07..fc7b86ccb0 100644
--- a/activestorage/test/service/azure_storage_service_test.rb
+++ b/activestorage/test/service/azure_storage_service_test.rb
@@ -9,6 +9,20 @@ if SERVICE_CONFIGURATIONS[:azure]
include ActiveStorage::Service::SharedServiceTests
+ test "upload with content_type" do
+ key = SecureRandom.base58(24)
+ data = "Foobar"
+
+ @service.upload(key, StringIO.new(data), checksum: Digest::MD5.base64digest(data), filename: ActiveStorage::Filename.new("test.txt"), content_type: "text/plain")
+
+ url = @service.url(key, expires_in: 2.minutes, disposition: :attachment, content_type: nil, filename: ActiveStorage::Filename.new("test.html"))
+ response = Net::HTTP.get_response(URI(url))
+ assert_equal "text/plain", response.content_type
+ assert_match(/attachment;.*test\.html/, response["Content-Disposition"])
+ ensure
+ @service.delete key
+ end
+
test "signed URL generation" do
url = @service.url(@key, expires_in: 5.minutes,
disposition: :inline, filename: ActiveStorage::Filename.new("avatar.png"), content_type: "image/png")
diff --git a/activestorage/test/service/disk_service_test.rb b/activestorage/test/service/disk_service_test.rb
index f3c4dd26bd..b766cc3f56 100644
--- a/activestorage/test/service/disk_service_test.rb
+++ b/activestorage/test/service/disk_service_test.rb
@@ -8,8 +8,14 @@ class ActiveStorage::Service::DiskServiceTest < ActiveSupport::TestCase
include ActiveStorage::Service::SharedServiceTests
test "URL generation" do
- assert_match(/^https:\/\/example.com\/rails\/active_storage\/disk\/.*\/avatar\.png\?content_type=image%2Fpng&disposition=inline/,
- @service.url(@key, expires_in: 5.minutes, disposition: :inline, filename: ActiveStorage::Filename.new("avatar.png"), content_type: "image/png"))
+ original_url_options = Rails.application.routes.default_url_options.dup
+ Rails.application.routes.default_url_options.merge!(protocol: "http", host: "test.example.com", port: 3001)
+ begin
+ assert_match(/^https:\/\/example.com\/rails\/active_storage\/disk\/.*\/avatar\.png\?content_type=image%2Fpng&disposition=inline/,
+ @service.url(@key, expires_in: 5.minutes, disposition: :inline, filename: ActiveStorage::Filename.new("avatar.png"), content_type: "image/png"))
+ ensure
+ Rails.application.routes.default_url_options = original_url_options
+ end
end
test "headers_for_direct_upload generation" do
diff --git a/activestorage/test/service/mirror_service_test.rb b/activestorage/test/service/mirror_service_test.rb
index 249a5652fb..aa4d610753 100644
--- a/activestorage/test/service/mirror_service_test.rb
+++ b/activestorage/test/service/mirror_service_test.rb
@@ -53,6 +53,20 @@ class ActiveStorage::Service::MirrorServiceTest < ActiveSupport::TestCase
end
end
+ test "mirroring a file from the primary service to secondary services where it doesn't exist" do
+ key = SecureRandom.base58(24)
+ data = "Something else entirely!"
+ checksum = Digest::MD5.base64digest(data)
+
+ @service.primary.upload key, StringIO.new(data), checksum: checksum
+ @service.mirrors.third.upload key, StringIO.new("Surprise!")
+
+ @service.mirror key, checksum: checksum
+ assert_equal data, @service.mirrors.first.download(key)
+ assert_equal data, @service.mirrors.second.download(key)
+ assert_equal "Surprise!", @service.mirrors.third.download(key)
+ end
+
test "URL generation in primary service" do
filename = ActiveStorage::Filename.new("test.txt")
diff --git a/activestorage/test/service/s3_service_test.rb b/activestorage/test/service/s3_service_test.rb
index 74c0aa0405..b9120770e6 100644
--- a/activestorage/test/service/s3_service_test.rb
+++ b/activestorage/test/service/s3_service_test.rb
@@ -46,8 +46,7 @@ if SERVICE_CONFIGURATIONS[:s3]
end
test "uploading with server-side encryption" do
- config = SERVICE_CONFIGURATIONS.deep_merge(s3: { upload: { server_side_encryption: "AES256" } })
- service = ActiveStorage::Service.configure(:s3, config)
+ service = build_service(upload: { server_side_encryption: "AES256" })
begin
key = SecureRandom.base58(24)
@@ -77,6 +76,25 @@ if SERVICE_CONFIGURATIONS[:s3]
ensure
@service.delete key
end
+
+ test "uploading a large object in multiple parts" do
+ service = build_service(upload: { multipart_threshold: 5.megabytes })
+
+ begin
+ key = SecureRandom.base58(24)
+ data = SecureRandom.bytes(8.megabytes)
+
+ service.upload key, StringIO.new(data), checksum: Digest::MD5.base64digest(data)
+ assert data == service.download(key)
+ ensure
+ service.delete key
+ end
+ end
+
+ private
+ def build_service(configuration)
+ ActiveStorage::Service.configure :s3, SERVICE_CONFIGURATIONS.deep_merge(s3: configuration)
+ end
end
else
puts "Skipping S3 Service tests because no S3 configuration was supplied"
diff --git a/activestorage/test/test_helper.rb b/activestorage/test/test_helper.rb
index b34d0d64bb..ac38b9362c 100644
--- a/activestorage/test/test_helper.rb
+++ b/activestorage/test/test_helper.rb
@@ -7,6 +7,7 @@ require "bundler/setup"
require "active_support"
require "active_support/test_case"
require "active_support/testing/autorun"
+require "active_storage/service/mirror_service"
require "image_processing/mini_magick"
begin
@@ -67,7 +68,8 @@ class ActiveSupport::TestCase
checksum = Digest::MD5.file(file).base64digest
create_blob_before_direct_upload(filename: filename, byte_size: byte_size, checksum: checksum, content_type: content_type).tap do |blob|
- ActiveStorage::Blob.service.upload(blob.key, file.open)
+ service = ActiveStorage::Blob.service.try(:primary) || ActiveStorage::Blob.service
+ service.upload(blob.key, file.open)
end
end
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index ccdf2c3040..f20c7c92e6 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,3 +1,63 @@
+* Add `compact_blank` for those times when you want to remove #blank? values from
+ an Enumerable (also `compact_blank!` on Hash, Array, ActionController::Parameters)
+
+ *Dana Sherson*
+
+* Make ActiveSupport::Logger Fiber-safe. Fixes #36752.
+
+ Use `Fiber.current.__id__` in `ActiveSupport::Logger#local_level=` in order
+ to make log level local to Ruby Fibers in addition to Threads.
+
+ Example:
+
+ logger = ActiveSupport::Logger.new(STDOUT)
+ logger.level = 1
+ p "Main is debug? #{logger.debug?}"
+
+ Fiber.new {
+ logger.local_level = 0
+ p "Thread is debug? #{logger.debug?}"
+ }.resume
+
+ p "Main is debug? #{logger.debug?}"
+
+ Before:
+
+ Main is debug? false
+ Thread is debug? true
+ Main is debug? true
+
+ After:
+
+ Main is debug? false
+ Thread is debug? true
+ Main is debug? false
+
+ *Alexander Varnin*
+
+* Allow the `on_rotation` proc used when decrypting/verifying a message to be
+ passed at the constructor level.
+
+ Before:
+
+ crypt = ActiveSupport::MessageEncryptor.new('long_secret')
+ crypt.decrypt_and_verify(encrypted_message, on_rotation: proc { ... })
+ crypt.decrypt_and_verify(another_encrypted_message, on_rotation: proc { ... })
+
+ After:
+
+ crypt = ActiveSupport::MessageEncryptor.new('long_secret', on_rotation: proc { ... })
+ crypt.decrypt_and_verify(encrypted_message)
+ crypt.decrypt_and_verify(another_encrypted_message)
+
+ *Edouard Chin*
+
+* `delegate_missing_to` would raise a `DelegationError` if the object
+ delegated to was `nil`. Now the `allow_nil` option has been added to enable
+ the user to specify they want `nil` returned in this case.
+
+ *Matthew Tanous*
+
* `truncate` would return the original string if it was too short to be truncated
and a frozen string if it were long enough to be truncated. Now truncate will
consistently return an unfrozen string regardless. This behavior is consistent
@@ -5,18 +65,19 @@
Before:
- 'foobar'.truncate(5).frozen?
- => true
- 'foobar'.truncate(6).frozen?
- => false
+ 'foobar'.truncate(5).frozen?
+ # => true
+ 'foobar'.truncate(6).frozen?
+ # => false
After:
- 'foobar'.truncate(5).frozen?
- => false
- 'foobar'.truncate(6).frozen?
- => false
+ 'foobar'.truncate(5).frozen?
+ # => false
+ 'foobar'.truncate(6).frozen?
+ # => false
*Jordan Thomas*
+
Please check [6-0-stable](https://github.com/rails/rails/blob/6-0-stable/activesupport/CHANGELOG.md) for previous changes.
diff --git a/activesupport/activesupport.gemspec b/activesupport/activesupport.gemspec
index 7ecbafc911..da295a0d35 100644
--- a/activesupport/activesupport.gemspec
+++ b/activesupport/activesupport.gemspec
@@ -34,5 +34,5 @@ Gem::Specification.new do |s|
s.add_dependency "tzinfo", "~> 1.1"
s.add_dependency "minitest", "~> 5.1"
s.add_dependency "concurrent-ruby", "~> 1.0", ">= 1.0.2"
- s.add_dependency "zeitwerk", "~> 2.1", ">= 2.1.4"
+ s.add_dependency "zeitwerk", "~> 2.1", ">= 2.1.8"
end
diff --git a/activesupport/lib/active_support/backtrace_cleaner.rb b/activesupport/lib/active_support/backtrace_cleaner.rb
index 02cbfbaee6..f55e821e10 100644
--- a/activesupport/lib/active_support/backtrace_cleaner.rb
+++ b/activesupport/lib/active_support/backtrace_cleaner.rb
@@ -85,7 +85,6 @@ module ActiveSupport
end
private
-
FORMATTED_GEMS_PATTERN = /\A[^\/]+ \([\w.]+\) /
def add_gem_filter
diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb
index e055135bb4..a5063d0784 100644
--- a/activesupport/lib/active_support/cache.rb
+++ b/activesupport/lib/active_support/cache.rb
@@ -678,18 +678,15 @@ module ActiveSupport
end
def instrument(operation, key, options = nil)
- log { "Cache #{operation}: #{normalize_key(key, options)}#{options.blank? ? "" : " (#{options.inspect})"}" }
+ if logger && logger.debug? && !silence?
+ logger.debug "Cache #{operation}: #{normalize_key(key, options)}#{options.blank? ? "" : " (#{options.inspect})"}"
+ end
payload = { key: key }
payload.merge!(options) if options.is_a?(Hash)
ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload) { yield(payload) }
end
- def log
- return unless logger && logger.debug? && !silence?
- logger.debug(yield)
- end
-
def handle_expired_entry(entry, key, options)
if entry && entry.expired?
race_ttl = options[:race_condition_ttl].to_i
diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb
index f43894a1ea..925440a23f 100644
--- a/activesupport/lib/active_support/cache/file_store.rb
+++ b/activesupport/lib/active_support/cache/file_store.rb
@@ -72,7 +72,6 @@ module ActiveSupport
end
private
-
def read_entry(key, options)
if File.exist?(key)
File.open(key) { |f| Marshal.load(f) }
diff --git a/activesupport/lib/active_support/cache/memory_store.rb b/activesupport/lib/active_support/cache/memory_store.rb
index 629eb2dd70..fa24da91b4 100644
--- a/activesupport/lib/active_support/cache/memory_store.rb
+++ b/activesupport/lib/active_support/cache/memory_store.rb
@@ -114,7 +114,6 @@ module ActiveSupport
end
private
-
PER_ENTRY_OVERHEAD = 240
def cached_size(key, entry)
diff --git a/activesupport/lib/active_support/cache/strategy/local_cache.rb b/activesupport/lib/active_support/cache/strategy/local_cache.rb
index 39b32fc7f6..8e80946fbb 100644
--- a/activesupport/lib/active_support/cache/strategy/local_cache.rb
+++ b/activesupport/lib/active_support/cache/strategy/local_cache.rb
@@ -1,6 +1,5 @@
# frozen_string_literal: true
-require "active_support/core_ext/object/duplicable"
require "active_support/core_ext/string/inflections"
require "active_support/per_thread_registry"
@@ -75,7 +74,10 @@ module ActiveSupport
end
def fetch_entry(key, options = nil) # :nodoc:
- @data.fetch(key) { @data[key] = yield }
+ entry = @data.fetch(key) { @data[key] = yield }
+ dup_entry = entry.dup
+ dup_entry&.dup_value!
+ dup_entry
end
end
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index d0644a0f7e..daf98c9528 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -7,7 +7,6 @@ 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
@@ -142,7 +141,6 @@ module ActiveSupport
end
private
-
# A hook invoked every time a before callback is halted.
# This can be overridden in ActiveSupport::Callbacks implementors in order
# to provide better debugging/logging.
@@ -582,7 +580,6 @@ module ActiveSupport
attr_reader :chain
private
-
def append_one(callback)
@callbacks = nil
remove_duplicates(callback)
@@ -843,7 +840,6 @@ module ActiveSupport
end
protected
-
def get_callbacks(name) # :nodoc:
__callbacks[name.to_sym]
end
diff --git a/activesupport/lib/active_support/concurrency/share_lock.rb b/activesupport/lib/active_support/concurrency/share_lock.rb
index f18ccf1c88..eae7d4469f 100644
--- a/activesupport/lib/active_support/concurrency/share_lock.rb
+++ b/activesupport/lib/active_support/concurrency/share_lock.rb
@@ -200,7 +200,6 @@ module ActiveSupport
end
private
-
# Must be called within synchronize
def busy_for_exclusive?(purpose)
busy_for_sharing?(purpose) ||
diff --git a/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb
index e2e11545e2..c7a2378e41 100644
--- a/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb
@@ -20,21 +20,11 @@ module DateAndTime
advance(days: -1)
end
- # Returns a new date/time the specified number of days ago.
- def prev_day(days = 1)
- advance(days: -days)
- end
-
# Returns a new date/time representing tomorrow.
def tomorrow
advance(days: 1)
end
- # Returns a new date/time the specified number of days in the future.
- def next_day(days = 1)
- advance(days: days)
- end
-
# Returns true if the date/time is today.
def today?
to_date == ::Date.current
@@ -198,21 +188,11 @@ module DateAndTime
end
end
- # Returns a new date/time the specified number of months in the future.
- def next_month(months = 1)
- advance(months: months)
- end
-
# Short-hand for months_since(3)
def next_quarter
months_since(3)
end
- # Returns a new date/time the specified number of years in the future.
- def next_year(years = 1)
- advance(years: years)
- end
-
# Returns a new date/time representing the given day in the previous week.
# Week is assumed to start on +start_day+, default is
# +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
@@ -233,11 +213,6 @@ module DateAndTime
end
alias_method :last_weekday, :prev_weekday
- # Returns a new date/time the specified number of months ago.
- def prev_month(months = 1)
- advance(months: -months)
- end
-
# Short-hand for months_ago(1).
def last_month
months_ago(1)
@@ -249,11 +224,6 @@ module DateAndTime
end
alias_method :last_quarter, :prev_quarter
- # Returns a new date/time the specified number of years ago.
- def prev_year(years = 1)
- advance(years: -years)
- end
-
# Short-hand for years_ago(1).
def last_year
years_ago(1)
diff --git a/activesupport/lib/active_support/core_ext/date_and_time/zones.rb b/activesupport/lib/active_support/core_ext/date_and_time/zones.rb
index 894fd9b76d..fb6a27cb27 100644
--- a/activesupport/lib/active_support/core_ext/date_and_time/zones.rb
+++ b/activesupport/lib/active_support/core_ext/date_and_time/zones.rb
@@ -29,7 +29,6 @@ module DateAndTime
end
private
-
def time_with_zone(time, zone)
if time
ActiveSupport::TimeWithZone.new(time.utc? ? time : time.getutc, zone)
diff --git a/activesupport/lib/active_support/core_ext/date_time/conversions.rb b/activesupport/lib/active_support/core_ext/date_time/conversions.rb
index 29725c89f7..231bf870a2 100644
--- a/activesupport/lib/active_support/core_ext/date_time/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/conversions.rb
@@ -96,7 +96,6 @@ class DateTime
end
private
-
def offset_in_seconds
(offset * 86400).to_i
end
diff --git a/activesupport/lib/active_support/core_ext/digest.rb b/activesupport/lib/active_support/core_ext/digest.rb
new file mode 100644
index 0000000000..ce1427e13a
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/digest.rb
@@ -0,0 +1,3 @@
+# frozen_string_literal: true
+
+require "active_support/core_ext/digest/uuid"
diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb
index 4675c41936..728d332306 100644
--- a/activesupport/lib/active_support/core_ext/enumerable.rb
+++ b/activesupport/lib/active_support/core_ext/enumerable.rb
@@ -148,6 +148,41 @@ module Enumerable
map { |element| element[keys.first] }
end
end
+
+ # Returns a new +Array+ without the blank items.
+ # Uses Object#blank? for determining if an item is blank.
+ #
+ # [1, "", nil, 2, " ", [], {}, false, true].compact_blank
+ # # => [1, 2, true]
+ #
+ # Set.new([nil, "", 1, 2])
+ # # => [2, 1] (or [1, 2])
+ #
+ # When called on a +Hash+, returns a new +Hash+ without the blank values.
+ #
+ # { a: "", b: 1, c: nil, d: [], e: false, f: true }.compact_blank
+ # #=> { b: 1, f: true }
+ def compact_blank
+ reject(&:blank?)
+ end
+end
+
+class Hash
+ # Hash#reject has its own definition, so this needs one too.
+ def compact_blank #:nodoc:
+ reject { |_k, v| v.blank? }
+ end
+
+ # Removes all blank values from the +Hash+ in place and returns self.
+ # Uses Object#blank? for determining if a value is blank.
+ #
+ # h = { a: "", b: 1, c: nil, d: [], e: false, f: true }
+ # h.compact_blank!
+ # # => { b: 1, f: true }
+ def compact_blank!
+ # use delete_if rather than reject! because it always returns self even if nothing changed
+ delete_if { |_k, v| v.blank? }
+ end
end
class Range #:nodoc:
@@ -185,4 +220,15 @@ class Array #:nodoc:
super
end
end
+
+ # Removes all blank elements from the +Array+ in place and returns self.
+ # Uses Object#blank? for determining if an item is blank.
+ #
+ # a = [1, "", nil, 2, " ", [], {}, false, true]
+ # a.compact_blank!
+ # # => [1, 2, true]
+ def compact_blank!
+ # use delete_if rather than reject! because it always returns self even if nothing changed
+ delete_if(&:blank?)
+ end
end
diff --git a/activesupport/lib/active_support/core_ext/hash/deep_transform_values.rb b/activesupport/lib/active_support/core_ext/hash/deep_transform_values.rb
index 720a1f67c8..18acb1e70c 100644
--- a/activesupport/lib/active_support/core_ext/hash/deep_transform_values.rb
+++ b/activesupport/lib/active_support/core_ext/hash/deep_transform_values.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
class Hash
- # Returns a new hash with all keys converted by the block operation.
- # This includes the keys from the root hash and from all
+ # Returns a new hash with all values converted by the block operation.
+ # This includes the values from the root hash and from all
# nested hashes and arrays.
#
# hash = { person: { name: 'Rob', age: '28' } }
diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb
index 9fe7f8fe01..14d7f0c484 100644
--- a/activesupport/lib/active_support/core_ext/module/delegation.rb
+++ b/activesupport/lib/active_support/core_ext/module/delegation.rb
@@ -205,18 +205,18 @@ class Module
if allow_nil
method_def = [
"def #{method_prefix}#{method}(#{definition})",
- "_ = #{to}",
- "if !_.nil? || nil.respond_to?(:#{method})",
- " _.#{method}(#{definition})",
- "end",
- "end"
+ " _ = #{to}",
+ " if !_.nil? || nil.respond_to?(:#{method})",
+ " _.#{method}(#{definition})",
+ " end",
+ "end"
].join ";"
else
exception = %(raise DelegationError, "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
method_def = [
"def #{method_prefix}#{method}(#{definition})",
- " _ = #{to}",
+ " _ = #{to}",
" _.#{method}(#{definition})",
"rescue NoMethodError => e",
" if _.nil? && e.name == :#{method}",
@@ -274,8 +274,14 @@ class Module
# variables, methods, constants, etc.
#
# The delegated method must be public on the target, otherwise it will
- # raise +NoMethodError+.
- def delegate_missing_to(target)
+ # raise +DelegationError+. If you wish to instead return +nil+,
+ # use the <tt>:allow_nil</tt> option.
+ #
+ # The <tt>marshal_dump</tt> and <tt>_dump</tt> methods are exempt from
+ # delegation due to possible interference when calling
+ # <tt>Marshal.dump(object)</tt>, should the delegation target method
+ # of <tt>object</tt> add or remove instance variables.
+ def delegate_missing_to(target, allow_nil: nil)
target = target.to_s
target = "self.#{target}" if DELEGATION_RESERVED_METHOD_NAMES.include?(target)
@@ -284,6 +290,7 @@ class Module
# It may look like an oversight, but we deliberately do not pass
# +include_private+, because they do not get delegated.
+ return false if name == :marshal_dump || name == :_dump
#{target}.respond_to?(name) || super
end
@@ -295,7 +302,11 @@ class Module
super
rescue NoMethodError
if #{target}.nil?
- raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil"
+ if #{allow_nil == true}
+ nil
+ else
+ raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil"
+ end
else
raise
end
diff --git a/activesupport/lib/active_support/core_ext/object/duplicable.rb b/activesupport/lib/active_support/core_ext/object/duplicable.rb
index c78ee6bbfc..3ebcdca02b 100644
--- a/activesupport/lib/active_support/core_ext/object/duplicable.rb
+++ b/activesupport/lib/active_support/core_ext/object/duplicable.rb
@@ -28,96 +28,6 @@ class Object
end
end
-class NilClass
- begin
- nil.dup
- rescue TypeError
-
- # +nil+ is not duplicable:
- #
- # nil.duplicable? # => false
- # nil.dup # => TypeError: can't dup NilClass
- def duplicable?
- false
- end
- end
-end
-
-class FalseClass
- begin
- false.dup
- rescue TypeError
-
- # +false+ is not duplicable:
- #
- # false.duplicable? # => false
- # false.dup # => TypeError: can't dup FalseClass
- def duplicable?
- false
- end
- end
-end
-
-class TrueClass
- begin
- true.dup
- rescue TypeError
-
- # +true+ is not duplicable:
- #
- # true.duplicable? # => false
- # true.dup # => TypeError: can't dup TrueClass
- def duplicable?
- false
- end
- end
-end
-
-class Symbol
- begin
- :symbol.dup
-
- # Some symbols couldn't be duped in Ruby 2.4.0 only, due to a bug.
- # This feature check catches any regression.
- "symbol_from_string".to_sym.dup
- rescue TypeError
-
- # Symbols are not duplicable:
- #
- # :my_symbol.duplicable? # => false
- # :my_symbol.dup # => TypeError: can't dup Symbol
- def duplicable?
- false
- end
- end
-end
-
-class Numeric
- begin
- 1.dup
- rescue TypeError
-
- # Numbers are not duplicable:
- #
- # 3.duplicable? # => false
- # 3.dup # => TypeError: can't dup Integer
- def duplicable?
- false
- end
- end
-end
-
-require "bigdecimal"
-class BigDecimal
- # BigDecimals are duplicable:
- #
- # BigDecimal("1.2").duplicable? # => true
- # BigDecimal("1.2").dup # => #<BigDecimal:...,'0.12E1',18(18)>
- def duplicable?
- true
- end
-end
-
class Method
# Methods are not duplicable:
#
@@ -128,32 +38,12 @@ class Method
end
end
-class Complex
- begin
- Complex(1).dup
- rescue TypeError
-
- # Complexes are not duplicable:
- #
- # Complex(1).duplicable? # => false
- # Complex(1).dup # => TypeError: can't copy Complex
- def duplicable?
- false
- end
- end
-end
-
-class Rational
- begin
- Rational(1).dup
- rescue TypeError
-
- # Rationals are not duplicable:
- #
- # Rational(1).duplicable? # => false
- # Rational(1).dup # => TypeError: can't copy Rational
- def duplicable?
- false
- end
+class UnboundMethod
+ # Unbound methods are not duplicable:
+ #
+ # method(:puts).unbind.duplicable? # => false
+ # method(:puts).unbind.dup # => TypeError: allocator undefined for UnboundMethod
+ def duplicable?
+ false
end
end
diff --git a/activesupport/lib/active_support/core_ext/range/each.rb b/activesupport/lib/active_support/core_ext/range/each.rb
index 2f22cd0e92..2d86997edf 100644
--- a/activesupport/lib/active_support/core_ext/range/each.rb
+++ b/activesupport/lib/active_support/core_ext/range/each.rb
@@ -15,7 +15,6 @@ module ActiveSupport
end
private
-
def ensure_iteration_allowed
raise TypeError, "can't iterate from #{first.class}" if first.is_a?(TimeWithZone)
end
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 645b1fea17..f48ea56326 100644
--- a/activesupport/lib/active_support/core_ext/string/output_safety.rb
+++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb
@@ -291,7 +291,6 @@ module ActiveSupport #:nodoc:
end
private
-
def html_escape_interpolated_argument(arg)
(!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s)
end
diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb
index f09a6271ad..eed34965e3 100644
--- a/activesupport/lib/active_support/core_ext/time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -311,4 +311,34 @@ class Time
end
alias_method :eql_without_coercion, :eql?
alias_method :eql?, :eql_with_coercion
+
+ # Returns a new time the specified number of days ago.
+ def prev_day(days = 1)
+ advance(days: -days)
+ end
+
+ # Returns a new time the specified number of days in the future.
+ def next_day(days = 1)
+ advance(days: days)
+ end
+
+ # Returns a new time the specified number of months ago.
+ def prev_month(months = 1)
+ advance(months: -months)
+ end
+
+ # Returns a new time the specified number of months in the future.
+ def next_month(months = 1)
+ advance(months: months)
+ end
+
+ # Returns a new time the specified number of years ago.
+ def prev_year(years = 1)
+ advance(years: -years)
+ end
+
+ # Returns a new time the specified number of years in the future.
+ def next_year(years = 1)
+ advance(years: years)
+ end
end
diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb
index 82f07c085e..923d6ad228 100644
--- a/activesupport/lib/active_support/dependencies.rb
+++ b/activesupport/lib/active_support/dependencies.rb
@@ -20,6 +20,9 @@ module ActiveSupport #:nodoc:
module Dependencies #:nodoc:
extend self
+ UNBOUND_METHOD_MODULE_NAME = Module.instance_method(:name)
+ private_constant :UNBOUND_METHOD_MODULE_NAME
+
mattr_accessor :interlock, default: Interlock.new
# :doc:
@@ -201,6 +204,11 @@ module ActiveSupport #:nodoc:
end
end
+ def self.include_into(base)
+ base.include(self)
+ append_features(base)
+ end
+
def const_missing(const_name)
from_mod = anonymous? ? guess_for_anonymous(const_name) : self
Dependencies.load_missing_constant(from_mod, const_name)
@@ -230,6 +238,21 @@ module ActiveSupport #:nodoc:
base.class_eval do
define_method(:load, Kernel.instance_method(:load))
private :load
+
+ define_method(:require, Kernel.instance_method(:require))
+ private :require
+ end
+ end
+
+ def self.include_into(base)
+ base.include(self)
+
+ if base.instance_method(:load).owner == base
+ base.remove_method(:load)
+ end
+
+ if base.instance_method(:require).owner == base
+ base.remove_method(:require)
end
end
@@ -290,7 +313,6 @@ module ActiveSupport #:nodoc:
end
private
-
def load(file, wrap = false)
result = false
load_dependency(file) { result = super }
@@ -326,9 +348,9 @@ module ActiveSupport #:nodoc:
end
def hook!
- Object.class_eval { include Loadable }
- Module.class_eval { include ModuleConstMissing }
- Exception.class_eval { include Blamable }
+ Loadable.include_into(Object)
+ ModuleConstMissing.include_into(Module)
+ Exception.include(Blamable)
end
def unhook!
@@ -639,7 +661,7 @@ module ActiveSupport #:nodoc:
# Determine if the given constant has been automatically loaded.
def autoloaded?(desc)
- return false if desc.is_a?(Module) && desc.anonymous?
+ return false if desc.is_a?(Module) && real_mod_name(desc).nil?
name = to_constant_name desc
return false unless qualified_const_defined?(name)
autoloaded_constants.include?(name)
@@ -695,7 +717,7 @@ module ActiveSupport #:nodoc:
when String then desc.sub(/^::/, "")
when Symbol then desc.to_s
when Module
- desc.name ||
+ real_mod_name(desc) ||
raise(ArgumentError, "Anonymous modules have no name to be referenced by")
else raise TypeError, "Not a valid constant descriptor: #{desc.inspect}"
end
@@ -769,6 +791,14 @@ module ActiveSupport #:nodoc:
def log(message)
logger.debug("autoloading: #{message}") if logger && verbose
end
+
+ private
+
+ # Returns the original name of a class or module even if `name` has been
+ # overridden.
+ def real_mod_name(mod)
+ UNBOUND_METHOD_MODULE_NAME.bind(mod).call
+ end
end
end
diff --git a/activesupport/lib/active_support/dependencies/zeitwerk_integration.rb b/activesupport/lib/active_support/dependencies/zeitwerk_integration.rb
index fd39ad6e55..f75083a05a 100644
--- a/activesupport/lib/active_support/dependencies/zeitwerk_integration.rb
+++ b/activesupport/lib/active_support/dependencies/zeitwerk_integration.rb
@@ -28,7 +28,7 @@ module ActiveSupport
end
def autoloaded?(object)
- cpath = object.is_a?(Module) ? object.name : object.to_s
+ cpath = object.is_a?(Module) ? real_mod_name(object) : object.to_s
Rails.autoloaders.main.unloadable_cpath?(cpath)
end
@@ -56,7 +56,6 @@ module ActiveSupport
end
private
-
def setup_autoloaders(enable_reloading)
Dependencies.autoload_paths.each do |autoload_path|
# Zeitwerk only accepts existing directories in `push_dir` to
diff --git a/activesupport/lib/active_support/deprecation/proxy_wrappers.rb b/activesupport/lib/active_support/deprecation/proxy_wrappers.rb
index 56f1e23136..d7d3c30b97 100644
--- a/activesupport/lib/active_support/deprecation/proxy_wrappers.rb
+++ b/activesupport/lib/active_support/deprecation/proxy_wrappers.rb
@@ -120,9 +120,16 @@ module ActiveSupport
# # => DEPRECATION WARNING: PLANETS is deprecated! Use PLANETS_POST_2006 instead.
# (Backtrace information…)
# ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
- class DeprecatedConstantProxy < DeprecationProxy
+ class DeprecatedConstantProxy < Module
+ def self.new(*args, &block)
+ object = args.first
+
+ return object unless object
+ super
+ end
+
def initialize(old_const, new_const, deprecator = ActiveSupport::Deprecation.instance, message: "#{old_const} is deprecated! Use #{new_const} instead.")
- require "active_support/inflector/methods"
+ Kernel.require "active_support/inflector/methods"
@old_const = old_const
@new_const = new_const
@@ -130,6 +137,14 @@ module ActiveSupport
@message = message
end
+ instance_methods.each { |m| undef_method m unless /^__|^object_id$/.match?(m) }
+
+ # Don't give a deprecation warning on inspect since test/unit and error
+ # logs rely on it for diagnostics.
+ def inspect
+ target.inspect
+ end
+
# Returns the class of the new constant.
#
# PLANETS_POST_2006 = %w(mercury venus earth mars jupiter saturn uranus neptune)
@@ -144,8 +159,14 @@ module ActiveSupport
ActiveSupport::Inflector.constantize(@new_const.to_s)
end
- def warn(callstack, called, args)
- @deprecator.warn(@message, callstack)
+ def const_missing(name)
+ @deprecator.warn(@message, caller_locations)
+ target.const_get(name)
+ end
+
+ def method_missing(called, *args, &block)
+ @deprecator.warn(@message, caller_locations)
+ target.__send__(called, *args, &block)
end
end
end
diff --git a/activesupport/lib/active_support/descendants_tracker.rb b/activesupport/lib/active_support/descendants_tracker.rb
index 21565138a7..b14842bf67 100644
--- a/activesupport/lib/active_support/descendants_tracker.rb
+++ b/activesupport/lib/active_support/descendants_tracker.rb
@@ -41,7 +41,6 @@ module ActiveSupport
end
private
-
def accumulate_descendants(klass, acc)
if direct_descendants = @@direct_descendants[klass]
direct_descendants.each do |direct_descendant|
@@ -78,15 +77,17 @@ module ActiveSupport
end
def <<(klass)
- cleanup!
@refs << WeakRef.new(klass)
end
def each
- @refs.each do |ref|
+ @refs.reject! do |ref|
yield ref.__getobj__
+ false
rescue WeakRef::RefError
+ true
end
+ self
end
def refs_size
diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb
index a30bd11a87..2b4f1288f1 100644
--- a/activesupport/lib/active_support/duration.rb
+++ b/activesupport/lib/active_support/duration.rb
@@ -198,7 +198,6 @@ module ActiveSupport
end
private
-
def calculate_total_seconds(parts)
parts.inject(0) do |total, (part, value)|
total + value * PARTS_IN_SECONDS[part]
@@ -399,7 +398,6 @@ module ActiveSupport
end
private
-
def sum(sign, time = ::Time.current)
parts.inject(time) do |t, (type, number)|
if t.acts_like?(:time) || t.acts_like?(:date)
diff --git a/activesupport/lib/active_support/duration/iso8601_parser.rb b/activesupport/lib/active_support/duration/iso8601_parser.rb
index d3233e6111..83f3b28602 100644
--- a/activesupport/lib/active_support/duration/iso8601_parser.rb
+++ b/activesupport/lib/active_support/duration/iso8601_parser.rb
@@ -80,7 +80,6 @@ module ActiveSupport
end
private
-
def finished?
scanner.eos?
end
diff --git a/activesupport/lib/active_support/duration/iso8601_serializer.rb b/activesupport/lib/active_support/duration/iso8601_serializer.rb
index 1125454919..8314df12b0 100644
--- a/activesupport/lib/active_support/duration/iso8601_serializer.rb
+++ b/activesupport/lib/active_support/duration/iso8601_serializer.rb
@@ -32,7 +32,6 @@ module ActiveSupport
end
private
-
# Return pair of duration's parts and whole duration sign.
# Parts are summarized (as they can become repetitive due to addition, etc).
# Zero parts are removed as not significant.
diff --git a/activesupport/lib/active_support/evented_file_update_checker.rb b/activesupport/lib/active_support/evented_file_update_checker.rb
index 3893b0de0e..6075e0a3d3 100644
--- a/activesupport/lib/active_support/evented_file_update_checker.rb
+++ b/activesupport/lib/active_support/evented_file_update_checker.rb
@@ -107,13 +107,23 @@ module ActiveSupport
private
def boot!
- Listen.to(*@dtw, &method(:changed)).start
+ normalize_dirs!
+
+ unless @dtw.empty?
+ Listen.to(*@dtw, &method(:changed)).start
+ end
end
def shutdown!
Listen.stop
end
+ def normalize_dirs!
+ @dirs.transform_keys! do |dir|
+ dir.exist? ? dir.realpath : dir
+ end
+ end
+
def changed(modified, added, removed)
unless updated?
@updated.make_true if (modified + added + removed).any? { |f| watching?(f) }
@@ -187,13 +197,6 @@ module ActiveSupport
lcsp
end
- # Returns the deepest existing ascendant, which could be the argument itself.
- def existing_parent(dir)
- dir.ascend do |ascendant|
- break ascendant if ascendant.directory?
- end
- end
-
# Filters out directories which are descendants of others in the collection (stable).
def filter_out_descendants(dirs)
return dirs if dirs.length < 2
@@ -214,7 +217,6 @@ module ActiveSupport
end
private
-
def ascendant_of?(base, other)
base != other && other.ascend do |ascendant|
break true if base == ascendant
diff --git a/activesupport/lib/active_support/file_update_checker.rb b/activesupport/lib/active_support/file_update_checker.rb
index 1a0bb10815..9b665e7f19 100644
--- a/activesupport/lib/active_support/file_update_checker.rb
+++ b/activesupport/lib/active_support/file_update_checker.rb
@@ -98,7 +98,6 @@ module ActiveSupport
end
private
-
def watched
@watched || begin
all = @files.select { |f| File.exist?(f) }
diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb
index 5981763f0e..6acf64cb39 100644
--- a/activesupport/lib/active_support/hash_with_indifferent_access.rb
+++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb
@@ -367,18 +367,20 @@ module ActiveSupport
key.kind_of?(Symbol) ? key.to_s : key
end
- def convert_value(value, options = {}) # :doc:
+ def convert_value(value, for: nil) # :doc:
+ conversion = binding.local_variable_get(:for)
+
if value.is_a? Hash
- if options[:for] == :to_hash
+ if conversion == :to_hash
value.to_hash
else
value.nested_under_indifferent_access
end
elsif value.is_a?(Array)
- if options[:for] != :assignment || value.frozen?
+ if conversion != :assignment || value.frozen?
value = value.dup
end
- value.map! { |e| convert_value(e, options) }
+ value.map! { |e| convert_value(e, for: conversion) }
else
value
end
diff --git a/activesupport/lib/active_support/inflector/inflections.rb b/activesupport/lib/active_support/inflector/inflections.rb
index 88cdd99dbd..efee74a1df 100644
--- a/activesupport/lib/active_support/inflector/inflections.rb
+++ b/activesupport/lib/active_support/inflector/inflections.rb
@@ -2,7 +2,6 @@
require "concurrent/map"
require "active_support/i18n"
-require "active_support/deprecation"
module ActiveSupport
module Inflector
@@ -230,7 +229,6 @@ module ActiveSupport
end
private
-
def define_acronym_regex_patterns
@acronym_regex = @acronyms.empty? ? /(?=a)b/ : /#{@acronyms.values.join("|")}/
@acronyms_camelize_regex = /^(?:#{@acronym_regex}(?=\b|[A-Z_])|\w)/
diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb
index ee193add6f..18f3f53879 100644
--- a/activesupport/lib/active_support/inflector/methods.rb
+++ b/activesupport/lib/active_support/inflector/methods.rb
@@ -359,7 +359,6 @@ module ActiveSupport
end
private
-
# Mounts a regular expression, returned as a string to ease interpolation,
# that will match part by part the given constant.
#
diff --git a/activesupport/lib/active_support/json/decoding.rb b/activesupport/lib/active_support/json/decoding.rb
index 402a3fbe60..b4bf882bc3 100644
--- a/activesupport/lib/active_support/json/decoding.rb
+++ b/activesupport/lib/active_support/json/decoding.rb
@@ -44,7 +44,6 @@ module ActiveSupport
end
private
-
def convert_dates_from(data)
case data
when nil
diff --git a/activesupport/lib/active_support/lazy_load_hooks.rb b/activesupport/lib/active_support/lazy_load_hooks.rb
index a6b096a973..c6f7ccf0a2 100644
--- a/activesupport/lib/active_support/lazy_load_hooks.rb
+++ b/activesupport/lib/active_support/lazy_load_hooks.rb
@@ -54,7 +54,6 @@ module ActiveSupport
end
private
-
def with_execution_control(name, block, once)
unless @run_once[name].include?(block)
@run_once[name] << block if once
diff --git a/activesupport/lib/active_support/log_subscriber.rb b/activesupport/lib/active_support/log_subscriber.rb
index 938cfdb914..8b9dd1fffe 100644
--- a/activesupport/lib/active_support/log_subscriber.rb
+++ b/activesupport/lib/active_support/log_subscriber.rb
@@ -29,6 +29,9 @@ module ActiveSupport
# subscriber, the line above should be called after your
# <tt>ActiveRecord::LogSubscriber</tt> definition.
#
+ # A logger also needs to be set with <tt>ActiveRecord::LogSubscriber.logger=</tt>.
+ # This is assigned automatically in a Rails environment.
+ #
# After configured, whenever a <tt>"sql.active_record"</tt> notification is published,
# it will properly dispatch the event
# (<tt>ActiveSupport::Notifications::Event</tt>) to the sql method.
@@ -112,7 +115,6 @@ module ActiveSupport
end
private
-
%w(info debug warn error fatal unknown).each do |level|
class_eval <<-METHOD, __FILE__, __LINE__ + 1
def #{level}(progname = nil, &block)
diff --git a/activesupport/lib/active_support/logger_thread_safe_level.rb b/activesupport/lib/active_support/logger_thread_safe_level.rb
index f16c90cfc6..1775a41492 100644
--- a/activesupport/lib/active_support/logger_thread_safe_level.rb
+++ b/activesupport/lib/active_support/logger_thread_safe_level.rb
@@ -3,6 +3,7 @@
require "active_support/concern"
require "active_support/core_ext/module/attribute_accessors"
require "concurrent"
+require "fiber"
module ActiveSupport
module LoggerThreadSafeLevel # :nodoc:
@@ -28,7 +29,7 @@ module ActiveSupport
end
def local_log_id
- Thread.current.__id__
+ Fiber.current.__id__
end
def local_level
diff --git a/activesupport/lib/active_support/message_verifier.rb b/activesupport/lib/active_support/message_verifier.rb
index c4a4afe95f..a5dc1181d8 100644
--- a/activesupport/lib/active_support/message_verifier.rb
+++ b/activesupport/lib/active_support/message_verifier.rb
@@ -178,8 +178,8 @@ module ActiveSupport
# Generates a signed message for the provided value.
#
- # The message is signed with the +MessageVerifier+'s secret. Without knowing
- # the secret, the original value cannot be extracted from the message.
+ # The message is signed with the +MessageVerifier+'s secret.
+ # Returns Base64-encoded message joined with the generated signature.
#
# verifier = ActiveSupport::MessageVerifier.new 's3Krit'
# verifier.generate 'a private message' # => "BAhJIhRwcml2YXRlLW1lc3NhZ2UGOgZFVA==--e2d724331ebdee96a10fb99b089508d1c72bd772"
diff --git a/activesupport/lib/active_support/messages/rotator.rb b/activesupport/lib/active_support/messages/rotator.rb
index 823a399d67..50ea7dcd8d 100644
--- a/activesupport/lib/active_support/messages/rotator.rb
+++ b/activesupport/lib/active_support/messages/rotator.rb
@@ -3,11 +3,12 @@
module ActiveSupport
module Messages
module Rotator # :nodoc:
- def initialize(*, **options)
+ def initialize(*, on_rotation: nil, **options)
super
@options = options
@rotations = []
+ @on_rotation = on_rotation
end
def rotate(*secrets, **options)
@@ -17,7 +18,7 @@ module ActiveSupport
module Encryptor
include Rotator
- def decrypt_and_verify(*args, on_rotation: nil, **options)
+ def decrypt_and_verify(*args, on_rotation: @on_rotation, **options)
super
rescue MessageEncryptor::InvalidMessage, MessageVerifier::InvalidSignature
run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, options) } || raise
@@ -32,7 +33,7 @@ module ActiveSupport
module Verifier
include Rotator
- def verified(*args, on_rotation: nil, **options)
+ def verified(*args, on_rotation: @on_rotation, **options)
super || run_rotations(on_rotation) { |verifier| verifier.verified(*args, options) }
end
@@ -46,7 +47,7 @@ module ActiveSupport
def run_rotations(on_rotation)
@rotations.find do |rotation|
if message = yield(rotation) rescue next
- on_rotation.call if on_rotation
+ on_rotation&.call
return message
end
end
diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb
index a1e23aeaca..2ba3936cae 100644
--- a/activesupport/lib/active_support/multibyte/chars.rb
+++ b/activesupport/lib/active_support/multibyte/chars.rb
@@ -207,7 +207,6 @@ module ActiveSupport #:nodoc:
end
private
-
def chars(string)
self.class.new(string)
end
diff --git a/activesupport/lib/active_support/multibyte/unicode.rb b/activesupport/lib/active_support/multibyte/unicode.rb
index ce8ecece69..3956137049 100644
--- a/activesupport/lib/active_support/multibyte/unicode.rb
+++ b/activesupport/lib/active_support/multibyte/unicode.rb
@@ -148,7 +148,6 @@ module ActiveSupport
end
private
-
def recode_windows1252_chars(string)
string.encode(Encoding::UTF_8, Encoding::Windows_1252, invalid: :replace, undef: :replace)
end
diff --git a/activesupport/lib/active_support/notifications.rb b/activesupport/lib/active_support/notifications.rb
index d9e93b530c..a7a6112b0f 100644
--- a/activesupport/lib/active_support/notifications.rb
+++ b/activesupport/lib/active_support/notifications.rb
@@ -38,6 +38,19 @@ module ActiveSupport
# payload # => Hash, the payload
# end
#
+ # Here, the +start+ and +finish+ values represent wall-clock time. If you are
+ # concerned about accuracy, you can register a monotonic subscriber.
+ #
+ # ActiveSupport::Notifications.monotonic_subscribe('render') do |name, start, finish, id, payload|
+ # name # => String, name of the event (such as 'render' from above)
+ # start # => Monotonic time, when the instrumented block started execution
+ # finish # => Monotonic time, when the instrumented block ended execution
+ # id # => String, unique ID for the instrumenter that fired the event
+ # payload # => Hash, the payload
+ # end
+ #
+ # The +start+ and +finish+ values above represent monotonic time.
+ #
# For instance, let's store all "render" events in an array:
#
# events = []
@@ -135,6 +148,16 @@ module ActiveSupport
# during the execution of the block. The callback is unsubscribed automatically
# after that.
#
+ # To record +started+ and +finished+ values with monotonic time,
+ # specify the optional <tt>:monotonic</tt> option to the
+ # <tt>subscribed</tt> method. The <tt>:monotonic</tt> option is set
+ # to +false+ by default.
+ #
+ # callback = lambda {|name, started, finished, unique_id, payload| ... }
+ # ActiveSupport::Notifications.subscribed(callback, "sql.active_record", monotonic: true) do
+ # ...
+ # end
+ #
# === Manual Unsubscription
#
# The +subscribe+ method returns a subscriber object:
@@ -208,12 +231,16 @@ module ActiveSupport
# ActiveSupport::Notifications.subscribe(/render/) do |event|
# @event = event
# end
- def subscribe(*args, &block)
- notifier.subscribe(*args, &block)
+ def subscribe(pattern = nil, callback = nil, &block)
+ notifier.subscribe(pattern, callback, monotonic: false, &block)
+ end
+
+ def monotonic_subscribe(pattern = nil, callback = nil, &block)
+ notifier.subscribe(pattern, callback, monotonic: true, &block)
end
- def subscribed(callback, *args, &block)
- subscriber = subscribe(*args, &callback)
+ def subscribed(callback, pattern = nil, monotonic: false, &block)
+ subscriber = notifier.subscribe(pattern, callback, monotonic: monotonic)
yield
ensure
unsubscribe(subscriber)
diff --git a/activesupport/lib/active_support/notifications/fanout.rb b/activesupport/lib/active_support/notifications/fanout.rb
index c506b35b1e..dda71b880e 100644
--- a/activesupport/lib/active_support/notifications/fanout.rb
+++ b/activesupport/lib/active_support/notifications/fanout.rb
@@ -20,8 +20,8 @@ module ActiveSupport
super
end
- def subscribe(pattern = nil, callable = nil, &block)
- subscriber = Subscribers.new(pattern, callable || block)
+ def subscribe(pattern = nil, callable = nil, monotonic: false, &block)
+ subscriber = Subscribers.new(pattern, callable || block, monotonic)
synchronize do
if String === pattern
@string_subscribers[pattern] << subscriber
@@ -84,8 +84,8 @@ module ActiveSupport
end
module Subscribers # :nodoc:
- def self.new(pattern, listener)
- subscriber_class = Timed
+ def self.new(pattern, listener, monotonic)
+ subscriber_class = monotonic ? MonotonicTimed : Timed
if listener.respond_to?(:start) && listener.respond_to?(:finish)
subscriber_class = Evented
@@ -190,6 +190,23 @@ module ActiveSupport
end
end
+ class MonotonicTimed < Evented # :nodoc:
+ def publish(name, *args)
+ @delegate.call name, *args
+ end
+
+ def start(name, id, payload)
+ timestack = Thread.current[:_timestack_monotonic] ||= []
+ timestack.push Concurrent.monotonic_time
+ end
+
+ def finish(name, id, payload)
+ timestack = Thread.current[:_timestack_monotonic]
+ started = timestack.pop
+ @delegate.call(name, started, Concurrent.monotonic_time, id, payload)
+ end
+ end
+
class EventObject < Evented
def start(name, id, payload)
stack = Thread.current[:_event_stack] ||= []
@@ -201,6 +218,7 @@ module ActiveSupport
def finish(name, id, payload)
stack = Thread.current[:_event_stack]
event = stack.pop
+ event.payload = payload
event.finish!
@delegate.call event
end
diff --git a/activesupport/lib/active_support/notifications/instrumenter.rb b/activesupport/lib/active_support/notifications/instrumenter.rb
index 12546511a8..24e1ab313a 100644
--- a/activesupport/lib/active_support/notifications/instrumenter.rb
+++ b/activesupport/lib/active_support/notifications/instrumenter.rb
@@ -46,14 +46,14 @@ module ActiveSupport
end
private
-
def unique_id
SecureRandom.hex(10)
end
end
class Event
- attr_reader :name, :time, :end, :transaction_id, :payload, :children
+ attr_reader :name, :time, :end, :transaction_id, :children
+ attr_accessor :payload
def self.clock_gettime_supported? # :nodoc:
defined?(Process::CLOCK_PROCESS_CPUTIME_ID) &&
diff --git a/activesupport/lib/active_support/number_helper.rb b/activesupport/lib/active_support/number_helper.rb
index d19a2f64d4..0c87114c0d 100644
--- a/activesupport/lib/active_support/number_helper.rb
+++ b/activesupport/lib/active_support/number_helper.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require "active_support/dependencies/autoload"
-
module ActiveSupport
module NumberHelper
extend ActiveSupport::Autoload
@@ -228,7 +226,7 @@ module ActiveSupport
end
# Formats the bytes in +number+ into a more understandable
- # representation (e.g., giving it 1500 yields 1.5 KB). This
+ # representation (e.g., giving it 1500 yields 1.46 KB). This
# method is useful for reporting file sizes to users. You can
# customize the format in the +options+ hash.
#
diff --git a/activesupport/lib/active_support/number_helper/number_converter.rb b/activesupport/lib/active_support/number_helper/number_converter.rb
index 06ba797a13..76dd12f27d 100644
--- a/activesupport/lib/active_support/number_helper/number_converter.rb
+++ b/activesupport/lib/active_support/number_helper/number_converter.rb
@@ -136,7 +136,6 @@ module ActiveSupport
end
private
-
def options
@options ||= format_options.merge(opts)
end
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 0e8ae82dd5..4ad89dc62e 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
@@ -21,7 +21,6 @@ module ActiveSupport
end
private
-
def absolute_value(number)
number.respond_to?(:abs) ? number.abs : number.sub(/\A-/, "")
end
diff --git a/activesupport/lib/active_support/number_helper/number_to_delimited_converter.rb b/activesupport/lib/active_support/number_helper/number_to_delimited_converter.rb
index 467a580a2e..351444289c 100644
--- a/activesupport/lib/active_support/number_helper/number_to_delimited_converter.rb
+++ b/activesupport/lib/active_support/number_helper/number_to_delimited_converter.rb
@@ -14,7 +14,6 @@ module ActiveSupport
end
private
-
def parts
left, right = number.to_s.split(".")
left.gsub!(delimiter_pattern) do |digit_to_delimit|
diff --git a/activesupport/lib/active_support/number_helper/number_to_human_converter.rb b/activesupport/lib/active_support/number_helper/number_to_human_converter.rb
index 494408fc01..f089d7ae65 100644
--- a/activesupport/lib/active_support/number_helper/number_to_human_converter.rb
+++ b/activesupport/lib/active_support/number_helper/number_to_human_converter.rb
@@ -31,7 +31,6 @@ module ActiveSupport
end
private
-
def format
options[:format] || translate_in_locale("human.decimal_units.format")
end
diff --git a/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb b/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb
index 91262fa656..ed8acbda6e 100644
--- a/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb
+++ b/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb
@@ -28,7 +28,6 @@ module ActiveSupport
end
private
-
def conversion_format
translate_number_value_with_default("human.storage_units.format", locale: options[:locale], raise: true)
end
diff --git a/activesupport/lib/active_support/number_helper/number_to_phone_converter.rb b/activesupport/lib/active_support/number_helper/number_to_phone_converter.rb
index d5e72981b4..21eadfdcc7 100644
--- a/activesupport/lib/active_support/number_helper/number_to_phone_converter.rb
+++ b/activesupport/lib/active_support/number_helper/number_to_phone_converter.rb
@@ -12,7 +12,6 @@ module ActiveSupport
end
private
-
def convert_to_phone_number(number)
if opts[:area_code]
convert_with_area_code(number)
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 6ceb9a572e..767cfe22ad 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
@@ -38,7 +38,6 @@ module ActiveSupport
end
private
-
def strip_insignificant_zeros
options[:strip_insignificant_zeros]
end
diff --git a/activesupport/lib/active_support/parameter_filter.rb b/activesupport/lib/active_support/parameter_filter.rb
index 1389d82523..e1cd7c46c1 100644
--- a/activesupport/lib/active_support/parameter_filter.rb
+++ b/activesupport/lib/active_support/parameter_filter.rb
@@ -51,7 +51,6 @@ module ActiveSupport
end
private
-
def compiled_filter
@compiled_filter ||= CompiledFilter.compile(@filters, mask: @mask)
end
@@ -110,7 +109,12 @@ module ActiveSupport
elsif value.is_a?(Hash)
value = call(value, parents, original_params)
elsif value.is_a?(Array)
- value = value.map { |v| v.is_a?(Hash) ? call(v, parents, original_params) : v }
+ # If we don't pop the current parent it will be duplicated as we
+ # process each array value.
+ parents.pop if deep_regexps
+ value = value.map { |v| value_for_key(key, v, parents, original_params) }
+ # Restore the parent stack after processing the array.
+ parents.push(key) if deep_regexps
elsif blocks.any?
key = key.dup if key.duplicable?
value = value.dup if value.duplicable?
diff --git a/activesupport/lib/active_support/rails.rb b/activesupport/lib/active_support/rails.rb
index 8b727a69ec..30857f04d8 100644
--- a/activesupport/lib/active_support/rails.rb
+++ b/activesupport/lib/active_support/rails.rb
@@ -13,9 +13,6 @@
# Defines Object#blank? and Object#present?.
require "active_support/core_ext/object/blank"
-# Rails own autoload, eager_load, etc.
-require "active_support/dependencies/autoload"
-
# Support for ClassMethods and the included macro.
require "active_support/concern"
diff --git a/activesupport/lib/active_support/secure_compare_rotator.rb b/activesupport/lib/active_support/secure_compare_rotator.rb
new file mode 100644
index 0000000000..97110d41f7
--- /dev/null
+++ b/activesupport/lib/active_support/secure_compare_rotator.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+require "active_support/security_utils"
+require "active_support/messages/rotator"
+
+module ActiveSupport
+ # The ActiveSupport::SecureCompareRotator is a wrapper around +ActiveSupport::SecurityUtils.secure_compare+
+ # and allows you to rotate a previously defined value to a new one.
+ #
+ # It can be used as follow:
+ #
+ # rotator = ActiveSupport::SecureCompareRotator.new('new_production_value')
+ # rotator.rotate('previous_production_value')
+ # rotator.secure_compare!('previous_production_value')
+ #
+ # One real use case example would be to rotate a basic auth credentials:
+ #
+ # class MyController < ApplicationController
+ # def authenticate_request
+ # rotator = ActiveSupport::SecureComparerotator.new('new_password')
+ # rotator.rotate('old_password')
+ #
+ # authenticate_or_request_with_http_basic do |username, password|
+ # rotator.secure_compare!(password)
+ # rescue ActiveSupport::SecureCompareRotator::InvalidMatch
+ # false
+ # end
+ # end
+ # end
+ class SecureCompareRotator
+ include SecurityUtils
+ prepend Messages::Rotator
+
+ InvalidMatch = Class.new(StandardError)
+
+ def initialize(value, **_options)
+ @value = value
+ end
+
+ def secure_compare!(other_value, on_rotation: @on_rotation)
+ secure_compare(@value, other_value) ||
+ run_rotations(on_rotation) { |wrapper| wrapper.secure_compare!(other_value) } ||
+ raise(InvalidMatch)
+ end
+
+ private
+
+ def build_rotation(previous_value, _options)
+ self.class.new(previous_value)
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/string_inquirer.rb b/activesupport/lib/active_support/string_inquirer.rb
index a3af36720e..e5091e127a 100644
--- a/activesupport/lib/active_support/string_inquirer.rb
+++ b/activesupport/lib/active_support/string_inquirer.rb
@@ -18,7 +18,6 @@ module ActiveSupport
# vehicle.bike? # => false
class StringInquirer < String
private
-
def respond_to_missing?(method_name, include_private = false)
(method_name[-1] == "?") || super
end
diff --git a/activesupport/lib/active_support/testing/parallelization.rb b/activesupport/lib/active_support/testing/parallelization.rb
index e760bf5ce3..96518a4a58 100644
--- a/activesupport/lib/active_support/testing/parallelization.rb
+++ b/activesupport/lib/active_support/testing/parallelization.rb
@@ -27,6 +27,10 @@ module ActiveSupport
@queue << o
end
+ def length
+ @queue.length
+ end
+
def pop; @queue.pop; end
end
@@ -68,7 +72,11 @@ module ActiveSupport
def start
@pool = @queue_size.times.map do |worker|
+ title = "Rails test worker #{worker}"
+
fork do
+ Process.setproctitle("#{title} - (starting)")
+
DRb.stop_service
begin
@@ -81,6 +89,9 @@ module ActiveSupport
klass = job[0]
method = job[1]
reporter = job[2]
+
+ Process.setproctitle("#{title} - #{klass}##{method}")
+
result = klass.with_info_handler reporter do
Minitest.run_one_method(klass, method)
end
@@ -95,8 +106,12 @@ module ActiveSupport
end
queue.record(reporter, result)
end
+
+ Process.setproctitle("#{title} - (idle)")
end
ensure
+ Process.setproctitle("#{title} - (stopping)")
+
run_cleanup(worker)
end
end
@@ -109,6 +124,10 @@ module ActiveSupport
def shutdown
@queue_size.times { @queue << nil }
@pool.each { |pid| Process.waitpid pid }
+
+ if @queue.length > 0
+ raise "Queue not empty, but all workers have finished. This probably means that a worker crashed and #{@queue.length} tests were missed."
+ end
end
private
diff --git a/activesupport/lib/active_support/testing/stream.rb b/activesupport/lib/active_support/testing/stream.rb
index 127cfe1e12..f895a74644 100644
--- a/activesupport/lib/active_support/testing/stream.rb
+++ b/activesupport/lib/active_support/testing/stream.rb
@@ -4,7 +4,6 @@ module ActiveSupport
module Testing
module Stream #:nodoc:
private
-
def silence_stream(stream)
old_stream = stream.dup
stream.reopen(IO::NULL)
diff --git a/activesupport/lib/active_support/testing/time_helpers.rb b/activesupport/lib/active_support/testing/time_helpers.rb
index 5a3fa9346c..84bd920d86 100644
--- a/activesupport/lib/active_support/testing/time_helpers.rb
+++ b/activesupport/lib/active_support/testing/time_helpers.rb
@@ -40,7 +40,6 @@ module ActiveSupport
end
private
-
def unstub_object(stub)
singleton_class = stub.object.singleton_class
singleton_class.silence_redefinition_of_method stub.method_name
@@ -191,7 +190,6 @@ module ActiveSupport
end
private
-
def simple_stubs
@simple_stubs ||= SimpleStubs.new
end
diff --git a/activesupport/lib/active_support/xml_mini.rb b/activesupport/lib/active_support/xml_mini.rb
index 075cd4ed8b..f6ae08bb5d 100644
--- a/activesupport/lib/active_support/xml_mini.rb
+++ b/activesupport/lib/active_support/xml_mini.rb
@@ -155,7 +155,6 @@ module ActiveSupport
end
private
-
def _dasherize(key)
# $2 must be a non-greedy regex for this to work
left, middle, right = /\A(_*)(.*?)(_*)\Z/.match(key.strip)[1, 3]
diff --git a/activesupport/lib/active_support/xml_mini/jdom.rb b/activesupport/lib/active_support/xml_mini/jdom.rb
index 32fe6ade28..12ca19a76f 100644
--- a/activesupport/lib/active_support/xml_mini/jdom.rb
+++ b/activesupport/lib/active_support/xml_mini/jdom.rb
@@ -53,7 +53,6 @@ module ActiveSupport
end
private
-
# Convert an XML element and merge into the hash
#
# hash::
diff --git a/activesupport/test/cache/behaviors/cache_store_behavior.rb b/activesupport/test/cache/behaviors/cache_store_behavior.rb
index a696760bb2..e6f014e08d 100644
--- a/activesupport/test/cache/behaviors/cache_store_behavior.rb
+++ b/activesupport/test/cache/behaviors/cache_store_behavior.rb
@@ -507,7 +507,6 @@ module CacheStoreBehavior
end
private
-
def assert_compressed(value, **options)
assert_compression(true, value, **options)
end
diff --git a/activesupport/test/cache/behaviors/local_cache_behavior.rb b/activesupport/test/cache/behaviors/local_cache_behavior.rb
index baa38ba6ac..6f5d53c190 100644
--- a/activesupport/test/cache/behaviors/local_cache_behavior.rb
+++ b/activesupport/test/cache/behaviors/local_cache_behavior.rb
@@ -46,6 +46,15 @@ module LocalCacheBehavior
end
end
+ def test_local_cache_of_read_returns_a_copy_of_the_entry
+ @cache.with_local_cache do
+ @cache.write(:foo, type: "bar")
+ value = @cache.read(:foo)
+ assert_equal("bar", value.delete(:type))
+ assert_equal({ type: "bar" }, @cache.read(:foo))
+ end
+ end
+
def test_local_cache_of_read
@cache.write("foo", "bar")
@cache.with_local_cache do
diff --git a/activesupport/test/cache/cache_key_test.rb b/activesupport/test/cache/cache_key_test.rb
index c2240d03c2..f0cd991553 100644
--- a/activesupport/test/cache/cache_key_test.rb
+++ b/activesupport/test/cache/cache_key_test.rb
@@ -79,7 +79,6 @@ class CacheKeyTest < ActiveSupport::TestCase
end
private
-
def with_env(kv)
old_values = {}
kv.each { |key, value| old_values[key], ENV[key] = ENV[key], value }
diff --git a/activesupport/test/cache/stores/mem_cache_store_test.rb b/activesupport/test/cache/stores/mem_cache_store_test.rb
index 0e472f5a1a..3917d14d1c 100644
--- a/activesupport/test/cache/stores/mem_cache_store_test.rb
+++ b/activesupport/test/cache/stores/mem_cache_store_test.rb
@@ -113,7 +113,6 @@ class MemCacheStoreTest < ActiveSupport::TestCase
end
private
-
def store
[:mem_cache_store, ENV["MEMCACHE_SERVERS"] || "localhost:11211"]
end
diff --git a/activesupport/test/cache/stores/redis_cache_store_test.rb b/activesupport/test/cache/stores/redis_cache_store_test.rb
index 790534cd3c..a2177e0476 100644
--- a/activesupport/test/cache/stores/redis_cache_store_test.rb
+++ b/activesupport/test/cache/stores/redis_cache_store_test.rb
@@ -191,7 +191,6 @@ module ActiveSupport::Cache::RedisCacheStoreTests
include ConnectionPoolBehavior
private
-
def store
[:redis_cache_store]
end
@@ -238,7 +237,6 @@ module ActiveSupport::Cache::RedisCacheStoreTests
include FailureSafetyBehavior
private
-
def emulating_unavailability
old_client = Redis.send(:remove_const, :Client)
Redis.const_set(:Client, UnavailableRedisClient)
diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb
index 79098b2a7d..cc37c4fa99 100644
--- a/activesupport/test/callbacks_test.rb
+++ b/activesupport/test/callbacks_test.rb
@@ -397,7 +397,6 @@ module CallbacksTest
end
private
-
def record1
@recorder << 1
end
@@ -989,6 +988,7 @@ module CallbacksTest
define_callbacks :foo, scope: [:name]
set_callback :foo, :before, :foo, if: callback
def run; run_callbacks :foo; end
+
private
def foo; end
}
diff --git a/activesupport/test/core_ext/date_and_time_behavior.rb b/activesupport/test/core_ext/date_and_time_behavior.rb
index b77ea22701..6d31734f27 100644
--- a/activesupport/test/core_ext/date_and_time_behavior.rb
+++ b/activesupport/test/core_ext/date_and_time_behavior.rb
@@ -8,31 +8,11 @@ module DateAndTimeBehavior
assert_equal date_time_init(2005, 2, 28, 10, 10, 10), date_time_init(2005, 3, 2, 10, 10, 10).yesterday.yesterday
end
- def test_prev_day
- assert_equal date_time_init(2005, 2, 24, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day(-2)
- assert_equal date_time_init(2005, 2, 23, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day(-1)
- assert_equal date_time_init(2005, 2, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day(0)
- assert_equal date_time_init(2005, 2, 21, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day(1)
- assert_equal date_time_init(2005, 2, 20, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day(2)
- assert_equal date_time_init(2005, 2, 21, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day
- assert_equal date_time_init(2005, 2, 28, 10, 10, 10), date_time_init(2005, 3, 2, 10, 10, 10).prev_day.prev_day
- end
-
def test_tomorrow
assert_equal date_time_init(2005, 2, 23, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).tomorrow
assert_equal date_time_init(2005, 3, 2, 10, 10, 10), date_time_init(2005, 2, 28, 10, 10, 10).tomorrow.tomorrow
end
- def test_next_day
- assert_equal date_time_init(2005, 2, 20, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day(-2)
- assert_equal date_time_init(2005, 2, 21, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day(-1)
- assert_equal date_time_init(2005, 2, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day(0)
- assert_equal date_time_init(2005, 2, 23, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day(1)
- assert_equal date_time_init(2005, 2, 24, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day(2)
- assert_equal date_time_init(2005, 2, 23, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day
- assert_equal date_time_init(2005, 3, 2, 10, 10, 10), date_time_init(2005, 2, 28, 10, 10, 10).next_day.next_day
- end
-
def test_days_ago
assert_equal date_time_init(2005, 6, 4, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).days_ago(1)
assert_equal date_time_init(2005, 5, 31, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).days_ago(5)
@@ -161,16 +141,6 @@ module DateAndTimeBehavior
assert_equal date_time_init(2015, 1, 5, 15, 15, 10), date_time_init(2015, 1, 3, 15, 15, 10).next_weekday
end
- def test_next_month
- assert_equal date_time_init(2004, 12, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month(-2)
- assert_equal date_time_init(2005, 1, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month(-1)
- assert_equal date_time_init(2005, 2, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month(0)
- assert_equal date_time_init(2005, 3, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month(1)
- assert_equal date_time_init(2005, 4, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month(2)
- assert_equal date_time_init(2005, 3, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month
- assert_equal date_time_init(2005, 4, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month.next_month
- end
-
def test_next_month_on_31st
assert_equal date_time_init(2005, 9, 30, 15, 15, 10), date_time_init(2005, 8, 31, 15, 15, 10).next_month
end
@@ -179,16 +149,6 @@ module DateAndTimeBehavior
assert_equal date_time_init(2005, 11, 30, 15, 15, 10), date_time_init(2005, 8, 31, 15, 15, 10).next_quarter
end
- def test_next_year
- assert_equal date_time_init(2003, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year(-2)
- assert_equal date_time_init(2004, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year(-1)
- assert_equal date_time_init(2005, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year(0)
- assert_equal date_time_init(2006, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year(1)
- assert_equal date_time_init(2007, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year(2)
- assert_equal date_time_init(2006, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year
- assert_equal date_time_init(2007, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year.next_year
- end
-
def test_prev_week
assert_equal date_time_init(2005, 2, 21, 0, 0, 0), date_time_init(2005, 3, 1, 15, 15, 10).prev_week
assert_equal date_time_init(2005, 2, 22, 0, 0, 0), date_time_init(2005, 3, 1, 15, 15, 10).prev_week(:tuesday)
@@ -229,16 +189,6 @@ module DateAndTimeBehavior
assert_equal date_time_init(2015, 1, 2, 15, 15, 10), date_time_init(2015, 1, 4, 15, 15, 10).prev_weekday
end
- def test_prev_month
- assert_equal date_time_init(2005, 4, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month(-2)
- assert_equal date_time_init(2005, 3, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month(-1)
- assert_equal date_time_init(2005, 2, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month(0)
- assert_equal date_time_init(2005, 1, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month(1)
- assert_equal date_time_init(2004, 12, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month(2)
- assert_equal date_time_init(2005, 1, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month
- assert_equal date_time_init(2004, 12, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month.prev_month
- end
-
def test_prev_month_on_31st
assert_equal date_time_init(2004, 2, 29, 10, 10, 10), date_time_init(2004, 3, 31, 10, 10, 10).prev_month
end
@@ -247,16 +197,6 @@ module DateAndTimeBehavior
assert_equal date_time_init(2004, 2, 29, 10, 10, 10), date_time_init(2004, 5, 31, 10, 10, 10).prev_quarter
end
- def test_prev_year
- assert_equal date_time_init(2007, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year(-2)
- assert_equal date_time_init(2006, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year(-1)
- assert_equal date_time_init(2005, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year(0)
- assert_equal date_time_init(2004, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year(1)
- assert_equal date_time_init(2003, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year(2)
- assert_equal date_time_init(2004, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year
- assert_equal date_time_init(2003, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year.prev_year
- end
-
def test_last_month_on_31st
assert_equal date_time_init(2004, 2, 29, 0, 0, 0), date_time_init(2004, 3, 31, 0, 0, 0).last_month
end
diff --git a/activesupport/test/core_ext/date_ext_test.rb b/activesupport/test/core_ext/date_ext_test.rb
index b8652884ce..7060dd3c56 100644
--- a/activesupport/test/core_ext/date_ext_test.rb
+++ b/activesupport/test/core_ext/date_ext_test.rb
@@ -112,14 +112,6 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
assert_equal Date.new(2005, 4, 30), Date.new(2005, 4, 20).end_of_month
end
- def test_prev_year_in_leap_years
- assert_equal Date.new(1999, 2, 28), Date.new(2000, 2, 29).prev_year
- end
-
- def test_prev_year_in_calendar_reform
- assert_equal Date.new(1582, 10, 4), Date.new(1583, 10, 14).prev_year
- end
-
def test_last_year_in_leap_years
assert_equal Date.new(1999, 2, 28), Date.new(2000, 2, 29).last_year
end
@@ -128,14 +120,6 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
assert_equal Date.new(1582, 10, 4), Date.new(1583, 10, 14).last_year
end
- def test_next_year_in_leap_years
- assert_equal Date.new(2001, 2, 28), Date.new(2000, 2, 29).next_year
- end
-
- def test_next_year_in_calendar_reform
- assert_equal Date.new(1582, 10, 4), Date.new(1581, 10, 10).next_year
- end
-
def test_advance
assert_equal Date.new(2006, 2, 28), Date.new(2005, 2, 28).advance(years: 1)
assert_equal Date.new(2005, 6, 28), Date.new(2005, 2, 28).advance(months: 4)
diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb
index 381b5a1f32..a9bf4b82f4 100644
--- a/activesupport/test/core_ext/enumerable_test.rb
+++ b/activesupport/test/core_ext/enumerable_test.rb
@@ -242,4 +242,28 @@ class EnumerableTests < ActiveSupport::TestCase
])
assert_equal [[5, 99], [15, 0], [10, 50]], payments.pluck(:dollars, :cents)
end
+
+ def test_compact_blank
+ values = GenericEnumerable.new([1, "", nil, 2, " ", [], {}, false, true])
+
+ assert_equal [1, 2, true], values.compact_blank
+ end
+
+ def test_array_compact_blank!
+ values = [1, "", nil, 2, " ", [], {}, false, true]
+ values.compact_blank!
+
+ assert_equal [1, 2, true], values
+ end
+
+ def test_hash_compact_blank
+ values = { a: "", b: 1, c: nil, d: [], e: false, f: true }
+ assert_equal({ b: 1, f: true }, values.compact_blank)
+ end
+
+ def test_hash_compact_blank!
+ values = { a: "", b: 1, c: nil, d: [], e: false, f: true }
+ values.compact_blank!
+ assert_equal({ b: 1, f: true }, values)
+ end
end
diff --git a/activesupport/test/core_ext/module_test.rb b/activesupport/test/core_ext/module_test.rb
index 04692f1484..dd36a9373a 100644
--- a/activesupport/test/core_ext/module_test.rb
+++ b/activesupport/test/core_ext/module_test.rb
@@ -25,7 +25,6 @@ Someone = Struct.new(:name, :place) do
delegate :bar, to: :place, allow_nil: true
private
-
def private_name
"Private"
end
@@ -92,6 +91,16 @@ DecoratedTester = Struct.new(:client) do
delegate_missing_to :client
end
+class DecoratedMissingAllowNil
+ delegate_missing_to :case, allow_nil: true
+
+ attr_reader :case
+
+ def initialize(kase)
+ @case = kase
+ end
+end
+
class DecoratedReserved
delegate_missing_to :case
@@ -102,6 +111,24 @@ class DecoratedReserved
end
end
+class Maze
+ attr_accessor :cavern, :passages
+end
+
+class Cavern
+ delegate_missing_to :target
+
+ attr_reader :maze
+
+ def initialize(maze)
+ @maze = maze
+ end
+
+ def target
+ @maze.passages = :twisty
+ end
+end
+
class Block
def hello?
true
@@ -382,6 +409,10 @@ class ModuleTest < ActiveSupport::TestCase
assert_equal "name delegated to client, but client is nil", e.message
end
+ def test_delegate_missing_to_returns_nil_if_allow_nil_and_nil_target
+ assert_nil DecoratedMissingAllowNil.new(nil).name
+ end
+
def test_delegate_missing_to_affects_respond_to
assert_respond_to DecoratedTester.new(@david), :name
assert_not_respond_to DecoratedTester.new(@david), :private_name
@@ -398,6 +429,17 @@ class ModuleTest < ActiveSupport::TestCase
assert_respond_to DecoratedTester.new(@david), :extra_missing
end
+ def test_delegate_missing_to_does_not_interfere_with_marshallization
+ maze = Maze.new
+ maze.cavern = Cavern.new(maze)
+
+ array = [maze, nil]
+ serialized_array = Marshal.dump(array)
+ deserialized_array = Marshal.load(serialized_array)
+
+ assert_nil deserialized_array[1]
+ end
+
def test_delegate_with_case
event = Event.new(Tester.new)
assert_equal 1, event.foo
diff --git a/activesupport/test/core_ext/object/duplicable_test.rb b/activesupport/test/core_ext/object/duplicable_test.rb
index 5203434ae6..a577c30c40 100644
--- a/activesupport/test/core_ext/object/duplicable_test.rb
+++ b/activesupport/test/core_ext/object/duplicable_test.rb
@@ -6,13 +6,8 @@ require "active_support/core_ext/object/duplicable"
require "active_support/core_ext/numeric/time"
class DuplicableTest < ActiveSupport::TestCase
- if RUBY_VERSION >= "2.5.0"
- RAISE_DUP = [method(:puts)]
- ALLOW_DUP = ["1", "symbol_from_string".to_sym, Object.new, /foo/, [], {}, Time.now, Class.new, Module.new, BigDecimal("4.56"), nil, false, true, 1, 2.3, Complex(1), Rational(1)]
- else
- RAISE_DUP = [method(:puts), Complex(1), Rational(1)]
- ALLOW_DUP = ["1", "symbol_from_string".to_sym, Object.new, /foo/, [], {}, Time.now, Class.new, Module.new, BigDecimal("4.56"), nil, false, true, 1, 2.3]
- end
+ RAISE_DUP = [method(:puts), method(:puts).unbind]
+ ALLOW_DUP = ["1", "symbol_from_string".to_sym, Object.new, /foo/, [], {}, Time.now, Class.new, Module.new, BigDecimal("4.56"), nil, false, true, 1, 2.3, Complex(1), Rational(1)]
def test_duplicable
rubinius_skip "* Method#dup is allowed at the moment on Rubinius\n" \
diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb
index 590b81b770..41ab98e721 100644
--- a/activesupport/test/core_ext/time_ext_test.rb
+++ b/activesupport/test/core_ext/time_ext_test.rb
@@ -949,6 +949,66 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal "invalid date", exception.message
end
+
+ def test_prev_day
+ assert_equal date_time_init(2005, 2, 24, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day(-2)
+ assert_equal date_time_init(2005, 2, 23, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day(-1)
+ assert_equal date_time_init(2005, 2, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day(0)
+ assert_equal date_time_init(2005, 2, 21, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day(1)
+ assert_equal date_time_init(2005, 2, 20, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day(2)
+ assert_equal date_time_init(2005, 2, 21, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day
+ assert_equal date_time_init(2005, 2, 28, 10, 10, 10), date_time_init(2005, 3, 2, 10, 10, 10).prev_day.prev_day
+ end
+
+ def test_next_day
+ assert_equal date_time_init(2005, 2, 20, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day(-2)
+ assert_equal date_time_init(2005, 2, 21, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day(-1)
+ assert_equal date_time_init(2005, 2, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day(0)
+ assert_equal date_time_init(2005, 2, 23, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day(1)
+ assert_equal date_time_init(2005, 2, 24, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day(2)
+ assert_equal date_time_init(2005, 2, 23, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day
+ assert_equal date_time_init(2005, 3, 2, 10, 10, 10), date_time_init(2005, 2, 28, 10, 10, 10).next_day.next_day
+ end
+
+ def test_prev_month
+ assert_equal date_time_init(2005, 4, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month(-2)
+ assert_equal date_time_init(2005, 3, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month(-1)
+ assert_equal date_time_init(2005, 2, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month(0)
+ assert_equal date_time_init(2005, 1, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month(1)
+ assert_equal date_time_init(2004, 12, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month(2)
+ assert_equal date_time_init(2005, 1, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month
+ assert_equal date_time_init(2004, 12, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month.prev_month
+ end
+
+ def test_next_month
+ assert_equal date_time_init(2004, 12, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month(-2)
+ assert_equal date_time_init(2005, 1, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month(-1)
+ assert_equal date_time_init(2005, 2, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month(0)
+ assert_equal date_time_init(2005, 3, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month(1)
+ assert_equal date_time_init(2005, 4, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month(2)
+ assert_equal date_time_init(2005, 3, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month
+ assert_equal date_time_init(2005, 4, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month.next_month
+ end
+
+ def test_prev_year
+ assert_equal date_time_init(2007, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year(-2)
+ assert_equal date_time_init(2006, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year(-1)
+ assert_equal date_time_init(2005, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year(0)
+ assert_equal date_time_init(2004, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year(1)
+ assert_equal date_time_init(2003, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year(2)
+ assert_equal date_time_init(2004, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year
+ assert_equal date_time_init(2003, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year.prev_year
+ end
+
+ def test_next_year
+ assert_equal date_time_init(2003, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year(-2)
+ assert_equal date_time_init(2004, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year(-1)
+ assert_equal date_time_init(2005, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year(0)
+ assert_equal date_time_init(2006, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year(1)
+ assert_equal date_time_init(2007, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year(2)
+ assert_equal date_time_init(2006, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year
+ assert_equal date_time_init(2007, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year.next_year
+ end
end
class TimeExtMarshalingTest < ActiveSupport::TestCase
diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb
index d4e709137e..6bad69f7f2 100644
--- a/activesupport/test/dependencies_test.rb
+++ b/activesupport/test/dependencies_test.rb
@@ -481,17 +481,14 @@ class DependenciesTest < ActiveSupport::TestCase
end
end
- # This raises only on 2.5.. (warns on ..2.4)
- if RUBY_VERSION > "2.5"
- def test_access_thru_and_upwards_fails
- with_autoloading_fixtures do
- assert_not defined?(ModuleFolder)
- assert_raise(NameError) { ModuleFolder::Object }
- assert_raise(NameError) { ModuleFolder::NestedClass::Object }
- end
- ensure
- remove_constants(:ModuleFolder)
+ def test_access_thru_and_upwards_fails
+ with_autoloading_fixtures do
+ assert_not defined?(ModuleFolder)
+ assert_raise(NameError) { ModuleFolder::Object }
+ assert_raise(NameError) { ModuleFolder::NestedClass::Object }
end
+ ensure
+ remove_constants(:ModuleFolder)
end
def test_non_existing_const_raises_name_error_with_fully_qualified_name
@@ -595,6 +592,13 @@ class DependenciesTest < ActiveSupport::TestCase
nil_name = Module.new
def nil_name.name() nil end
assert_not ActiveSupport::Dependencies.autoloaded?(nil_name)
+
+ invalid_constant_name = Module.new do
+ def self.name
+ "primary::SchemaMigration"
+ end
+ end
+ assert_not ActiveSupport::Dependencies.autoloaded?(invalid_constant_name)
end
ensure
remove_constants(:ModuleFolder)
diff --git a/activesupport/test/deprecation/method_wrappers_test.rb b/activesupport/test/deprecation/method_wrappers_test.rb
index 0aa3233aab..8c40534452 100644
--- a/activesupport/test/deprecation/method_wrappers_test.rb
+++ b/activesupport/test/deprecation/method_wrappers_test.rb
@@ -10,12 +10,10 @@ class MethodWrappersTest < ActiveSupport::TestCase
alias_method :old_method, :new_method
protected
-
def new_protected_method; "abc" end
alias_method :old_protected_method, :new_protected_method
private
-
def new_private_method; "abc" end
alias_method :old_private_method, :new_private_method
end
diff --git a/activesupport/test/deprecation_test.rb b/activesupport/test/deprecation_test.rb
index f25c704586..ae2f4a6e58 100644
--- a/activesupport/test/deprecation_test.rb
+++ b/activesupport/test/deprecation_test.rb
@@ -38,6 +38,11 @@ class Deprecatee
C = 1
end
A = ActiveSupport::Deprecation::DeprecatedConstantProxy.new("Deprecatee::A", "Deprecatee::B::C")
+
+ module New
+ class Descendant; end
+ end
+ Old = ActiveSupport::Deprecation::DeprecatedConstantProxy.new("Deprecatee::Old", "Deprecatee::New")
end
class DeprecateeWithAccessor
@@ -210,6 +215,18 @@ class DeprecationTest < ActiveSupport::TestCase
assert_not_deprecated { assert_equal Deprecatee::B::C.class, Deprecatee::A.class }
end
+ def test_deprecated_constant_descendant
+ assert_not_deprecated { Deprecatee::New::Descendant }
+
+ assert_deprecated("Deprecatee::Old") do
+ assert_equal Deprecatee::Old::Descendant, Deprecatee::New::Descendant
+ end
+
+ assert_raises(NameError) do
+ assert_deprecated("Deprecatee::Old") { Deprecatee::Old::NON_EXISTENCE }
+ end
+ end
+
def test_deprecated_constant_accessor
assert_not_deprecated { DeprecateeWithAccessor::B::C }
assert_deprecated("DeprecateeWithAccessor::A") { assert_equal DeprecateeWithAccessor::B::C, DeprecateeWithAccessor::A }
diff --git a/activesupport/test/descendants_tracker_test_cases.rb b/activesupport/test/descendants_tracker_test_cases.rb
index f8752688d2..7d39783826 100644
--- a/activesupport/test/descendants_tracker_test_cases.rb
+++ b/activesupport/test/descendants_tracker_test_cases.rb
@@ -52,7 +52,6 @@ module DescendantsTrackerTestCases
end
private
-
def assert_equal_sets(expected, actual)
assert_equal Set.new(expected), Set.new(actual)
end
diff --git a/activesupport/test/evented_file_update_checker_test.rb b/activesupport/test/evented_file_update_checker_test.rb
index b2d5eb94c2..4d5a9bed7a 100644
--- a/activesupport/test/evented_file_update_checker_test.rb
+++ b/activesupport/test/evented_file_update_checker_test.rb
@@ -77,32 +77,48 @@ class EventedFileUpdateCheckerTest < ActiveSupport::TestCase
Process.wait(pid)
end
+ test "should detect changes through symlink" do
+ actual_dir = File.join(tmpdir, "actual")
+ linked_dir = File.join(tmpdir, "linked")
+
+ Dir.mkdir(actual_dir)
+ FileUtils.ln_s(actual_dir, linked_dir)
+
+ checker = new_checker([], linked_dir => ".rb") { }
+
+ assert_not_predicate checker, :updated?
+
+ FileUtils.touch(File.join(actual_dir, "a.rb"))
+ wait
+
+ assert_predicate checker, :updated?
+ assert checker.execute_if_updated
+ end
+
test "updated should become true when nonexistent directory is added later" do
- Dir.mktmpdir do |dir|
- watched_dir = File.join(dir, "app")
- unwatched_dir = File.join(dir, "node_modules")
- not_exist_watched_dir = File.join(dir, "test")
+ watched_dir = File.join(tmpdir, "app")
+ unwatched_dir = File.join(tmpdir, "node_modules")
+ not_exist_watched_dir = File.join(tmpdir, "test")
- Dir.mkdir(watched_dir)
- Dir.mkdir(unwatched_dir)
+ Dir.mkdir(watched_dir)
+ Dir.mkdir(unwatched_dir)
- checker = new_checker([], watched_dir => ".rb", not_exist_watched_dir => ".rb") { }
+ checker = new_checker([], watched_dir => ".rb", not_exist_watched_dir => ".rb") { }
- FileUtils.touch(File.join(watched_dir, "a.rb"))
- wait
- assert_predicate checker, :updated?
- assert checker.execute_if_updated
+ FileUtils.touch(File.join(watched_dir, "a.rb"))
+ wait
+ assert_predicate checker, :updated?
+ assert checker.execute_if_updated
- Dir.mkdir(not_exist_watched_dir)
- wait
- assert_predicate checker, :updated?
- assert checker.execute_if_updated
+ Dir.mkdir(not_exist_watched_dir)
+ wait
+ assert_predicate checker, :updated?
+ assert checker.execute_if_updated
- FileUtils.touch(File.join(unwatched_dir, "a.rb"))
- wait
- assert_not_predicate checker, :updated?
- assert_not checker.execute_if_updated
- end
+ FileUtils.touch(File.join(unwatched_dir, "a.rb"))
+ wait
+ assert_not_predicate checker, :updated?
+ assert_not checker.execute_if_updated
end
end
@@ -156,14 +172,6 @@ class EventedFileUpdateCheckerPathHelperTest < ActiveSupport::TestCase
assert_nil @ph.longest_common_subpath([])
end
- test "#existing_parent returns the most specific existing ascendant" do
- wd = Pathname.getwd
-
- assert_equal wd, @ph.existing_parent(wd)
- assert_equal wd, @ph.existing_parent(wd.join("non-existing/directory"))
- assert_equal pn("/"), @ph.existing_parent(pn("/non-existing/directory"))
- end
-
test "#filter_out_descendants returns the same collection if there are no descendants (empty)" do
assert_equal [], @ph.filter_out_descendants([])
end
diff --git a/activesupport/test/json/decoding_test.rb b/activesupport/test/json/decoding_test.rb
index 8d9587f248..2e8ea01aca 100644
--- a/activesupport/test/json/decoding_test.rb
+++ b/activesupport/test/json/decoding_test.rb
@@ -113,7 +113,6 @@ class TestJSONDecoding < ActiveSupport::TestCase
end
private
-
def with_parse_json_times(value)
old_value = ActiveSupport.parse_json_times
ActiveSupport.parse_json_times = value
diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb
index 7589ffd0ea..c4e0b71f26 100644
--- a/activesupport/test/json/encoding_test.rb
+++ b/activesupport/test/json/encoding_test.rb
@@ -466,7 +466,6 @@ EXPECTED
end
private
-
def object_keys(json_object)
json_object[1..-2].scan(/([^{}:,\s]+):/).flatten.sort
end
diff --git a/activesupport/test/lazy_load_hooks_test.rb b/activesupport/test/lazy_load_hooks_test.rb
index 50a703e49f..5e9a21f047 100644
--- a/activesupport/test/lazy_load_hooks_test.rb
+++ b/activesupport/test/lazy_load_hooks_test.rb
@@ -175,7 +175,6 @@ class LazyLoadHooksTest < ActiveSupport::TestCase
end
private
-
def incr_amt
5
end
diff --git a/activesupport/test/logger_test.rb b/activesupport/test/logger_test.rb
index 160e1156b6..6f7a186022 100644
--- a/activesupport/test/logger_test.rb
+++ b/activesupport/test/logger_test.rb
@@ -258,6 +258,50 @@ class LoggerTest < ActiveSupport::TestCase
assert_level(Logger::INFO)
end
+ def test_logger_level_main_fiber_safety
+ @logger.level = Logger::INFO
+ assert_level(Logger::INFO)
+
+ fiber = Fiber.new do
+ assert_level(Logger::INFO)
+ end
+
+ @logger.silence(Logger::ERROR) do
+ assert_level(Logger::ERROR)
+ fiber.resume
+ end
+ end
+
+ def test_logger_level_local_fiber_safety
+ @logger.level = Logger::INFO
+ assert_level(Logger::INFO)
+
+ another_fiber = Fiber.new do
+ @logger.silence(Logger::ERROR) do
+ assert_level(Logger::ERROR)
+ @logger.silence(Logger::DEBUG) do
+ assert_level(Logger::DEBUG)
+ end
+ end
+
+ assert_level(Logger::INFO)
+ end
+
+ Fiber.new do
+ @logger.silence(Logger::ERROR) do
+ assert_level(Logger::ERROR)
+ @logger.silence(Logger::DEBUG) do
+ another_fiber.resume
+ assert_level(Logger::DEBUG)
+ end
+ end
+
+ assert_level(Logger::INFO)
+ end.resume
+
+ assert_level(Logger::INFO)
+ end
+
private
def level_name(level)
::Logger::Severity.constants.find do |severity|
diff --git a/activesupport/test/message_encryptor_test.rb b/activesupport/test/message_encryptor_test.rb
index 9edf07f762..097aa8b5f8 100644
--- a/activesupport/test/message_encryptor_test.rb
+++ b/activesupport/test/message_encryptor_test.rb
@@ -171,6 +171,34 @@ class MessageEncryptorTest < ActiveSupport::TestCase
assert rotated
end
+ def test_on_rotation_can_be_passed_at_the_constructor_level
+ older_message = ActiveSupport::MessageEncryptor.new(secrets[:older], "older sign").encrypt_and_sign(encoded: "message")
+
+ rotated = false
+ encryptor = ActiveSupport::MessageEncryptor.new(@secret, on_rotation: proc { rotated = true })
+ encryptor.rotate secrets[:older], "older sign"
+
+ assert_changes(:rotated, from: false, to: true) do
+ message = encryptor.decrypt_and_verify(older_message)
+
+ assert_equal({ encoded: "message" }, message)
+ end
+ end
+
+ def test_on_rotation_option_takes_precedence_over_the_one_given_in_constructor
+ older_message = ActiveSupport::MessageEncryptor.new(secrets[:older], "older sign").encrypt_and_sign(encoded: "message")
+
+ rotated = false
+ encryptor = ActiveSupport::MessageEncryptor.new(@secret, on_rotation: proc { rotated = true })
+ encryptor.rotate secrets[:older], "older sign"
+
+ assert_changes(:rotated, from: false, to: "Yes") do
+ message = encryptor.decrypt_and_verify(older_message, on_rotation: proc { rotated = "Yes" })
+
+ assert_equal({ encoded: "message" }, message)
+ end
+ end
+
def test_with_rotated_metadata
old_message = ActiveSupport::MessageEncryptor.new(secrets[:old], cipher: "aes-256-gcm").
encrypt_and_sign("metadata", purpose: :rotation)
diff --git a/activesupport/test/multibyte_chars_test.rb b/activesupport/test/multibyte_chars_test.rb
index 5f4e3f3fd3..e0e0d9afc0 100644
--- a/activesupport/test/multibyte_chars_test.rb
+++ b/activesupport/test/multibyte_chars_test.rb
@@ -783,7 +783,6 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase
end
private
-
def string_from_classes(classes)
# Characters from the character classes as described in UAX #29
character_from_class = {
diff --git a/activesupport/test/notifications_test.rb b/activesupport/test/notifications_test.rb
index d3c660a014..08277e5436 100644
--- a/activesupport/test/notifications_test.rb
+++ b/activesupport/test/notifications_test.rb
@@ -20,7 +20,6 @@ module Notifications
end
private
-
def event(*args)
ActiveSupport::Notifications::Event.new(*args)
end
@@ -42,6 +41,27 @@ module Notifications
assert_operator event.duration, :>, 0
end
+ def test_subscribe_to_events_where_payload_is_changed_during_instrumentation
+ @notifier.subscribe do |event|
+ assert_equal "success!", event.payload[:my_key]
+ end
+
+ ActiveSupport::Notifications.instrument("foo") do |payload|
+ payload[:my_key] = "success!"
+ end
+ end
+
+ def test_subscribe_to_events_can_handle_nested_hashes_in_the_paylaod
+ @notifier.subscribe do |event|
+ assert_equal "success!", event.payload[:some_key][:key_one]
+ assert_equal "great_success!", event.payload[:some_key][:key_two]
+ end
+
+ ActiveSupport::Notifications.instrument("foo", some_key: { key_one: "success!" }) do |payload|
+ payload[:some_key][:key_two] = "great_success!"
+ end
+ end
+
def test_subscribe_via_top_level_api
old_notifier = ActiveSupport::Notifications.notifier
ActiveSupport::Notifications.notifier = ActiveSupport::Notifications::Fanout.new
@@ -62,6 +82,38 @@ module Notifications
end
end
+ class TimedAndMonotonicTimedSubscriberTest < TestCase
+ def test_subscribe
+ event_name = "foo"
+ class_of_started = nil
+ class_of_finished = nil
+
+ ActiveSupport::Notifications.subscribe(event_name) do |name, started, finished, unique_id, data|
+ class_of_started = started.class
+ class_of_finished = finished.class
+ end
+
+ ActiveSupport::Notifications.instrument(event_name)
+
+ assert_equal [Time, Time], [class_of_started, class_of_finished]
+ end
+
+ def test_monotonic_subscribe
+ event_name = "foo"
+ class_of_started = nil
+ class_of_finished = nil
+
+ ActiveSupport::Notifications.monotonic_subscribe(event_name) do |name, started, finished, unique_id, data|
+ class_of_started = started.class
+ class_of_finished = finished.class
+ end
+
+ ActiveSupport::Notifications.instrument(event_name)
+
+ assert_equal [Float, Float], [class_of_started, class_of_finished]
+ end
+ end
+
class SubscribedTest < TestCase
def test_subscribed
name = "foo"
@@ -81,6 +133,24 @@ module Notifications
assert_equal expected, events
end
+ def test_subscribed_all_messages
+ name = "foo"
+ name2 = name * 2
+ expected = [name, name2, name]
+
+ events = []
+ callback = lambda { |*_| events << _.first }
+ ActiveSupport::Notifications.subscribed(callback) do
+ ActiveSupport::Notifications.instrument(name)
+ ActiveSupport::Notifications.instrument(name2)
+ ActiveSupport::Notifications.instrument(name)
+ end
+ assert_equal expected, events
+
+ ActiveSupport::Notifications.instrument(name)
+ assert_equal expected, events
+ end
+
def test_subscribing_to_instrumentation_while_inside_it
# the repro requires that there are no evented subscribers for the "foo" event,
# so we have to duplicate some of the setup code
@@ -95,6 +165,42 @@ module Notifications
ensure
ActiveSupport::Notifications.notifier = old_notifier
end
+
+ def test_timed_subscribed
+ event_name = "foo"
+ class_of_started = nil
+ class_of_finished = nil
+ callback = lambda do |name, started, finished, unique_id, data|
+ class_of_started = started.class
+ class_of_finished = finished.class
+ end
+
+ ActiveSupport::Notifications.subscribed(callback, event_name) do
+ ActiveSupport::Notifications.instrument(event_name)
+ end
+
+ ActiveSupport::Notifications.instrument(event_name)
+
+ assert_equal [Time, Time], [class_of_started, class_of_finished]
+ end
+
+ def test_monotonic_timed_subscribed
+ event_name = "foo"
+ class_of_started = nil
+ class_of_finished = nil
+ callback = lambda do |name, started, finished, unique_id, data|
+ class_of_started = started.class
+ class_of_finished = finished.class
+ end
+
+ ActiveSupport::Notifications.subscribed(callback, event_name, monotonic: true) do
+ ActiveSupport::Notifications.instrument(event_name)
+ end
+
+ ActiveSupport::Notifications.instrument(event_name)
+
+ assert_equal [Float, Float], [class_of_started, class_of_finished]
+ end
end
class UnsubscribeTest < TestCase
@@ -317,7 +423,6 @@ module Notifications
assert_equal 0, event.cpu_time
end
-
def test_events_consumes_information_given_as_payload
event = event(:foo, Concurrent.monotonic_time, Concurrent.monotonic_time + 1, random_id, payload: :bar)
assert_equal Hash[payload: :bar], event.payload
diff --git a/activesupport/test/parameter_filter_test.rb b/activesupport/test/parameter_filter_test.rb
index d2dc71061d..e680a22479 100644
--- a/activesupport/test/parameter_filter_test.rb
+++ b/activesupport/test/parameter_filter_test.rb
@@ -28,10 +28,17 @@ class ParameterFilterTest < ActiveSupport::TestCase
value.replace("world!") if original_params["barg"]["blah"] == "bar" && key == "hello"
}
+ filter_words << lambda { |key, value|
+ value.upcase! if key == "array_elements"
+ }
+
parameter_filter = ActiveSupport::ParameterFilter.new(filter_words)
before_filter["barg"] = { :bargain => "gain", "blah" => "bar", "bar" => { "bargain" => { "blah" => "foo", "hello" => "world" } } }
after_filter["barg"] = { :bargain => "niag", "blah" => "[FILTERED]", "bar" => { "bargain" => { "blah" => "[FILTERED]", "hello" => "world!" } } }
+ before_filter["array_elements"] = %w(element1 element2)
+ after_filter["array_elements"] = %w(ELEMENT1 ELEMENT2)
+
assert_equal after_filter, parameter_filter.filter(before_filter)
end
end
diff --git a/activesupport/test/secure_compare_rotator_test.rb b/activesupport/test/secure_compare_rotator_test.rb
new file mode 100644
index 0000000000..d80faea128
--- /dev/null
+++ b/activesupport/test/secure_compare_rotator_test.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+require "abstract_unit"
+require "active_support/secure_compare_rotator"
+
+class SecureCompareRotatorTest < ActiveSupport::TestCase
+ test "#secure_compare! works correctly after rotation" do
+ wrapper = ActiveSupport::SecureCompareRotator.new("old_secret")
+ wrapper.rotate("new_secret")
+
+ assert_equal(true, wrapper.secure_compare!("new_secret"))
+ end
+
+ test "#secure_compare! works correctly after multiple rotation" do
+ wrapper = ActiveSupport::SecureCompareRotator.new("old_secret")
+ wrapper.rotate("new_secret")
+ wrapper.rotate("another_secret")
+ wrapper.rotate("and_another_one")
+
+ assert_equal(true, wrapper.secure_compare!("and_another_one"))
+ end
+
+ test "#secure_compare! fails correctly when credential is not part of the rotation" do
+ wrapper = ActiveSupport::SecureCompareRotator.new("old_secret")
+ wrapper.rotate("new_secret")
+
+ assert_raises(ActiveSupport::SecureCompareRotator::InvalidMatch) do
+ wrapper.secure_compare!("different_secret")
+ end
+ end
+
+ test "#secure_compare! calls the on_rotation proc" do
+ wrapper = ActiveSupport::SecureCompareRotator.new("old_secret")
+ wrapper.rotate("new_secret")
+ wrapper.rotate("another_secret")
+ wrapper.rotate("and_another_one")
+
+ @witness = nil
+
+ assert_changes(:@witness, from: nil, to: true) do
+ assert_equal(true, wrapper.secure_compare!("and_another_one", on_rotation: -> { @witness = true }))
+ end
+ end
+
+ test "#secure_compare! calls the on_rotation proc that given in constructor" do
+ @witness = nil
+
+ wrapper = ActiveSupport::SecureCompareRotator.new("old_secret", on_rotation: -> { @witness = true })
+ wrapper.rotate("new_secret")
+ wrapper.rotate("another_secret")
+ wrapper.rotate("and_another_one")
+
+ assert_changes(:@witness, from: nil, to: true) do
+ assert_equal(true, wrapper.secure_compare!("and_another_one"))
+ end
+ end
+end
diff --git a/activesupport/test/share_lock_test.rb b/activesupport/test/share_lock_test.rb
index a40c813fe3..68e78ccc16 100644
--- a/activesupport/test/share_lock_test.rb
+++ b/activesupport/test/share_lock_test.rb
@@ -488,12 +488,10 @@ class ShareLockTest < ActiveSupport::TestCase
end
private
-
module CustomAssertions
SUFFICIENT_TIMEOUT = 0.2
private
-
def assert_threads_stuck_but_releasable_by_latch(threads, latch)
assert_threads_stuck threads
latch.count_down
diff --git a/activesupport/test/subscriber_test.rb b/activesupport/test/subscriber_test.rb
index bc8d8f1c13..829fba6057 100644
--- a/activesupport/test/subscriber_test.rb
+++ b/activesupport/test/subscriber_test.rb
@@ -17,7 +17,6 @@ class TestSubscriber < ActiveSupport::Subscriber
end
private
-
def private_party(event)
events << event
end
diff --git a/activesupport/test/test_case_test.rb b/activesupport/test/test_case_test.rb
index 56cd2665e0..dd75548e9c 100644
--- a/activesupport/test/test_case_test.rb
+++ b/activesupport/test/test_case_test.rb
@@ -315,7 +315,6 @@ class SetupAndTeardownTest < ActiveSupport::TestCase
end
private
-
def reset_callback_record
@called_back = []
end
diff --git a/guides/assets/images/getting_started/unknown_action_create_for_articles.png b/guides/assets/images/getting_started/unknown_action_create_for_articles.png
index ec4758e085..e75b9780cc 100644
--- a/guides/assets/images/getting_started/unknown_action_create_for_articles.png
+++ b/guides/assets/images/getting_started/unknown_action_create_for_articles.png
Binary files differ
diff --git a/guides/rails_guides/generator.rb b/guides/rails_guides/generator.rb
index 7d4a15962c..2b2ccfa906 100644
--- a/guides/rails_guides/generator.rb
+++ b/guides/rails_guides/generator.rb
@@ -43,7 +43,6 @@ module RailsGuides
end
private
-
def register_kindle_mime_types
Mime::Type.register_alias("application/xml", :opf, %w(opf))
Mime::Type.register_alias("application/xml", :ncx, %w(ncx))
diff --git a/guides/rails_guides/indexer.rb b/guides/rails_guides/indexer.rb
index c707464cdf..576ec85b27 100644
--- a/guides/rails_guides/indexer.rb
+++ b/guides/rails_guides/indexer.rb
@@ -18,7 +18,6 @@ module RailsGuides
end
private
-
def process(string, current_level = 3, counters = [1])
s = StringScanner.new(string)
diff --git a/guides/rails_guides/markdown.rb b/guides/rails_guides/markdown.rb
index 018f49ffd0..d926d233bb 100644
--- a/guides/rails_guides/markdown.rb
+++ b/guides/rails_guides/markdown.rb
@@ -30,7 +30,6 @@ module RailsGuides
end
private
-
def dom_id(nodes)
dom_id = dom_id_text(nodes.last.text)
diff --git a/guides/rails_guides/markdown/renderer.rb b/guides/rails_guides/markdown/renderer.rb
index 7f14c28bbc..4877e806fd 100644
--- a/guides/rails_guides/markdown/renderer.rb
+++ b/guides/rails_guides/markdown/renderer.rb
@@ -53,7 +53,6 @@ HTML
end
private
-
def convert_footnotes(text)
text.gsub(/\[<sup>(\d+)\]<\/sup>/i) do
%(<sup class="footnote" id="footnote-#{$1}-ref">) +
diff --git a/guides/source/2_3_release_notes.md b/guides/source/2_3_release_notes.md
index ee9a499953..b46d5ee4db 100644
--- a/guides/source/2_3_release_notes.md
+++ b/guides/source/2_3_release_notes.md
@@ -415,7 +415,7 @@ select_datetime(DateTime.now, :prompt =>
### AssetTag Timestamp Caching
-You're likely familiar with Rails' practice of adding timestamps to static asset paths as a "cache buster." This helps ensure that stale copies of things like images and stylesheets don't get served out of the user's browser cache when you change them on the server. You can now modify this behavior with the `cache_asset_timestamps` configuration option for Action View. If you enable the cache, then Rails will calculate the timestamp once when it first serves an asset, and save that value. This means fewer (expensive) file system calls to serve static assets - but it also means that you can't modify any of the assets while the server is running and expect the changes to get picked up by clients.
+You're likely familiar with Rails' practice of adding timestamps to static asset paths as a "cache buster". This helps ensure that stale copies of things like images and stylesheets don't get served out of the user's browser cache when you change them on the server. You can now modify this behavior with the `cache_asset_timestamps` configuration option for Action View. If you enable the cache, then Rails will calculate the timestamp once when it first serves an asset, and save that value. This means fewer (expensive) file system calls to serve static assets - but it also means that you can't modify any of the assets while the server is running and expect the changes to get picked up by clients.
### Asset Hosts as Objects
diff --git a/guides/source/5_1_release_notes.md b/guides/source/5_1_release_notes.md
index e885b1e42e..f870c4c47c 100644
--- a/guides/source/5_1_release_notes.md
+++ b/guides/source/5_1_release_notes.md
@@ -41,8 +41,8 @@ Major Features
[Pull Request](https://github.com/rails/rails/pull/26836)
Rails 5.1 allows managing JavaScript dependencies
-from NPM via Yarn. This will make it easy to use libraries like React, VueJS
-or any other library from NPM world. The Yarn support is integrated with
+from npm via Yarn. This will make it easy to use libraries like React, VueJS
+or any other library from npm world. The Yarn support is integrated with
the asset pipeline so that all dependencies will work seamlessly with the
Rails 5.1 app.
diff --git a/guides/source/5_2_release_notes.md b/guides/source/5_2_release_notes.md
index ac247bc3f9..7aac07dbbe 100644
--- a/guides/source/5_2_release_notes.md
+++ b/guides/source/5_2_release_notes.md
@@ -326,7 +326,7 @@ Please refer to the [Changelog][action-view] for detailed changes.
select divider `option`.
([Pull Request](https://github.com/rails/rails/pull/31088))
-* Change `form_with` to generates ids by default.
+* Change `form_with` to generate ids by default.
([Commit](https://github.com/rails/rails/commit/260d6f112a0ffdbe03e6f5051504cb441c1e94cd))
* Add `preload_link_tag` helper.
diff --git a/guides/source/6_0_release_notes.md b/guides/source/6_0_release_notes.md
index 4eb5296c41..7c5478a03d 100644
--- a/guides/source/6_0_release_notes.md
+++ b/guides/source/6_0_release_notes.md
@@ -178,7 +178,7 @@ Please refer to the [Changelog][action-cable] for detailed changes.
`ActionCable::Connection`.
([Pull Request](https://github.com/rails/rails/pull/34194))
-* Convert the Action Cable Javascript package from CoffeeScript to ES2015 and
+* Convert the Action Cable JavaScript package from CoffeeScript to ES2015 and
publish the source code in the npm distribution.
([Pull Request](https://github.com/rails/rails/pull/34370))
@@ -202,7 +202,7 @@ Please refer to the [Changelog][action-pack] for detailed changes.
* Remove deprecated methods in `ActionDispatch::TestResponse`:
`#success?` in favor of `#successful?`, `#missing?` in favor of `#not_found?`,
- `#error?` in favor of `#server_error?`
+ `#error?` in favor of `#server_error?`.
([Commit](https://github.com/rails/rails/commit/13ddc92e079e59a0b894e31bf5bb4fdecbd235d1))
### Deprecations
@@ -215,6 +215,10 @@ Please refer to the [Changelog][action-pack] for detailed changes.
### Notable changes
+* Change `ActionDispatch::Response#content_type` returning Content-Type
+ header as it is.
+ ([Pull Request](https://github.com/rails/rails/pull/36034))
+
* Raise an `ArgumentError` if a resource param contains a colon.
([Pull Request](https://github.com/rails/rails/pull/35236))
@@ -229,7 +233,7 @@ Please refer to the [Changelog][action-pack] for detailed changes.
* Allow the use of `parsed_body` in `ActionController::TestCase`.
([Pull Request](https://github.com/rails/rails/pull/34717))
-* Raise an `ArgumentError` when multiple root routes exists in the same context
+* Raise an `ArgumentError` when multiple root routes exist in the same context
without `as:` naming specifications.
([Pull Request](https://github.com/rails/rails/pull/34494))
@@ -245,7 +249,7 @@ Please refer to the [Changelog][action-pack] for detailed changes.
* Expose `ActionController::Parameters#each_key`.
([Pull Request](https://github.com/rails/rails/pull/33758))
-* Add purpose metadata to signed/encrypted cookies to prevent copying the value of
+* Add purpose and expiry metadata inside signed/encrypted cookies to prevent copying the value of
cookies into one another.
([Pull Request](https://github.com/rails/rails/pull/32937))
@@ -298,14 +302,14 @@ Please refer to the [Changelog][action-view] for detailed changes.
### Notable changes
-* Clear ActionView cache in development only on file changes, speeding up
+* Clear Action View cache in development only on file changes, speeding up
development mode.
([Pull Request](https://github.com/rails/rails/pull/35629))
* Move all of the Rails npm packages into a `@rails` scope.
([Pull Request](https://github.com/rails/rails/pull/34905))
-* Only accept formats from registered Mime types.
+* Only accept formats from registered MIME types.
([Pull Request](https://github.com/rails/rails/pull/35604), [Pull Request](https://github.com/rails/rails/pull/35753))
* Add allocations to the template and partial rendering server output.
@@ -323,7 +327,7 @@ Please refer to the [Changelog][action-view] for detailed changes.
enable `ActionView::Template` finalizers.
([Pull Request](https://github.com/rails/rails/pull/32418))
-* Extract the JS `confirm` call to its own, overridable method in `rails_ujs`.
+* Extract the JavaScript `confirm` call to its own, overridable method in `rails_ujs`.
([Pull Request](https://github.com/rails/rails/pull/32404))
* Add a `action_controller.default_enforce_utf8` configuration option to handle
@@ -402,7 +406,7 @@ Please refer to the [Changelog][active-record] for detailed changes.
* Remove support for passing the column name to `count` when a block is passed.
([Commit](https://github.com/rails/rails/commit/67356f2034ab41305af7218f7c8b2fee2d614129))
-* Remove support for delegation of missing methods in a relation to arel.
+* Remove support for delegation of missing methods in a relation to Arel.
([Commit](https://github.com/rails/rails/commit/d97980a16d76ad190042b4d8578109714e9c53d0))
* Remove support for delegating missing methods in a relation to private methods of the class.
@@ -445,7 +449,7 @@ Please refer to the [Changelog][active-record] for detailed changes.
### Notable changes
-* Bump the minimum sqlite3 version to 1.4.
+* Bump the minimum version of the `sqlite3` gem to 1.4.
([Pull Request](https://github.com/rails/rails/pull/35844))
* Add `rails db:prepare` to create a database if it doesn't exist, and run its migrations.
@@ -467,7 +471,7 @@ Please refer to the [Changelog][active-record] for detailed changes.
([Pull Request](https://github.com/rails/rails/pull/35631))
* Add `rails db:seed:replant` that truncates tables of each database
- for ther current environment and loads the seeds.
+ for the current environment and loads the seeds.
([Pull Request](https://github.com/rails/rails/pull/34779))
* Add `reselect` method, which is a short-hand for `unscope(:select).select(fields)`.
@@ -509,7 +513,7 @@ Please refer to the [Changelog][active-record] for detailed changes.
([Pull Request](https://github.com/rails/rails/pull/34742))
* Add the ability to disable scopes generated by `ActiveRecord.enum`.
- ([Pull Request](https://github.com/rails/rails/pull/34605/files))
+ ([Pull Request](https://github.com/rails/rails/pull/34605))
* Make implicit ordering configurable for a column.
([Pull Request](https://github.com/rails/rails/pull/34480))
@@ -577,7 +581,7 @@ Please refer to the [Changelog][active-record] for detailed changes.
* Allow the `:to_table` option of `remove_foreign_key` to be invertible.
([Pull Request](https://github.com/rails/rails/pull/33530))
-* Fix default value for mysql time types with specified precision.
+* Fix default value for MySQL time types with specified precision.
([Pull Request](https://github.com/rails/rails/pull/33280))
* Fix the `touch` option to behave consistently with `Persistence#touch` method.
@@ -668,6 +672,12 @@ Please refer to the [Changelog][active-storage] for detailed changes.
is saved instead of immediately.
([Pull Request](https://github.com/rails/rails/pull/33303))
+* Optionally replace existing files instead of adding to them when assigning to
+ a collection of attachments (as in `@user.update!(images: [ … ])`). Use
+ `config.active_storage.replace_on_assign_to_many` to control this behavior.
+ ([Pull Request](https://github.com/rails/rails/pull/33303),
+ [Pull Request](https://github.com/rails/rails/pull/36716))
+
* Add the ability to reflect on defined attachments using the existing
Active Record reflection mechanism.
([Pull Request](https://github.com/rails/rails/pull/33018))
@@ -682,11 +692,7 @@ Please refer to the [Changelog][active-storage] for detailed changes.
* Use the `image_processing` gem for Active Storage variants. This replaces using
`mini_magick` directly.
- ([Pull Request](https://github.com/rails/rails/pull/32471)
-
-* Replace existing images instead of adding to them when updating an
- attached model via `update` or `update!` with, say, `@user.update!(images: [ … ])`.
- ([Pull Request](https://github.com/rails/rails/pull/33303))
+ ([Pull Request](https://github.com/rails/rails/pull/32471))
Active Model
------------
@@ -762,7 +768,7 @@ Please refer to the [Changelog][active-support] for detailed changes.
([Pull Request](https://github.com/rails/rails/pull/34123))
* Deprecate `ActiveSupport::Multibyte::Unicode#normalize`
- and `ActiveSuppport::Multibyte::Chars#normalize` in favor of
+ and `ActiveSupport::Multibyte::Chars#normalize` in favor of
`String#unicode_normalize`.
([Pull Request](https://github.com/rails/rails/pull/34202))
@@ -771,7 +777,7 @@ Please refer to the [Changelog][active-support] for detailed changes.
([Pull Request](https://github.com/rails/rails/pull/34215))
* Deprecate `ActiveSupport::Multibyte::Unicode#pack_graphemes(array)`
- and `ActiveSuppport::Multibyte::Unicode#unpack_graphemes(string)`
+ and `ActiveSupport::Multibyte::Unicode#unpack_graphemes(string)`
in favor of `array.flatten.pack("U*")` and `string.scan(/\X/).map(&:codepoints)`,
respectively.
([Pull Request](https://github.com/rails/rails/pull/34254))
diff --git a/guides/source/action_text_overview.md b/guides/source/action_text_overview.md
index 07919775e2..a735ec2b0e 100644
--- a/guides/source/action_text_overview.md
+++ b/guides/source/action_text_overview.md
@@ -46,6 +46,8 @@ happens after every keystroke, and avoids the need to use execCommand at all.
## Installation
Run `rails action_text:install` to add the Yarn package and copy over the necessary migration.
+Also, you need to set up Active Storage for embedded images and other attachments.
+Please refer to the [Active Storage Overview](active_storage_overview.html) guide.
## Examples
diff --git a/guides/source/action_view_overview.md b/guides/source/action_view_overview.md
index a1b69edd22..dda3ae0863 100644
--- a/guides/source/action_view_overview.md
+++ b/guides/source/action_view_overview.md
@@ -1025,6 +1025,34 @@ If `@article.author_id` is 1, this would return:
<label for="article_author_id_3">M. Clark</label>
```
+Recovering some option passed (e.g. programatically checking an object from collection):
+
+```ruby
+collection_radio_buttons(:article, :author_id, Author.all, :id, :name_with_initial, {checked: Author.last})
+```
+
+In this case, the last object from the collection will be checked:
+
+```html
+<input id="article_author_id_1" name="article[author_id]" type="radio" value="1" />
+<label for="article_author_id_1">D. Heinemeier Hansson</label>
+<input id="article_author_id_2" name="article[author_id]" type="radio" value="2" />
+<label for="article_author_id_2">D. Thomas</label>
+<input id="article_author_id_3" name="article[author_id]" type="radio" value="3" checked="checked" />
+<label for="article_author_id_3">M. Clark</label>
+```
+
+To access the passed options programatically (e.g. adding a custom class if checked):
+
+**Sample html.erb**
+
+```html+erb
+<%= collection_radio_buttons(:article, :author_id, Author.all, :id, :name_with_initial, {checked: Author.last, required: true} do |rb| %>
+ <%= rb.label(class: "#{'my-custom-class' if rb.value == Author.last.id}") { rb.radio_button + rb.text } %>
+<% end %>
+```
+
+
#### collection_check_boxes
Returns `check_box` tags for the collection of existing return values of `method` for `object`'s class.
diff --git a/guides/source/active_record_migrations.md b/guides/source/active_record_migrations.md
index 270e4a3bf9..9398244ccf 100644
--- a/guides/source/active_record_migrations.md
+++ b/guides/source/active_record_migrations.md
@@ -225,6 +225,8 @@ class CreateProducts < ActiveRecord::Migration[5.0]
create_table :products do |t|
t.string :name
t.string :part_number
+
+ t.timestamps
end
end
end
diff --git a/guides/source/active_record_multiple_databases.md b/guides/source/active_record_multiple_databases.md
new file mode 100644
index 0000000000..07be21a254
--- /dev/null
+++ b/guides/source/active_record_multiple_databases.md
@@ -0,0 +1,288 @@
+**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.**
+
+Multiple Databases with Active Record
+=====================================
+
+This guide covers using multiple databases with your Rails application.
+
+After reading this guide you will know:
+
+* How to setup your application for multiple databases.
+* How automatic connection switching works.
+* What features are supported and what's still a work in progress.
+
+--------------------------------------------------------------------------------
+
+As an application grows in popularity and usage you'll need to scale the application
+to support your new users and their data. One way in which your application may need
+to scale is on the database level. Rails now has support for multiple databases
+so you don't have to store your data all in one place.
+
+At this time the following features are supported:
+
+* Multiple primary databases and a replica for each
+* Automatic connection switching for the model you're working with
+* Automatic swapping between the primary and replica depending on the HTTP verb
+and recent writes
+* Rails tasks for creating, dropping, migrating, and interacting with the multiple
+databases
+
+The following features are not (yet) supported:
+
+* Sharding
+* Joining across clusters
+* Load balancing replicas
+* Dumping schema caches for multiple databases
+
+## Setting up your application
+
+While Rails tries to do most of the work for you there are still some steps you'll
+need to do to get your application ready for multiple databases.
+
+Let's say we have an application with a single primary database and we need to add a
+new database for some new tables we're adding. The name of the new database will be
+"animals".
+
+The database.yml looks like this:
+
+```yaml
+production:
+ database: my_primary_database
+ user: root
+ adapter: mysql
+```
+
+Let's add a replica for the primary, a new writer called animals and a replica for that
+as well. To do this we need to change our database.yml from a 2-tier to a 3-tier config.
+
+```yaml
+production:
+ primary:
+ database: my_primary_database
+ user: root
+ adapter: mysql
+ primary_replica:
+ database: my_primary_database
+ user: root_readonly
+ adapter: mysql
+ replica: true
+ animals:
+ database: my_animals_database
+ user: animals_root
+ adapter: mysql
+ migrations_paths: db/animals_migrate
+ animals_replica:
+ database: my_animals_database
+ user: animals_readonly
+ adapter: mysql
+ replica: true
+```
+
+When using multiple databases there are a few important settings.
+
+First, the database name for the primary and replica should be the same because they contain
+the same data. Second, the username for the primary and replica should be different, and the
+replica user's permissions should be to read and not write.
+
+When using a replica database you need to add a `replica: true` entry to the replica in the
+`database.yml`. This is because Rails otherwise has no way of knowing which one is a replica
+and which one is the primary.
+
+Lastly, for new primary databases you need to set the `migrations_paths` to the directory
+where you will store migrations for that database. We'll look more at `migrations_paths`
+later on in this guide.
+
+Now that we have a new database, let's set up the model. In order to use the new database we
+need to create a new abstract class and connect to the animals databases.
+
+```ruby
+class AnimalsBase < ApplicationRecord
+ self.abstract_class = true
+
+ connects_to database: { writing: :animals, reading: :animals_replica }
+end
+```
+ Then we need to
+update `ApplicationRecord` to be aware of our new replica.
+
+```ruby
+class ApplicationRecord < ActiveRecord::Base
+ self.abstract_class = true
+
+ connects_to database: { writing: :primary, reading: :primary_replica }
+end
+```
+
+By default Rails expects the database roles to be `writing` and `reading` for the primary
+and replica respectively. If you have a legacy system you may already have roles set up that
+you don't want to change. In that case you can set a new role name in your application config.
+
+```ruby
+config.active_record.writing_role = :default
+config.active_record.reading_role = :readonly
+```
+
+It's important to connect to your database in a single model and then inherit from that model
+for the tables rather than connect multiple individual models to the same database. Database
+clients have a limit to the number of open connections there can be and if you do this it will
+multiply the number of connections you have since Rails uses the model class name for the
+connection specification name.
+
+Now that we have the database.yml and the new model set up it's time to create the databases.
+Rails 6.0 ships with all the rails tasks you need to use multiple databases in Rails.
+
+You can run `rails -T` to see all the commands you're able to run. You should see the following:
+
+```
+$ rails -T
+rails db:create # Creates the database from DATABASE_URL or config/database.yml for the ...
+rails db:create:animals # Create animals database for current environment
+rails db:create:primary # Create primary database for current environment
+rails db:drop # Drops the database from DATABASE_URL or config/database.yml for the cu...
+rails db:drop:animals # Drop animals database for current environment
+rails db:drop:primary # Drop primary database for current environment
+rails db:migrate # Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)
+rails db:migrate:animals # Migrate animals database for current environment
+rails db:migrate:primary # Migrate primary database for current environment
+rails db:migrate:status # Display status of migrations
+rails db:migrate:status:animals # Display status of migrations for animals database
+rails db:migrate:status:primary # Display status of migrations for primary database
+```
+
+Running a command like `rails db:create` will create both the primary and animals databases.
+Note that there is no command for creating the users and you'll need to do that manually
+to support the readonly users for your replicas. If you want to create just the animals
+database you can run `rails db:create:animals`.
+
+## Migrations
+
+Migrations for multiple databases should live in their own folders prefixed with the
+name of the database key in the configuration.
+
+You also need to set the `migrations_paths` in the database configurations to tell Rails
+where to find the migrations.
+
+For example the `animals` database would look in the `db/animals_migrate` directory and
+`primary` would look in `db/migrate`. Rails generators now take a `--database` option
+so that the file is generated in the correct directory. The command can be run like so:
+
+```
+$ rails g migration CreateDogs name:string --database animals
+```
+
+## Activating automatic connection switching
+
+Finally, in order to use the read-only replica in your application you'll need to activate
+the middleware for automatic switching.
+
+Automatic switching allows the application to switch from the primary to replica or replica
+to primary based on the HTTP verb and whether there was a recent write.
+
+If the application is receiving a POST, PUT, DELETE, or PATCH request the application will
+automatically write to the primary. For the specified time after the write the application
+will read from the primary. For a GET or HEAD request the application will read from the
+replica unless there was a recent write.
+
+To activate the automatic connection switching middleware, add or uncomment the following
+lines in your application config.
+
+```ruby
+config.active_record.database_selector = { delay: 2.seconds }
+config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
+config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
+```
+
+Rails guarantees "read your own write" and will send your GET or HEAD request to the
+primary if it's within the `delay` window. By default the delay is set to 2 seconds. You
+should change this based on your database infrastructure. Rails doesn't guarantee "read
+a recent write" for other users within the delay window and will send GET and HEAD requests
+to the replicas unless they wrote recently.
+
+The automatic connection switching in Rails is relatively primitive and deliberately doesn't
+do a whole lot. The goal was a system that demonstrated how to do automatic connection
+switching that was flexible enough to be customizable by app developers.
+
+The setup in Rails allows you to easily change how the switching is done and what
+parameters it's based on. Let's say you want to use a cookie instead of a session to
+decide when to swap connections. You can write your own class:
+
+```ruby
+class MyCookieResolver
+ # code for your cookie class
+end
+```
+
+And then pass it to the middleware:
+
+```ruby
+config.active_record.database_selector = { delay: 2.seconds }
+config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
+config.active_record.database_resolver_context = MyCookieResolver
+```
+
+## Using manual connection switching
+
+There are some cases where you may want your application to connect to a primary or a replica
+and the automatic connection switching isn't adequate. For example, you may know that for a
+particular request you always want to send the request to a replica, even when you are in a
+POST request path.
+
+To do this Rails provides a `connected_to` method that will switch to the connection you
+need.
+
+```ruby
+ActiveRecord::Base.connected_to(role: :reading) do
+ # all code in this block will be connected to the reading role
+end
+```
+
+The "role" in the `connected_to` call looks up the connections that are connected on that
+connection handler (or role). The `reading` connection handler will hold all the connections
+that were connected via `connects_to` with the role name of `reading`.
+
+There also may be a case where you have a database that you don't always want to connect to
+on application boot but may need for a slow query or analytics. After defining that database
+in the database.yml you can connect by passing a database argument to `connected_to`
+
+```ruby
+ActiveRecord::Base.connected_to(database: { reading_slow: :animals_slow_replica }) do
+ # do something while connected to the slow replica
+end
+```
+
+The `database` argument for `connected_to` will take a symbol or a config hash.
+
+Note that `connected_to` with a role will look up an existing connection and switch
+using the connection specification name. This means that if you pass an unknown role
+like `connected_to(role: :nonexistent)` you will get an error that says
+`ActiveRecord::ConnectionNotEstablished (No connection pool with 'AnimalsBase' found
+for the 'nonexistent' role.)`
+
+## Caveats
+
+### Sharding
+
+As noted at the top, Rails doesn't (yet) support sharding. We had to do a lot of work
+to support multiple databases for Rails 6.0. The lack of support for sharding isn't
+an oversight, but does require additional work that didn't make it in for 6.0. For now
+if you need sharding it may be advisable to continue using one of the many gems
+that supports this.
+
+### Load Balancing Replicas
+
+Rails also doesn't support automatic load balancing of replicas. This is very
+dependent on your infrastructure. We may implement basic, primitive load balancing
+in the future, but for an application at scale this should be something your application
+handles outside of Rails.
+
+### Joining Across Databases
+
+Applications cannot join across databases. Rails 6.1 will support using `has_many`
+relationships and creating 2 queries instead of joining, but Rails 6.0 will require
+you to split the joins into 2 selects manually.
+
+### Schema Cache
+
+If you use a schema cache and multiple databases you'll need to write an initializer
+that loads the schema cache from your app. This wasn't an issue we could resolve in
+time for Rails 6.0 but hope to have it in a future version soon.
diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md
index e40f16e62d..5fb030fad4 100644
--- a/guides/source/active_record_querying.md
+++ b/guides/source/active_record_querying.md
@@ -1821,6 +1821,21 @@ Client.limit(1).pluck(:name)
# => ["David"]
```
+NOTE: You should also know that using `pluck` will trigger eager loading if the relation object contains include values, even if the eager loading is not necessary for the query. For example:
+
+```ruby
+# store association for reusing it
+assoc = Company.includes(:account)
+assoc.pluck(:id)
+# SELECT "companies"."id" FROM "companies" LEFT OUTER JOIN "accounts" ON "accounts"."id" = "companies"."account_id"
+```
+
+One way to avoid this is to `unscope` the includes:
+
+```ruby
+assoc.unscope(:includes).pluck(:id)
+```
+
### `ids`
`ids` can be used to pluck all the IDs for the relation using the table's primary key.
diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md
index 615f576797..54f8f5c2b5 100644
--- a/guides/source/active_storage_overview.md
+++ b/guides/source/active_storage_overview.md
@@ -41,6 +41,10 @@ application (or upgrading your application to Rails 5.2), run
`rails active_storage:install` to generate a migration that creates these
tables. Use `rails db:migrate` to run the migration.
+WARNING: `active_storage_attachments` is a polymorphic join table that stores your model's class name. If your model's class name changes, you will need to run a migration on this table to update the underlying `record_type` to your model's new class name.
+
+WARNING: If you are using UUIDs instead of integers as the primary key on your models you will need to change the column type of `record_id` for the `active_storage_attachments` table in the generated migration accordingly.
+
Declare Active Storage services in `config/storage.yml`. For each service your
application uses, provide a name and the requisite configuration. The example
below declares three services named `local`, `test`, and `amazon`:
@@ -189,14 +193,21 @@ gem "google-cloud-storage", "~> 1.11", require: false
### Mirror Service
-You can keep multiple services in sync by defining a mirror service. When a file
-is uploaded or deleted, it's done across all the mirrored services. Mirrored
-services can be used to facilitate a migration between services in production.
-You can start mirroring to the new service, copy existing files from the old
-service to the new, then go all-in on the new service. Define each of the
-services you'd like to use as described above and reference them from a mirrored
+You can keep multiple services in sync by defining a mirror service. A mirror
+service replicates uploads and deletes across two or more subordinate services.
+
+A mirror service is intended to be used temporarily during a migration between
+services in production. You can start mirroring to a new service, copy
+pre-existing files from the old service to the new, then go all-in on the new
service.
+NOTE: Mirroring is not atomic. It is possible for an upload to succeed on the
+primary service and fail on any of the subordinate services. Before going
+all-in on a new service, verify that all files have been copied.
+
+Define each of the services you'd like to mirror as described above. Reference
+them by name when defining a mirror service:
+
```yaml
s3_west_coast:
service: S3
@@ -219,9 +230,12 @@ production:
- s3_west_coast
```
-NOTE: Files are served from the primary service.
+Although all secondary services receive uploads, downloads are always handled
+by the primary service.
-NOTE: This is not compatible with the [direct uploads](#direct-uploads) feature.
+Mirror services are compatible with direct uploads. New files are directly
+uploaded to the primary service. When a directly-uploaded file is attached to a
+record, a background job is enqueued to copy it to the secondary services.
Attaching Files to Records
--------------------------
@@ -386,6 +400,10 @@ helper allows you to set the disposition.
rails_blob_path(user.avatar, disposition: "attachment")
```
+WARNING: To prevent XSS attacks, ActiveStorage forces the Content-Disposition header
+to "attachment" for some kind of files. To change this behaviour see the
+available configuration opions in [Configuring Rails Applications](configuring.html#configuring-active-storage).
+
If you need to create a link from outside of controller/view context (Background
jobs, Cronjobs, etc.), you can access the rails_blob_path like this:
diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md
index 1a057832d4..f36cacfe8d 100644
--- a/guides/source/active_support_core_extensions.md
+++ b/guides/source/active_support_core_extensions.md
@@ -155,15 +155,6 @@ Complex(1).duplicable? # => true
1.method(:+).duplicable? # => false
```
-`duplicable?` matches the current Ruby version's `dup` behavior,
-so results will vary according the version of Ruby you're using.
-In Ruby 2.4, for example, Complex and Rational are not duplicable:
-
-```ruby
-Rational(1).duplicable? # => false
-Complex(1).duplicable? # => false
-```
-
WARNING: Any class can disallow duplication by removing `dup` and `clone` or raising exceptions from them. Thus only `rescue` can tell whether a given arbitrary object is duplicable. `duplicable?` depends on the hard-coded list above, but it is much faster than `rescue`. Use it only if you know the hard-coded list is enough in your use case.
NOTE: Defined in `active_support/core_ext/object/duplicable.rb`.
@@ -2358,10 +2349,6 @@ There's also a related idiom that uses the splat operator:
[*object]
```
-which in Ruby 1.8 returns `[nil]` for `nil`, and calls to `Array(object)` otherwise. (Please if you know the exact behavior in 1.9 contact fxn.)
-
-Thus, in this case the behavior is different for `nil`, and the differences with `Kernel#Array` explained above apply to the rest of `object`s.
-
NOTE: Defined in `active_support/core_ext/array/wrap.rb`.
### Duplicating
@@ -2633,14 +2620,12 @@ The method `stringify_keys` returns a hash that has a stringified version of the
# => {"" => nil, "1" => 1, "a" => :a}
```
-In case of key collision, one of the values will be chosen. The chosen value may not always be the same given the same hash:
+In case of key collision, the value will be the one most recently inserted into the hash:
```ruby
{"a" => 1, a: 2}.stringify_keys
-# The result could either be
+# The result will be
# => {"a"=>2}
-# or
-# => {"a"=>1}
```
This method may be useful for example to easily accept both symbols and strings as options. For instance `ActionView::Helpers::FormHelper` defines:
@@ -2677,14 +2662,12 @@ The method `symbolize_keys` returns a hash that has a symbolized version of the
WARNING. Note in the previous example only one key was symbolized.
-In case of key collision, one of the values will be chosen. The chosen value may not always be the same given the same hash:
+In case of key collision, the value will be the one most recently inserted into the hash:
```ruby
{"a" => 1, a: 2}.symbolize_keys
-# The result could either be
+# The result will be
# => {:a=>2}
-# or
-# => {:a=>1}
```
This method may be useful for example to easily accept both symbols and strings as options. For instance `ActionController::UrlRewriter` defines
@@ -3420,56 +3403,56 @@ NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`.
#### `prev_day`, `next_day`
-In Ruby 1.9 `prev_day` and `next_day` return the date in the last or next day:
+`prev_day` and `next_day` return the time in the last or next day:
```ruby
-d = Date.new(2010, 5, 8) # => Sat, 08 May 2010
-d.prev_day # => Fri, 07 May 2010
-d.next_day # => Sun, 09 May 2010
+t = Time.new(2010, 5, 8) # => 2010-05-08 00:00:00 +0900
+t.prev_day # => 2010-05-07 00:00:00 +0900
+t.next_day # => 2010-05-09 00:00:00 +0900
```
-NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`.
+NOTE: Defined in `active_support/core_ext/time/calculations.rb`.
#### `prev_month`, `next_month`
-In Ruby 1.9 `prev_month` and `next_month` return the date with the same day in the last or next month:
+`prev_month` and `next_month` return the time with the same day in the last or next month:
```ruby
-d = Date.new(2010, 5, 8) # => Sat, 08 May 2010
-d.prev_month # => Thu, 08 Apr 2010
-d.next_month # => Tue, 08 Jun 2010
+t = Time.new(2010, 5, 8) # => 2010-05-08 00:00:00 +0900
+t.prev_month # => 2010-04-08 00:00:00 +0900
+t.next_month # => 2010-06-08 00:00:00 +0900
```
If such a day does not exist, the last day of the corresponding month is returned:
```ruby
-Date.new(2000, 5, 31).prev_month # => Sun, 30 Apr 2000
-Date.new(2000, 3, 31).prev_month # => Tue, 29 Feb 2000
-Date.new(2000, 5, 31).next_month # => Fri, 30 Jun 2000
-Date.new(2000, 1, 31).next_month # => Tue, 29 Feb 2000
+Time.new(2000, 5, 31).prev_month # => 2000-04-30 00:00:00 +0900
+Time.new(2000, 3, 31).prev_month # => 2000-02-29 00:00:00 +0900
+Time.new(2000, 5, 31).next_month # => 2000-06-30 00:00:00 +0900
+Time.new(2000, 1, 31).next_month # => 2000-02-29 00:00:00 +0900
```
-NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`.
+NOTE: Defined in `active_support/core_ext/time/calculations.rb`.
#### `prev_year`, `next_year`
-In Ruby 1.9 `prev_year` and `next_year` return a date with the same day/month in the last or next year:
+`prev_year` and `next_year` return a time with the same day/month in the last or next year:
```ruby
-d = Date.new(2010, 5, 8) # => Sat, 08 May 2010
-d.prev_year # => Fri, 08 May 2009
-d.next_year # => Sun, 08 May 2011
+t = Time.new(2010, 5, 8) # => 2010-05-08 00:00:00 +0900
+t.prev_year # => 2009-05-08 00:00:00 +0900
+t.next_year # => 2011-05-08 00:00:00 +0900
```
If date is the 29th of February of a leap year, you obtain the 28th:
```ruby
-d = Date.new(2000, 2, 29) # => Tue, 29 Feb 2000
-d.prev_year # => Sun, 28 Feb 1999
-d.next_year # => Wed, 28 Feb 2001
+t = Time.new(2000, 2, 29) # => 2000-02-29 00:00:00 +0900
+t.prev_year # => 1999-02-28 00:00:00 +0900
+t.next_year # => 2001-02-28 00:00:00 +0900
```
-NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`.
+NOTE: Defined in `active_support/core_ext/time/calculations.rb`.
#### `prev_quarter`, `next_quarter`
diff --git a/guides/source/active_support_instrumentation.md b/guides/source/active_support_instrumentation.md
index 4868b00bbe..9f15e70da6 100644
--- a/guides/source/active_support_instrumentation.md
+++ b/guides/source/active_support_instrumentation.md
@@ -643,7 +643,16 @@ The block receives the following arguments:
```ruby
ActiveSupport::Notifications.subscribe "process_action.action_controller" do |name, started, finished, unique_id, data|
# your own custom stuff
- Rails.logger.info "#{name} Received!"
+ Rails.logger.info "#{name} Received! (started: #{started}, finished: #{finished})" # process_action.action_controller Received (started: 2019-05-05 13:43:57 -0800, finished: 2019-05-05 13:43:58 -0800)
+end
+```
+
+If you are concerned about the accuracy of `started` and `finished` to compute a precise elapsed time then use `ActiveSupport::Notifications.monotonic_subscribe`. The given block would receive the same arguments as above but the `started` and `finished` will have values with an accurate monotonic time instead of wall-clock time.
+
+```ruby
+ActiveSupport::Notifications.monotonic_subscribe "process_action.action_controller" do |name, started, finished, unique_id, data|
+ # your own custom stuff
+ Rails.logger.info "#{name} Received! (started: #{started}, finished: #{finished})" # process_action.action_controller Received (started: 1560978.425334, finished: 1560979.429234)
end
```
diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md
index 62e9270539..27387ac3ac 100644
--- a/guides/source/association_basics.md
+++ b/guides/source/association_basics.md
@@ -2451,8 +2451,8 @@ Extensions can refer to the internals of the association proxy using these three
* `proxy_association.reflection` returns the reflection object that describes the association.
* `proxy_association.target` returns the associated object for `belongs_to` or `has_one`, or the collection of associated objects for `has_many` or `has_and_belongs_to_many`.
-Single Table Inheritance
-------------------------
+Single Table Inheritance (STI)
+------------------------------
Sometimes, you may want to share fields and behavior between different models.
Let's say we have Car, Motorcycle, and Bicycle models. We will want to share
diff --git a/guides/source/autoloading_and_reloading_constants.md b/guides/source/autoloading_and_reloading_constants.md
index 7dfc39e192..8cd2d353de 100644
--- a/guides/source/autoloading_and_reloading_constants.md
+++ b/guides/source/autoloading_and_reloading_constants.md
@@ -1,18 +1,18 @@
**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.**
-Autoloading and Reloading Constants
-===================================
+Autoloading and Reloading Constants (Zeitwerk Mode)
+======================================================
-This guide documents how constant autoloading and reloading works.
+This guide documents how autoloading and reloading works in `zeitwerk` mode.
After reading this guide, you will know:
-* Key aspects of Ruby constants
-* What are the `autoload_paths` and how does eager loading work in production?
-* How constant autoloading works
-* What is `require_dependency`
-* How constant reloading works
-* Solutions to common autoloading gotchas
+* Autoloading modes
+* Related Rails configuration
+* Project structure
+* Autoloading, reloading, and eager loading
+* Single Table Inheritance
+* And more
--------------------------------------------------------------------------------
@@ -20,13 +20,15 @@ After reading this guide, you will know:
Introduction
------------
-Ruby on Rails allows applications to be written as if their code was preloaded.
+INFO. This guide documents autoloading in `zeitwerk` mode, which is new in Rails 6. If you'd like to read about `classic` mode instead, please check [Autoloading and Reloading Constants (Classic Mode)](autoloading_and_reloading_constants_classic_mode.html).
-In a normal Ruby program classes need to load their dependencies:
+In a normal Ruby program, dependencies need to be loaded by hand. For example, the following controller uses classes `ApplicationController` and `Post`, and normally you'd need to put `require` calls for them:
```ruby
-require 'application_controller'
-require 'post'
+# DO NOT DO THIS.
+require "application_controller"
+require "post"
+# DO NOT DO THIS.
class PostsController < ApplicationController
def index
@@ -35,16 +37,7 @@ class PostsController < ApplicationController
end
```
-Our Rubyist instinct quickly sees some redundancy in there: If classes were
-defined in files matching their name, couldn't their loading be automated
-somehow? We could save scanning the file for dependencies, which is brittle.
-
-Moreover, `Kernel#require` loads files once, but development is much more smooth
-if code gets refreshed when it changes without restarting the server. It would
-be nice to be able to use `Kernel#load` in development, and `Kernel#require` in
-production.
-
-Indeed, those features are provided by Ruby on Rails, where we just write
+This is not the case in Rails applications, where application classes and modules are just available everywhere:
```ruby
class PostsController < ApplicationController
@@ -54,1330 +47,255 @@ class PostsController < ApplicationController
end
```
-This guide documents how that works.
-
-
-Constants Refresher
--------------------
-
-While constants are trivial in most programming languages, they are a rich
-topic in Ruby.
-
-It is beyond the scope of this guide to document Ruby constants, but we are
-nevertheless going to highlight a few key topics. Truly grasping the following
-sections is instrumental to understanding constant autoloading and reloading.
-
-### Nesting
-
-Class and module definitions can be nested to create namespaces:
-
-```ruby
-module XML
- class SAXParser
- # (1)
- end
-end
-```
-
-The *nesting* at any given place is the collection of enclosing nested class and
-module objects outwards. The nesting at any given place can be inspected with
-`Module.nesting`. For example, in the previous example, the nesting at
-(1) is
-
-```ruby
-[XML::SAXParser, XML]
-```
-
-It is important to understand that the nesting is composed of class and module
-*objects*, it has nothing to do with the constants used to access them, and is
-also unrelated to their names.
-
-For instance, while this definition is similar to the previous one:
-
-```ruby
-class XML::SAXParser
- # (2)
-end
-```
-
-the nesting in (2) is different:
-
-```ruby
-[XML::SAXParser]
-```
-
-`XML` does not belong to it.
-
-We can see in this example that the name of a class or module that belongs to a
-certain nesting does not necessarily correlate with the namespaces at the spot.
-
-Even more, they are totally independent, take for instance
-
-```ruby
-module X
- module Y
- end
-end
-
-module A
- module B
- end
-end
-
-module X::Y
- module A::B
- # (3)
- end
-end
-```
-
-The nesting in (3) consists of two module objects:
-
-```ruby
-[A::B, X::Y]
-```
-
-So, it not only doesn't end in `A`, which does not even belong to the nesting,
-but it also contains `X::Y`, which is independent from `A::B`.
-
-The nesting is an internal stack maintained by the interpreter, and it gets
-modified according to these rules:
-
-* The class object following a `class` keyword gets pushed when its body is
-executed, and popped after it.
-
-* The module object following a `module` keyword gets pushed when its body is
-executed, and popped after it.
-
-* A singleton class opened with `class << object` gets pushed, and popped later.
-
-* When `instance_eval` is called using a string argument,
-the singleton class of the receiver is pushed to the nesting of the eval'ed
-code. When `class_eval` or `module_eval` is called using a string argument,
-the receiver is pushed to the nesting of the eval'ed code.
-
-* The nesting at the top-level of code interpreted by `Kernel#load` is empty
-unless the `load` call receives a true value as second argument, in which case
-a newly created anonymous module is pushed by Ruby.
-
-It is interesting to observe that blocks do not modify the stack. In particular
-the blocks that may be passed to `Class.new` and `Module.new` do not get the
-class or module being defined pushed to their nesting. That's one of the
-differences between defining classes and modules in one way or another.
-
-### Class and Module Definitions are Constant Assignments
-
-Let's suppose the following snippet creates a class (rather than reopening it):
-
-```ruby
-class C
-end
-```
-
-Ruby creates a constant `C` in `Object` and stores in that constant a class
-object. The name of the class instance is "C", a string, named after the
-constant.
+Idiomatic Rails applications only issue `require` calls to load stuff from their `lib` directory, the Ruby standard library, Ruby gems, etc. That is, anything that does not belong to their autoload paths, explained below.
-That is,
-```ruby
-class Project < ApplicationRecord
-end
-```
+Enabling Zeitwerk Mode
+----------------------
-performs a constant assignment equivalent to
+The autoloading `zeitwerk` mode is enabled by default in Rails 6 applications running on CRuby:
```ruby
-Project = Class.new(ApplicationRecord)
+# config/application.rb
+config.load_defaults "6.x" # enables zeitwerk mode in CRuby
```
-including setting the name of the class as a side-effect:
+In `zeitwerk` mode, Rails uses [Zeitwerk](https://github.com/fxn/zeitwerk) internally to autoload, reload, and eager load. Rails instantiates and configures a dedicated Zeitwerk instance that manages the project.
-```ruby
-Project.name # => "Project"
-```
+INFO. You do not configure Zeitwerk manually in a Rails application. Rather, you configure the application using the portable configuration points explained in this guide, and Rails translates that to Zeitwerk on your behalf.
-Constant assignment has a special rule to make that happen: if the object
-being assigned is an anonymous class or module, Ruby sets the object's name to
-the name of the constant.
+Project Structure
+-----------------
-INFO. From then on, what happens to the constant and the instance does not
-matter. For example, the constant could be deleted, the class object could be
-assigned to a different constant, be stored in no constant anymore, etc. Once
-the name is set, it doesn't change.
+In a Rails application file names have to match the constants they define, with directories acting as namespaces.
-Similarly, module creation using the `module` keyword as in
+For example, the file `app/helpers/users_helper.rb` should define `UsersHelper` and the file `app/controllers/admin/payments_controller.rb` should define `Admin::PaymentsController`.
-```ruby
-module Admin
-end
-```
-
-performs a constant assignment equivalent to
+Rails configures Zeitwerk to inflect file names with `String#camelize`. For example, it expects that `app/controllers/users_controller.rb` defines the constant `UsersController` because
```ruby
-Admin = Module.new
+"users_controller".camelize # => UsersController
```
-including setting the name as a side-effect:
+If you need to customize any of these inflections, for example to add an acronym, please have a look at `config/initializers/inflections.rb`.
-```ruby
-Admin.name # => "Admin"
-```
+Please, check the [Zeitwerk documentation](https://github.com/fxn/zeitwerk#file-structure) for further details.
-WARNING. The execution context of a block passed to `Class.new` or `Module.new`
-is not entirely equivalent to the one of the body of the definitions using the
-`class` and `module` keywords. But both idioms result in the same constant
-assignment.
-
-Thus, an informal expression like "the `String` class" technically means the
-class object stored in the constant called "String". That constant, in turn,
-belongs to the class object stored in the constant called "Object".
-
-`String` is an ordinary constant, and everything related to them such as
-resolution algorithms applies to it.
-
-Likewise, in the controller
-
-```ruby
-class PostsController < ApplicationController
- def index
- @posts = Post.all
- end
-end
-```
-
-`Post` is not syntax for a class. Rather, `Post` is a regular Ruby constant. If
-all is good, the constant is evaluated to an object that responds to `all`.
+Autoload paths
+--------------
-That is why we talk about *constant* autoloading, Rails has the ability to
-load constants on the fly.
+We call _autoload paths_ to the list of application directories whose contents are to be autoloaded. For example, `app/models`. Such directories represent the root namespace: `Object`.
-### Constants are Stored in Modules
+INFO. Autoload paths are called _root directories_ in Zeitwerk documentation, but we'll stay with "autoload path" in this guide.
-Constants belong to modules in a very literal sense. Classes and modules have
-a constant table; think of it as a hash table.
+Within an autoload path, file names must match the constants they define as documented [here](https://github.com/fxn/zeitwerk#file-structure).
-Let's analyze an example to really understand what that means. While common
-abuses of language like "the `String` class" are convenient, the exposition is
-going to be precise here for didactic purposes.
+By default, the autoload paths of an application consist of all the subdirectories of `app` that exist when the application boots ---except for `aasets`, `javascripts`, `views`,--- plus the autoload paths of engines it might depend on.
-Let's consider the following module definition:
+For example, if `UsersHelper` is implemented in `app/helpers/users_helper.rb`, the module is autoloadable, you do not need (and should not write) a `require` call for it:
-```ruby
-module Colors
- RED = '0xff0000'
-end
```
-
-First, when the `module` keyword is processed, the interpreter creates a new
-entry in the constant table of the class object stored in the `Object` constant.
-Said entry associates the name "Colors" to a newly created module object.
-Furthermore, the interpreter sets the name of the new module object to be the
-string "Colors".
-
-Later, when the body of the module definition is interpreted, a new entry is
-created in the constant table of the module object stored in the `Colors`
-constant. That entry maps the name "RED" to the string "0xff0000".
-
-In particular, `Colors::RED` is totally unrelated to any other `RED` constant
-that may live in any other class or module object. If there were any, they
-would have separate entries in their respective constant tables.
-
-Pay special attention in the previous paragraphs to the distinction between
-class and module objects, constant names, and value objects associated to them
-in constant tables.
-
-### Resolution Algorithms
-
-#### Resolution Algorithm for Relative Constants
-
-At any given place in the code, let's define *cref* to be the first element of
-the nesting if it is not empty, or `Object` otherwise.
-
-Without getting too much into the details, the resolution algorithm for relative
-constant references goes like this:
-
-1. If the nesting is not empty the constant is looked up in its elements and in
-order. The ancestors of those elements are ignored.
-
-2. If not found, then the algorithm walks up the ancestor chain of the cref.
-
-3. If not found and the cref is a module, the constant is looked up in `Object`.
-
-4. If not found, `const_missing` is invoked on the cref. The default
-implementation of `const_missing` raises `NameError`, but it can be overridden.
-
-Rails autoloading **does not emulate this algorithm**, but its starting point is
-the name of the constant to be autoloaded, and the cref. See more in [Relative
-References](#autoloading-algorithms-relative-references).
-
-#### Resolution Algorithm for Qualified Constants
-
-Qualified constants look like this:
-
-```ruby
-Billing::Invoice
+$ bin/rails runner 'p UsersHelper'
+UsersHelper
```
-`Billing::Invoice` is composed of two constants: `Billing` is relative and is
-resolved using the algorithm of the previous section.
-
-INFO. Leading colons would make the first segment absolute rather than
-relative: `::Billing::Invoice`. That would force `Billing` to be looked up
-only as a top-level constant.
-
-`Invoice` on the other hand is qualified by `Billing` and we are going to see
-its resolution next. Let's define *parent* to be that qualifying class or module
-object, that is, `Billing` in the example above. The algorithm for qualified
-constants goes like this:
-
-1. The constant is looked up in the parent and its ancestors. In Ruby >= 2.5,
-`Object` is skipped if present among the ancestors. `Kernel` and `BasicObject`
-are still checked though.
+Autoload paths automatically pick any custom directories under `app`. For example, if your application has `app/presenters`, or `app/services`, etc., they are added to autoload paths.
-2. If the lookup fails, `const_missing` is invoked in the parent. The default
-implementation of `const_missing` raises `NameError`, but it can be overridden.
+The array of autoload paths can be extended by mutating `config.autoload_paths`, in `config/application.rb`, but nowadays this is discouraged.
-INFO. In Ruby < 2.5 `String::Hash` evaluates to `Hash` and the interpreter
-issues a warning: "toplevel constant Hash referenced by String::Hash". Starting
-with 2.5, `String::Hash` raises `NameError` because `Object` is skipped.
+WARNING. Please, do not mutate `ActiveSupport::Dependencies.autoload_paths`, the public interface to change autoload paths is `config.autoload_paths`.
-As you see, this algorithm is simpler than the one for relative constants. In
-particular, the nesting plays no role here, and modules are not special-cased,
-if neither they nor their ancestors have the constants, `Object` is **not**
-checked.
-Rails autoloading **does not emulate this algorithm**, but its starting point is
-the name of the constant to be autoloaded, and the parent. See more in
-[Qualified References](#autoloading-algorithms-qualified-references).
-
-
-Vocabulary
+$LOAD_PATH
----------
-### Parent Namespaces
-
-Given a string with a constant path we define its *parent namespace* to be the
-string that results from removing its rightmost segment.
-
-For example, the parent namespace of the string "A::B::C" is the string "A::B",
-the parent namespace of "A::B" is "A", and the parent namespace of "A" is "".
-
-The interpretation of a parent namespace when thinking about classes and modules
-is tricky though. Let's consider a module M named "A::B":
-
-* The parent namespace, "A", may not reflect nesting at a given spot.
-
-* The constant `A` may no longer exist, some code could have removed it from
-`Object`.
-
-* If `A` exists, the class or module that was originally in `A` may not be there
-anymore. For example, if after a constant removal there was another constant
-assignment there would generally be a different object in there.
-
-* In such case, it could even happen that the reassigned `A` held a new class or
-module called also "A"!
-
-* In the previous scenarios M would no longer be reachable through `A::B` but
-the module object itself could still be alive somewhere and its name would
-still be "A::B".
-
-The idea of a parent namespace is at the core of the autoloading algorithms
-and helps explain and understand their motivation intuitively, but as you see
-that metaphor leaks easily. Given an edge case to reason about, take always into
-account that by "parent namespace" the guide means exactly that specific string
-derivation.
-
-### Loading Mechanism
-
-Rails autoloads files with `Kernel#load` when `config.cache_classes` is false,
-the default in development mode, and with `Kernel#require` otherwise, the
-default in production mode.
-
-`Kernel#load` allows Rails to execute files more than once if [constant
-reloading](#constant-reloading) is enabled.
-
-This guide uses the word "load" freely to mean a given file is interpreted, but
-the actual mechanism can be `Kernel#load` or `Kernel#require` depending on that
-flag.
-
-
-Autoloading Availability
-------------------------
-
-Rails is always able to autoload provided its environment is in place. For
-example the `runner` command autoloads:
-
-```
-$ rails runner 'p User.column_names'
-["id", "email", "created_at", "updated_at"]
-```
-
-The console autoloads, the test suite autoloads, and of course the application
-autoloads.
-
-By default, Rails eager loads the application files when it boots in production
-mode, so most of the autoloading going on in development does not happen. But
-autoloading may still be triggered during eager loading.
-
-For example, given
-
-```ruby
-class BeachHouse < House
-end
-```
-
-if `House` is still unknown when `app/models/beach_house.rb` is being eager
-loaded, Rails autoloads it.
-
-
-autoload_paths and eager_load_paths
------------------------------------
-
-As you probably know, when `require` gets a relative file name:
+Autoload paths are added to `$LOAD_PATH` by default. However, Zeitwerk uses absolute file names internally, and your application should not issue `require` calls for autoloadable files, so those directories are actually not needed there. You can opt-out with this flag:
```ruby
-require 'erb'
+config.add_autoload_paths_to_load_path = false
```
-Ruby looks for the file in the directories listed in `$LOAD_PATH`. That is, Ruby
-iterates over all its directories and for each one of them checks whether they
-have a file called "erb.rb", or "erb.so", or "erb.o", or "erb.dll". If it finds
-any of them, the interpreter loads it and ends the search. Otherwise, it tries
-again in the next directory of the list. If the list gets exhausted, `LoadError`
-is raised.
-
-We are going to cover how constant autoloading works in more detail later, but
-the idea is that when a constant like `Post` is hit and missing, if there's a
-`post.rb` file for example in `app/models` Rails is going to find it, evaluate
-it, and have `Post` defined as a side-effect.
-
-All right, Rails has a collection of directories similar to `$LOAD_PATH` in which
-to look up `post.rb`. That collection is called `autoload_paths` and by
-default it contains:
-
-* All subdirectories of `app` in the application and engines present at boot
- time. For example, `app/controllers`. They do not need to be the default
- ones, any custom directories like `app/workers` belong automatically to
- `autoload_paths`.
+That may speed legit `require` calls a bit, since there are less lookups. Also, if your application uses [Bootsnap](https://github.com/Shopify/bootsnap), that saves the library from building unnecessary indexes, and saves the RAM they would need.
-* Any existing second level directories called `app/*/concerns` in the
- application and engines.
-* The directory `test/mailers/previews`.
+Reloading
+---------
-`eager_load_paths` is initially the `app` paths above
+Rails automatically reloads classes and modules if application files change.
-How files are autoloaded depends on `eager_load` and `cache_classes` config settings which typically vary in development, production, and test modes:
+More precisely, if the web server is running and application files have been modified, Rails unloads all autoloaded constants just before the next request is processed. That way, application classes or modules used during that request are going to be autoloaded, thus picking up their current implementation in the file system.
- * In **development**, you want quicker startup with incremental loading of application code. So `eager_load` should be set to `false`, and Rails will autoload files as needed (see [Autoloading Algorithms](#autoloading-algorithms) below) -- and then reload them when they change (see [Constant Reloading](#constant-reloading) below).
- * In **production**, however, you want consistency and thread-safety and can live with a longer boot time. So `eager_load` is set to `true`, and then during boot (before the app is ready to receive requests) Rails loads all files in the `eager_load_paths` and then turns off auto loading (NB: autoloading may be needed during eager loading). Not autoloading after boot is a `good thing`, as autoloading can cause the app to be have thread-safety problems.
- * In **test**, for speed of execution (of individual tests) `eager_load` is `false`, so Rails follows development behaviour.
+Reloading can be enabled or disabled. The setting that controls this behavior is `config.cache_classes`, which is false by default in `development` mode (reloading enabled), and true by default in `production` mode (reloading disabled).
-What is described above are the defaults with a newly generated Rails app. There are multiple ways this can be configured differently (see [Configuring Rails Applications](configuring.html#rails-general-configuration).
-). But using `autoload_paths` on its own in the past (before Rails 5) developers might configure `autoload_paths` to add in extra locations (e.g. `lib` which used to be an autoload path list years ago, but no longer is). However this is now discouraged for most purposes, as it is likely to lead to production-only errors. It is possible to add new locations to both `config.eager_load_paths` and `config.autoload_paths` but use at your own risk.
+Rails detects files have changed using an evented file monitor (default), or walking the autoload paths, depending on `config.file_watcher`.
-See also [Autoloading in the Test Environment](#autoloading-in-the-test-environment).
+In a Rails console there is no file watcher active regardless of the value of `config.cache_classes`. This is so because, normally, it would be confusing to have code reloaded in the middle of a console session, the same way you generally want an individual request to be served by a consistent, non-changing set of application classes and modules.
-`config.autoload_paths` is not changeable from environment-specific configuration files.
-
-The value of `autoload_paths` can be inspected. In a just-generated application
-it is (edited):
+However, you can force a reload in the console executing `reload!`:
```
-$ rails r 'puts ActiveSupport::Dependencies.autoload_paths'
-.../app/assets
-.../app/channels
-.../app/controllers
-.../app/controllers/concerns
-.../app/helpers
-.../app/jobs
-.../app/mailers
-.../app/models
-.../app/models/concerns
-.../activestorage/app/assets
-.../activestorage/app/controllers
-.../activestorage/app/javascript
-.../activestorage/app/jobs
-.../activestorage/app/models
-.../actioncable/app/assets
-.../actionview/app/assets
-.../test/mailers/previews
+$ bin/rails c
+Loading development environment (Rails 6.0.0)
+irb(main):001:0> User.object_id
+=> 70136277390120
+irb(main):002:0> reload!
+Reloading...
+=> true
+irb(main):003:0> User.object_id
+=> 70136284426020
```
-INFO. `autoload_paths` is computed and cached during the initialization process.
-The application needs to be restarted to reflect any changes in the directory
-structure.
+as you can see, the class object stored in the `User` constant is different after reloading.
+### Reloading and Stale Objects
-Autoloading Algorithms
-----------------------
+It is very important to understand that Ruby does not have a way to truly reload classes and modules in memory, and have that reflected everywhere they are already used. Technically, "unloading" the `User` class means removing the `User` constant via `Object.send(:remove_const, "User")`.
-### Relative References
+Therefore, if you store a reloadable class or module object in a place that is not reloaded, that value is going to become stale.
-A relative constant reference may appear in several places, for example, in
+For example, if an initializer stores and caches a certain class object
```ruby
-class PostsController < ApplicationController
- def index
- @posts = Post.all
- end
-end
+# config/initializers/configure_payment_gateway.rb
+# DO NOT DO THIS.
+$PAYMENT_GATEWAY = Rails.env.production? ? RealGateway : MockedGateway
+# DO NOT DO THIS.
```
-all three constant references are relative.
-
-#### Constants after the `class` and `module` Keywords
-
-Ruby performs a lookup for the constant that follows a `class` or `module`
-keyword because it needs to know if the class or module is going to be created
-or reopened.
-
-If the constant is not defined at that point it is not considered to be a
-missing constant, autoloading is **not** triggered.
-
-So, in the previous example, if `PostsController` is not defined when the file
-is interpreted Rails autoloading is not going to be triggered, Ruby will just
-define the controller.
-
-#### Top-Level Constants
-
-On the contrary, if `ApplicationController` is unknown, the constant is
-considered missing and an autoload is going to be attempted by Rails.
-
-In order to load `ApplicationController`, Rails iterates over `autoload_paths`.
-First it checks if `app/assets/application_controller.rb` exists. If it does not,
-which is normally the case, it continues and finds
-`app/controllers/application_controller.rb`.
+and `MockedGateway` gets reloaded, `$PAYMENT_GATEWAY` still stores the class object `MockedGateway` evaluated to when the initializer ran. Reloading does not change the class object stored in `$PAYMENT_GATEWAY`.
-If the file defines the constant `ApplicationController` all is fine, otherwise
-`LoadError` is raised:
+Similarly, in the Rails console, if you have a user instance and reload:
```
-unable to autoload constant ApplicationController, expected
-<full path to application_controller.rb> to define it (LoadError)
+> user = User.new
+> reload!
```
-INFO. Rails does not require the value of autoloaded constants to be a class or
-module object. For example, if the file `app/models/max_clients.rb` defines
-`MAX_CLIENTS = 100` autoloading `MAX_CLIENTS` works just fine.
-
-#### Namespaces
+the `user` object is instance of a stale class object. Ruby gives you a new class if you evaluate `User` again, but does not update the class `user` is instance of.
-Autoloading `ApplicationController` looks directly under the directories of
-`autoload_paths` because the nesting in that spot is empty. The situation of
-`Post` is different, the nesting in that line is `[PostsController]` and support
-for namespaces comes into play.
-
-The basic idea is that given
+Another use case of this gotcha is subclassing reloadable classes in a place that is not reloaded:
```ruby
-module Admin
- class BaseController < ApplicationController
- @@all_roles = Role.all
- end
+# lib/vip_user.rb
+class VipUser < User
end
```
-to autoload `Role` we are going to check if it is defined in the current or
-parent namespaces, one at a time. So, conceptually we want to try to autoload
-any of
-
-```
-Admin::BaseController::Role
-Admin::Role
-Role
-```
-
-in that order. That's the idea. To do so, Rails looks in `autoload_paths`
-respectively for file names like these:
-
-```
-admin/base_controller/role.rb
-admin/role.rb
-role.rb
-```
-
-modulus some additional directory lookups we are going to cover soon.
-
-INFO. `'Constant::Name'.underscore` gives the relative path without extension of
-the file name where `Constant::Name` is expected to be defined.
-
-Let's see how Rails autoloads the `Post` constant in the `PostsController`
-above assuming the application has a `Post` model defined in
-`app/models/post.rb`.
-
-First it checks for `posts_controller/post.rb` in `autoload_paths`:
-
-```
-app/assets/posts_controller/post.rb
-app/controllers/posts_controller/post.rb
-app/helpers/posts_controller/post.rb
-...
-test/mailers/previews/posts_controller/post.rb
-```
-
-Since the lookup is exhausted without success, a similar search for a directory
-is performed, we are going to see why in the [next section](#automatic-modules):
+if `User` is reloaded, since `VipUser` is not, the superclass of `VipUser` is the original stale class object.
-```
-app/assets/posts_controller/post
-app/controllers/posts_controller/post
-app/helpers/posts_controller/post
-...
-test/mailers/previews/posts_controller/post
-```
+Bottom line: **do not cache reloadable classes or modules**.
-If all those attempts fail, then Rails starts the lookup again in the parent
-namespace. In this case only the top-level remains:
-```
-app/assets/post.rb
-app/controllers/post.rb
-app/helpers/post.rb
-app/mailers/post.rb
-app/models/post.rb
-```
+Eager Loading
+-------------
-A matching file is found in `app/models/post.rb`. The lookup stops there and the
-file is loaded. If the file actually defines `Post` all is fine, otherwise
-`LoadError` is raised.
+In production-like environments it is generally better to load all the application code when the application boots. Eager loading puts everything in memory ready to serve requests right away, and it is also [CoW](https://en.wikipedia.org/wiki/Copy-on-write)-friendly.
-### Qualified References
+Eager loading is controlled by the flag `config.eager_load`, which is enabled by default in `production` mode.
-When a qualified constant is missing Rails does not look for it in the parent
-namespaces. But there is a caveat: when a constant is missing, Rails is
-unable to tell if the trigger was a relative reference or a qualified one.
+The order in which files are eager loaded is undefined.
-For example, consider
+if the `Zeitwerk` constant is defined, Rails invokes `Zeitwerk::Loader.eager_load_all` regardless of the application autoloading mode. That ensures dependencies managed by Zeitwerk are eager loaded.
-```ruby
-module Admin
- User
-end
-```
-and
-
-```ruby
-Admin::User
-```
-
-If `User` is missing, in either case all Rails knows is that a constant called
-"User" was missing in a module called "Admin".
+Single Table Inheritance
+------------------------
-If there is a top-level `User` Ruby would resolve it in the former example, but
-wouldn't in the latter. In general, Rails does not emulate the Ruby constant
-resolution algorithms, but in this case it tries using the following heuristic:
+Single Table Inheritance is a feature that doesn't play well with lazy loading. Reason is, its API generally needs to be able to enumerate the STI hierarchy to work correctly, whereas lazy loading defers loading classes until they are referenced. You can't enumerate what you haven't referenced yet.
-> If none of the parent namespaces of the class or module has the missing
-> constant then Rails assumes the reference is relative. Otherwise qualified.
+In a sense, applications need to eager load STI hierarchies regardless of the loading mode.
-For example, if this code triggers autoloading
+Of course, if the application eager loads on boot, that is already accomplished. When it does not, it is in practice enough to instantiate the existing types in the database, which in development or test modes is usually fine. One way to do that is to throw this module into the `lib` directory:
```ruby
-Admin::User
-```
-
-and the `User` constant is already present in `Object`, it is not possible that
-the situation is
-
-```ruby
-module Admin
- User
-end
-```
-
-because otherwise Ruby would have resolved `User` and no autoloading would have
-been triggered in the first place. Thus, Rails assumes a qualified reference and
-considers the file `admin/user.rb` and directory `admin/user` to be the only
-valid options.
-
-In practice, this works quite well as long as the nesting matches all parent
-namespaces respectively and the constants that make the rule apply are known at
-that time.
-
-However, autoloading happens on demand. If by chance the top-level `User` was
-not yet loaded, then Rails assumes a relative reference by contract.
-
-Naming conflicts of this kind are rare in practice, but if one occurs,
-`require_dependency` provides a solution by ensuring that the constant needed
-to trigger the heuristic is defined in the conflicting place.
-
-### Automatic Modules
-
-When a module acts as a namespace, Rails does not require the application to
-define a file for it, a directory matching the namespace is enough.
+module StiPreload
+ unless Rails.application.config.eager_load
+ extend ActiveSupport::Concern
-Suppose an application has a back office whose controllers are stored in
-`app/controllers/admin`. If the `Admin` module is not yet loaded when
-`Admin::UsersController` is hit, Rails needs first to autoload the constant
-`Admin`.
-
-If `autoload_paths` has a file called `admin.rb` Rails is going to load that
-one, but if there's no such file and a directory called `admin` is found, Rails
-creates an empty module and assigns it to the `Admin` constant on the fly.
-
-### Generic Procedure
-
-Relative references are reported to be missing in the cref where they were hit,
-and qualified references are reported to be missing in their parent (see
-[Resolution Algorithm for Relative
-Constants](#resolution-algorithm-for-relative-constants) at the beginning of
-this guide for the definition of *cref*, and [Resolution Algorithm for Qualified
-Constants](#resolution-algorithm-for-qualified-constants) for the definition of
-*parent*).
-
-The procedure to autoload constant `C` in an arbitrary situation is as follows:
-
-```
-if the class or module in which C is missing is Object
- let ns = ''
-else
- let M = the class or module in which C is missing
-
- if M is anonymous
- let ns = ''
- else
- let ns = M.name
- end
-end
-
-loop do
- # Look for a regular file.
- for dir in autoload_paths
- if the file "#{dir}/#{ns.underscore}/c.rb" exists
- load/require "#{dir}/#{ns.underscore}/c.rb"
-
- if C is now defined
- return
- else
- raise LoadError
- end
+ included do
+ cattr_accessor :preloaded, instance_accessor: false
end
- end
- # Look for an automatic module.
- for dir in autoload_paths
- if the directory "#{dir}/#{ns.underscore}/c" exists
- if ns is an empty string
- let C = Module.new in Object and return
- else
- let C = Module.new in ns.constantize and return
+ class_methods do
+ def descendants
+ preload_sti unless preloaded
+ super
end
- end
- end
-
- if ns is empty
- # We reached the top-level without finding the constant.
- raise NameError
- else
- if C exists in any of the parent namespaces
- # Qualified constants heuristic.
- raise NameError
- else
- # Try again in the parent namespace.
- let ns = the parent namespace of ns and retry
- end
- end
-end
-```
-
-
-require_dependency
-------------------
-
-Constant autoloading is triggered on demand and therefore code that uses a
-certain constant may have it already defined or may trigger an autoload. That
-depends on the execution path and it may vary between runs.
-
-There are times, however, in which you want to make sure a certain constant is
-known when the execution reaches some code. `require_dependency` provides a way
-to load a file using the current [loading mechanism](#loading-mechanism), and
-keeping track of constants defined in that file as if they were autoloaded to
-have them reloaded as needed.
-
-`require_dependency` is rarely needed, but see a couple of use cases in
-[Autoloading and STI](#autoloading-and-sti) and [When Constants aren't
-Triggered](#when-constants-aren-t-missed).
-
-WARNING. Unlike autoloading, `require_dependency` does not expect the file to
-define any particular constant. Exploiting this behavior would be a bad practice
-though, file and constant paths should match.
-
-
-Constant Reloading
-------------------
-
-When `config.cache_classes` is false Rails is able to reload autoloaded
-constants.
-For example, if you're in a console session and edit some file behind the
-scenes, the code can be reloaded with the `reload!` command:
-
-```
-> reload!
-```
-
-When the application runs, code is reloaded when something relevant to this
-logic changes. In order to do that, Rails monitors a number of things:
-
-* `config/routes.rb`.
-
-* Locales.
-
-* Ruby files under `autoload_paths`.
-
-* `db/schema.rb` and `db/structure.sql`.
-
-If anything in there changes, there is a middleware that detects it and reloads
-the code.
-
-Autoloading keeps track of autoloaded constants. Reloading is implemented by
-removing them all from their respective classes and modules using
-`Module#remove_const`. That way, when the code goes on, those constants are
-going to be unknown again, and files reloaded on demand.
-
-INFO. This is an all-or-nothing operation, Rails does not attempt to reload only
-what changed since dependencies between classes makes that really tricky.
-Instead, everything is wiped.
-
-
-Module#autoload isn't Involved
-------------------------------
-
-`Module#autoload` provides a lazy way to load constants that is fully integrated
-with the Ruby constant lookup algorithms, dynamic constant API, etc. It is quite
-transparent.
-
-Rails internals make extensive use of it to defer as much work as possible from
-the boot process. But constant autoloading in Rails is **not** implemented with
-`Module#autoload`.
-
-One possible implementation based on `Module#autoload` would be to walk the
-application tree and issue `autoload` calls that map existing file names to
-their conventional constant name.
-
-There are a number of reasons that prevent Rails from using that implementation.
-
-For example, `Module#autoload` is only capable of loading files using `require`,
-so reloading would not be possible. Not only that, it uses an internal `require`
-which is not `Kernel#require`.
-
-Then, it provides no way to remove declarations in case a file is deleted. If a
-constant gets removed with `Module#remove_const` its `autoload` is not triggered
-again. Also, it doesn't support qualified names, so files with namespaces should
-be interpreted during the walk tree to install their own `autoload` calls, but
-those files could have constant references not yet configured.
-
-An implementation based on `Module#autoload` would be awesome but, as you see,
-at least as of today it is not possible. Constant autoloading in Rails is
-implemented with `Module#const_missing`, and that's why it has its own contract,
-documented in this guide.
-
-
-Common Gotchas
---------------
-
-### Nesting and Qualified Constants
-
-Let's consider
-
-```ruby
-module Admin
- class UsersController < ApplicationController
- def index
- @users = User.all
+ # Constantizes all types present in the database. There might be more on
+ # disk, but that does not matter in practice as far as the STI API is
+ # concerned.
+ #
+ # Assumes store_full_sti_class is true, the default.
+ def preload_sti
+ types_in_db = \
+ base_class.
+ select(inheritance_column).
+ distinct.
+ pluck(inheritance_column).
+ compact.
+ each(&:constantize)
+
+ types_in_db.each do |type|
+ logger.debug("Preloading STI type #{type}")
+ type.constantize
+ end
+
+ self.preloaded = true
+ end
end
end
end
```
-and
+and then include it in the STI root classes of your project:
```ruby
-class Admin::UsersController < ApplicationController
- def index
- @users = User.all
- end
-end
-```
-
-To resolve `User` Ruby checks `Admin` in the former case, but it does not in
-the latter because it does not belong to the nesting (see [Nesting](#nesting)
-and [Resolution Algorithms](#resolution-algorithms)).
-
-Unfortunately Rails autoloading does not know the nesting in the spot where the
-constant was missing and so it is not able to act as Ruby would. In particular,
-`Admin::User` will get autoloaded in either case.
-
-Albeit qualified constants with `class` and `module` keywords may technically
-work with autoloading in some cases, it is preferable to use relative constants
-instead:
+# app/models/shape.rb
+require "sti_preload"
-```ruby
-module Admin
- class UsersController < ApplicationController
- def index
- @users = User.all
- end
- end
+class Shape < ApplicationRecord
+ include StiPreload # Only in the root class.
end
-```
-### Autoloading and STI
-
-Single Table Inheritance (STI) is a feature of Active Record that enables
-storing a hierarchy of models in one single table. The API of such models is
-aware of the hierarchy and encapsulates some common needs. For example, given
-these classes:
-
-```ruby
# app/models/polygon.rb
-class Polygon < ApplicationRecord
+class Polygon < Shape
end
# app/models/triangle.rb
class Triangle < Polygon
end
-
-# app/models/rectangle.rb
-class Rectangle < Polygon
-end
-```
-
-`Triangle.create` creates a row that represents a triangle, and
-`Rectangle.create` creates a row that represents a rectangle. If `id` is the
-ID of an existing record, `Polygon.find(id)` returns an object of the correct
-type.
-
-Methods that operate on collections are also aware of the hierarchy. For
-example, `Polygon.all` returns all the records of the table, because all
-rectangles and triangles are polygons. Active Record takes care of returning
-instances of their corresponding class in the result set.
-
-Types are autoloaded as needed. For example, if `Polygon.first` is a rectangle
-and `Rectangle` has not yet been loaded, Active Record autoloads it and the
-record is correctly instantiated.
-
-All good, but if instead of performing queries based on the root class we need
-to work on some subclass, things get interesting.
-
-While working with `Polygon` you do not need to be aware of all its descendants,
-because anything in the table is by definition a polygon, but when working with
-subclasses Active Record needs to be able to enumerate the types it is looking
-for. Let's see an example.
-
-`Rectangle.all` only loads rectangles by adding a type constraint to the query:
-
-```sql
-SELECT "polygons".* FROM "polygons"
-WHERE "polygons"."type" IN ("Rectangle")
-```
-
-Let's introduce now a subclass of `Rectangle`:
-
-```ruby
-# app/models/square.rb
-class Square < Rectangle
-end
-```
-
-`Rectangle.all` should now return rectangles **and** squares:
-
-```sql
-SELECT "polygons".* FROM "polygons"
-WHERE "polygons"."type" IN ("Rectangle", "Square")
-```
-
-But there's a caveat here: How does Active Record know that the class `Square`
-exists at all?
-
-Even if the file `app/models/square.rb` exists and defines the `Square` class,
-if no code yet used that class, `Rectangle.all` issues the query
-
-```sql
-SELECT "polygons".* FROM "polygons"
-WHERE "polygons"."type" IN ("Rectangle")
-```
-
-That is not a bug, the query includes all *known* descendants of `Rectangle`.
-
-A way to ensure this works correctly regardless of the order of execution is to
-manually load the direct subclasses at the bottom of the file that defines each
-intermediate class:
-
-```ruby
-# app/models/rectangle.rb
-class Rectangle < Polygon
-end
-require_dependency 'square'
-```
-
-This needs to happen for every intermediate (non-root and non-leaf) class. The
-root class does not scope the query by type, and therefore does not necessarily
-have to know all its descendants.
-
-### Autoloading and `require`
-
-Files defining constants to be autoloaded should never be `require`d:
-
-```ruby
-require 'user' # DO NOT DO THIS
-
-class UsersController < ApplicationController
- ...
-end
-```
-
-There are two possible gotchas here in development mode:
-
-1. If `User` is autoloaded before reaching the `require`, `app/models/user.rb`
-runs again because `load` does not update `$LOADED_FEATURES`.
-
-2. If the `require` runs first Rails does not mark `User` as an autoloaded
-constant and changes to `app/models/user.rb` aren't reloaded.
-
-Just follow the flow and use constant autoloading always, never mix
-autoloading and `require`. As a last resort, if some file absolutely needs to
-load a certain file use `require_dependency` to play nice with constant
-autoloading. This option is rarely needed in practice, though.
-
-Of course, using `require` in autoloaded files to load ordinary 3rd party
-libraries is fine, and Rails is able to distinguish their constants, they are
-not marked as autoloaded.
-
-### Autoloading and Initializers
-
-Consider this assignment in `config/initializers/set_auth_service.rb`:
-
-```ruby
-AUTH_SERVICE = if Rails.env.production?
- RealAuthService
-else
- MockedAuthService
-end
-```
-
-The purpose of this setup would be that the application uses the class that
-corresponds to the environment via `AUTH_SERVICE`. In development mode
-`MockedAuthService` gets autoloaded when the initializer runs. Let's suppose
-we do some requests, change its implementation, and hit the application again.
-To our surprise the changes are not reflected. Why?
-
-As [we saw earlier](#constant-reloading), Rails removes autoloaded constants,
-but `AUTH_SERVICE` stores the original class object. Stale, non-reachable
-using the original constant, but perfectly functional.
-
-The following code summarizes the situation:
-
-```ruby
-class C
- def quack
- 'quack!'
- end
-end
-
-X = C
-Object.instance_eval { remove_const(:C) }
-X.new.quack # => quack!
-X.name # => C
-C # => uninitialized constant C (NameError)
-```
-
-Because of that, it is not a good idea to autoload constants on application
-initialization.
-
-In the case above we could implement a dynamic access point:
-
-```ruby
-# app/models/auth_service.rb
-class AuthService
- if Rails.env.production?
- def self.instance
- RealAuthService
- end
- else
- def self.instance
- MockedAuthService
- end
- end
-end
-```
-
-and have the application use `AuthService.instance` instead. `AuthService`
-would be loaded on demand and be autoload-friendly.
-
-### `require_dependency` and Initializers
-
-As we saw before, `require_dependency` loads files in an autoloading-friendly
-way. Normally, though, such a call does not make sense in an initializer.
-
-One could think about doing some [`require_dependency`](#require-dependency)
-calls in an initializer to make sure certain constants are loaded upfront, for
-example as an attempt to address the [gotcha with STIs](#autoloading-and-sti).
-
-Problem is, in development mode [autoloaded constants are wiped](#constant-reloading)
-if there is any relevant change in the file system. If that happens then
-we are in the very same situation the initializer wanted to avoid!
-
-Calls to `require_dependency` have to be strategically written in autoloaded
-spots.
-
-### When Constants aren't Missed
-
-#### Relative References
-
-Let's consider a flight simulator. The application has a default flight model
-
-```ruby
-# app/models/flight_model.rb
-class FlightModel
-end
-```
-
-that can be overridden by each airplane, for instance
-
-```ruby
-# app/models/bell_x1/flight_model.rb
-module BellX1
- class FlightModel < FlightModel
- end
-end
-
-# app/models/bell_x1/aircraft.rb
-module BellX1
- class Aircraft
- def initialize
- @flight_model = FlightModel.new
- end
- end
-end
-```
-
-The initializer wants to create a `BellX1::FlightModel` and nesting has
-`BellX1`, that looks good. But if the default flight model is loaded and the
-one for the Bell-X1 is not, the interpreter is able to resolve the top-level
-`FlightModel` and autoloading is thus not triggered for `BellX1::FlightModel`.
-
-That code depends on the execution path.
-
-These kind of ambiguities can often be resolved using qualified constants:
-
-```ruby
-module BellX1
- class Plane
- def flight_model
- @flight_model ||= BellX1::FlightModel.new
- end
- end
-end
-```
-
-Also, `require_dependency` is a solution:
-
-```ruby
-require_dependency 'bell_x1/flight_model'
-
-module BellX1
- class Plane
- def flight_model
- @flight_model ||= FlightModel.new
- end
- end
-end
-```
-
-#### Qualified References
-
-WARNING. This gotcha is only possible in Ruby < 2.5.
-
-Given
-
-```ruby
-# app/models/hotel.rb
-class Hotel
-end
-
-# app/models/image.rb
-class Image
-end
-
-# app/models/hotel/image.rb
-class Hotel
- class Image < Image
- end
-end
-```
-
-the expression `Hotel::Image` is ambiguous because it depends on the execution
-path.
-
-As [we saw before](#resolution-algorithm-for-qualified-constants), Ruby looks
-up the constant in `Hotel` and its ancestors. If `app/models/image.rb` has
-been loaded but `app/models/hotel/image.rb` hasn't, Ruby does not find `Image`
-in `Hotel`, but it does in `Object`:
-
-```
-$ rails r 'Image; p Hotel::Image' 2>/dev/null
-Image # NOT Hotel::Image!
-```
-
-The code evaluating `Hotel::Image` needs to make sure
-`app/models/hotel/image.rb` has been loaded, possibly with
-`require_dependency`.
-
-In these cases the interpreter issues a warning though:
-
-```
-warning: toplevel constant Image referenced by Hotel::Image
-```
-
-This surprising constant resolution can be observed with any qualifying class:
-
-```
-2.1.5 :001 > String::Array
-(irb):1: warning: toplevel constant Array referenced by String::Array
- => Array
-```
-
-WARNING. To find this gotcha the qualifying namespace has to be a class,
-`Object` is not an ancestor of modules.
-
-### Autoloading within Singleton Classes
-
-Let's suppose we have these class definitions:
-
-```ruby
-# app/models/hotel/services.rb
-module Hotel
- class Services
- end
-end
-
-# app/models/hotel/geo_location.rb
-module Hotel
- class GeoLocation
- class << self
- Services
- end
- end
-end
```
-If `Hotel::Services` is known by the time `app/models/hotel/geo_location.rb`
-is being loaded, `Services` is resolved by Ruby because `Hotel` belongs to the
-nesting when the singleton class of `Hotel::GeoLocation` is opened.
+Rails.autoloaders
+-----------------
-But if `Hotel::Services` is not known, Rails is not able to autoload it, the
-application raises `NameError`.
-
-The reason is that autoloading is triggered for the singleton class, which is
-anonymous, and as [we saw before](#generic-procedure), Rails only checks the
-top-level namespace in that edge case.
-
-An easy solution to this caveat is to qualify the constant:
+The Zeitwerk instances managing your application are availabe at
```ruby
-module Hotel
- class GeoLocation
- class << self
- Hotel::Services
- end
- end
-end
+Rails.autoloaders.main
+Rails.autoloaders.once
```
-### Autoloading in `BasicObject`
-
-Direct descendants of `BasicObject` do not have `Object` among their ancestors
-and cannot resolve top-level constants:
-
-```ruby
-class C < BasicObject
- String # NameError: uninitialized constant C::String
-end
-```
+The former is the main one. The latter is there mostly for backwards compatibily reasons, in case the application has something in `config.autoload_once_paths` (this is discouraged nowadays).
-When autoloading is involved that plot has a twist. Let's consider:
+You can check if `zeitwerk` mode is enabled with
```ruby
-class C < BasicObject
- def user
- User # WRONG
- end
-end
+Rails.autoloaders.zeitwerk_enabled?
```
-Since Rails checks the top-level namespace `User` gets autoloaded just fine the
-first time the `user` method is invoked. You only get the exception if the
-`User` constant is known at that point, in particular in a *second* call to
-`user`:
-
-```ruby
-c = C.new
-c.user # surprisingly fine, User
-c.user # NameError: uninitialized constant C::User
-```
-
-because it detects that a parent namespace already has the constant (see [Qualified
-References](#autoloading-algorithms-qualified-references)).
-
-As with pure Ruby, within the body of a direct descendant of `BasicObject` use
-always absolute constant paths:
-
-```ruby
-class C < BasicObject
- ::String # RIGHT
-
- def user
- ::User # RIGHT
- end
-end
-```
-
-### Autoloading in the Test Environment
-
-When configuring the `test` environment for autoloading you might consider multiple factors.
-
-For example it might be worth running your tests with an identical setup to production (`config.eager_load = true`, `config.cache_classes = true`) in order to catch any problems before they hit production (this is compensation for the lack of dev-prod parity). However this will slow down the boot time for individual tests on a dev machine (and is not immediately compatible with spring see below). So one possibility is to do this on a
-[CI](https://en.wikipedia.org/wiki/Continuous_integration) machine only (which should run without spring).
-
-On a development machine you can then have your tests running with whatever is fastest (ideally `config.eager_load = false`).
-
-With the [Spring](https://github.com/rails/spring) pre-loader (included with new Rails apps), you ideally keep `config.eager_load = false` as per development. Sometimes you may end up with a hybrid configuration (`config.eager_load = true`, `config.cache_classes = true` AND `config.enable_dependency_loading = true`), see [spring issue](https://github.com/rails/spring/issues/519#issuecomment-348324369). However it might be simpler to keep the same configuration as development, and work out whatever it is that is causing autoloading to fail (perhaps by the results of your CI test results).
-
-Occasionally you may need to explicitly eager_load by using `Rails
-.application.eager_load!` in the setup of your tests -- this might occur if your [tests involve multithreading](https://stackoverflow.com/questions/25796409/in-rails-how-can-i-eager-load-all-code-before-a-specific-rspec-test).
-
-## Troubleshooting
-
-### Tracing Autoloads
-
-Active Support is able to report constants as they are autoloaded. To enable these traces in a Rails application, put the following two lines in some initializer:
-
-```ruby
-ActiveSupport::Dependencies.logger = Rails.logger
-ActiveSupport::Dependencies.verbose = true
-```
-
-### Where is a Given Autoload Triggered?
+Opting Out
+----------
-If constant `Foo` is being autoloaded, and you'd like to know where is that autoload coming from, just throw
+Applications can load Rails 6 defaults and still use the classic autoloader this way:
```ruby
-puts caller
+# config/application.rb
+config.load_defaults "6.x"
+config.autoloader = :classic
```
-at the top of `foo.rb` and inspect the printed stack trace.
-
-### Which Constants Have Been Autoloaded?
-
-At any given time,
-
-```ruby
-ActiveSupport::Dependencies.autoloaded_constants
-```
+That may be handy if upgrading to Rails 6 in different phases, but classic mode is discouraged for new applications.
-has the collection of constants that have been autoloaded so far.
+`zeitwerk` mode is not available in versions of Rails previous to 6.0.
diff --git a/guides/source/autoloading_and_reloading_constants_classic_mode.md b/guides/source/autoloading_and_reloading_constants_classic_mode.md
new file mode 100644
index 0000000000..d0d9e076d6
--- /dev/null
+++ b/guides/source/autoloading_and_reloading_constants_classic_mode.md
@@ -0,0 +1,1351 @@
+**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.**
+
+Autoloading and Reloading Constants (Classic Mode)
+==================================================
+
+This guide documents how constant autoloading and reloading works in `classic` mode.
+
+After reading this guide, you will know:
+
+* Key aspects of Ruby constants
+* What are the `autoload_paths` and how does eager loading work in production?
+* How constant autoloading works
+* What is `require_dependency`
+* How constant reloading works
+* Solutions to common autoloading gotchas
+
+--------------------------------------------------------------------------------
+
+
+Introduction
+------------
+
+INFO. This guide documents autoloading in `classic` mode, which is the traditional one. If you'd like to read about `zeiwerk` mode instead, the new one in Rails 6, please check [Autoloading and Reloading Constants (Zeitwerk Mode)](autoloading_and_reloading_constants.html).
+
+Ruby on Rails allows applications to be written as if their code was preloaded.
+
+In a normal Ruby program classes need to load their dependencies:
+
+```ruby
+require 'application_controller'
+require 'post'
+
+class PostsController < ApplicationController
+ def index
+ @posts = Post.all
+ end
+end
+```
+
+Our Rubyist instinct quickly sees some redundancy in there: If classes were
+defined in files matching their name, couldn't their loading be automated
+somehow? We could save scanning the file for dependencies, which is brittle.
+
+Moreover, `Kernel#require` loads files once, but development is much more smooth
+if code gets refreshed when it changes without restarting the server. It would
+be nice to be able to use `Kernel#load` in development, and `Kernel#require` in
+production.
+
+Indeed, those features are provided by Ruby on Rails, where we just write
+
+```ruby
+class PostsController < ApplicationController
+ def index
+ @posts = Post.all
+ end
+end
+```
+
+This guide documents how that works.
+
+
+Constants Refresher
+-------------------
+
+While constants are trivial in most programming languages, they are a rich
+topic in Ruby.
+
+It is beyond the scope of this guide to document Ruby constants, but we are
+nevertheless going to highlight a few key topics. Truly grasping the following
+sections is instrumental to understanding constant autoloading and reloading.
+
+### Nesting
+
+Class and module definitions can be nested to create namespaces:
+
+```ruby
+module XML
+ class SAXParser
+ # (1)
+ end
+end
+```
+
+The *nesting* at any given place is the collection of enclosing nested class and
+module objects outwards. The nesting at any given place can be inspected with
+`Module.nesting`. For example, in the previous example, the nesting at
+(1) is
+
+```ruby
+[XML::SAXParser, XML]
+```
+
+It is important to understand that the nesting is composed of class and module
+*objects*, it has nothing to do with the constants used to access them, and is
+also unrelated to their names.
+
+For instance, while this definition is similar to the previous one:
+
+```ruby
+class XML::SAXParser
+ # (2)
+end
+```
+
+the nesting in (2) is different:
+
+```ruby
+[XML::SAXParser]
+```
+
+`XML` does not belong to it.
+
+We can see in this example that the name of a class or module that belongs to a
+certain nesting does not necessarily correlate with the namespaces at the spot.
+
+Even more, they are totally independent, take for instance
+
+```ruby
+module X
+ module Y
+ end
+end
+
+module A
+ module B
+ end
+end
+
+module X::Y
+ module A::B
+ # (3)
+ end
+end
+```
+
+The nesting in (3) consists of two module objects:
+
+```ruby
+[A::B, X::Y]
+```
+
+So, it not only doesn't end in `A`, which does not even belong to the nesting,
+but it also contains `X::Y`, which is independent from `A::B`.
+
+The nesting is an internal stack maintained by the interpreter, and it gets
+modified according to these rules:
+
+* The class object following a `class` keyword gets pushed when its body is
+executed, and popped after it.
+
+* The module object following a `module` keyword gets pushed when its body is
+executed, and popped after it.
+
+* A singleton class opened with `class << object` gets pushed, and popped later.
+
+* When `instance_eval` is called using a string argument,
+the singleton class of the receiver is pushed to the nesting of the eval'ed
+code. When `class_eval` or `module_eval` is called using a string argument,
+the receiver is pushed to the nesting of the eval'ed code.
+
+* The nesting at the top-level of code interpreted by `Kernel#load` is empty
+unless the `load` call receives a true value as second argument, in which case
+a newly created anonymous module is pushed by Ruby.
+
+It is interesting to observe that blocks do not modify the stack. In particular
+the blocks that may be passed to `Class.new` and `Module.new` do not get the
+class or module being defined pushed to their nesting. That's one of the
+differences between defining classes and modules in one way or another.
+
+### Class and Module Definitions are Constant Assignments
+
+Let's suppose the following snippet creates a class (rather than reopening it):
+
+```ruby
+class C
+end
+```
+
+Ruby creates a constant `C` in `Object` and stores in that constant a class
+object. The name of the class instance is "C", a string, named after the
+constant.
+
+That is,
+
+```ruby
+class Project < ApplicationRecord
+end
+```
+
+performs a constant assignment equivalent to
+
+```ruby
+Project = Class.new(ApplicationRecord)
+```
+
+including setting the name of the class as a side-effect:
+
+```ruby
+Project.name # => "Project"
+```
+
+Constant assignment has a special rule to make that happen: if the object
+being assigned is an anonymous class or module, Ruby sets the object's name to
+the name of the constant.
+
+INFO. From then on, what happens to the constant and the instance does not
+matter. For example, the constant could be deleted, the class object could be
+assigned to a different constant, be stored in no constant anymore, etc. Once
+the name is set, it doesn't change.
+
+Similarly, module creation using the `module` keyword as in
+
+```ruby
+module Admin
+end
+```
+
+performs a constant assignment equivalent to
+
+```ruby
+Admin = Module.new
+```
+
+including setting the name as a side-effect:
+
+```ruby
+Admin.name # => "Admin"
+```
+
+WARNING. The execution context of a block passed to `Class.new` or `Module.new`
+is not entirely equivalent to the one of the body of the definitions using the
+`class` and `module` keywords. But both idioms result in the same constant
+assignment.
+
+Thus, an informal expression like "the `String` class" technically means the
+class object stored in the constant called "String". That constant, in turn,
+belongs to the class object stored in the constant called "Object".
+
+`String` is an ordinary constant, and everything related to them such as
+resolution algorithms applies to it.
+
+Likewise, in the controller
+
+```ruby
+class PostsController < ApplicationController
+ def index
+ @posts = Post.all
+ end
+end
+```
+
+`Post` is not syntax for a class. Rather, `Post` is a regular Ruby constant. If
+all is good, the constant is evaluated to an object that responds to `all`.
+
+That is why we talk about *constant* autoloading, Rails has the ability to
+load constants on the fly.
+
+### Constants are Stored in Modules
+
+Constants belong to modules in a very literal sense. Classes and modules have
+a constant table; think of it as a hash table.
+
+Let's analyze an example to really understand what that means. While common
+abuses of language like "the `String` class" are convenient, the exposition is
+going to be precise here for didactic purposes.
+
+Let's consider the following module definition:
+
+```ruby
+module Colors
+ RED = '0xff0000'
+end
+```
+
+First, when the `module` keyword is processed, the interpreter creates a new
+entry in the constant table of the class object stored in the `Object` constant.
+Said entry associates the name "Colors" to a newly created module object.
+Furthermore, the interpreter sets the name of the new module object to be the
+string "Colors".
+
+Later, when the body of the module definition is interpreted, a new entry is
+created in the constant table of the module object stored in the `Colors`
+constant. That entry maps the name "RED" to the string "0xff0000".
+
+In particular, `Colors::RED` is totally unrelated to any other `RED` constant
+that may live in any other class or module object. If there were any, they
+would have separate entries in their respective constant tables.
+
+Pay special attention in the previous paragraphs to the distinction between
+class and module objects, constant names, and value objects associated to them
+in constant tables.
+
+### Resolution Algorithms
+
+#### Resolution Algorithm for Relative Constants
+
+At any given place in the code, let's define *cref* to be the first element of
+the nesting if it is not empty, or `Object` otherwise.
+
+Without getting too much into the details, the resolution algorithm for relative
+constant references goes like this:
+
+1. If the nesting is not empty the constant is looked up in its elements and in
+order. The ancestors of those elements are ignored.
+
+2. If not found, then the algorithm walks up the ancestor chain of the cref.
+
+3. If not found and the cref is a module, the constant is looked up in `Object`.
+
+4. If not found, `const_missing` is invoked on the cref. The default
+implementation of `const_missing` raises `NameError`, but it can be overridden.
+
+Rails autoloading **does not emulate this algorithm**, but its starting point is
+the name of the constant to be autoloaded, and the cref. See more in [Relative
+References](#autoloading-algorithms-relative-references).
+
+#### Resolution Algorithm for Qualified Constants
+
+Qualified constants look like this:
+
+```ruby
+Billing::Invoice
+```
+
+`Billing::Invoice` is composed of two constants: `Billing` is relative and is
+resolved using the algorithm of the previous section.
+
+INFO. Leading colons would make the first segment absolute rather than
+relative: `::Billing::Invoice`. That would force `Billing` to be looked up
+only as a top-level constant.
+
+`Invoice` on the other hand is qualified by `Billing` and we are going to see
+its resolution next. Let's define *parent* to be that qualifying class or module
+object, that is, `Billing` in the example above. The algorithm for qualified
+constants goes like this:
+
+1. The constant is looked up in the parent and its ancestors. In Ruby >= 2.5,
+`Object` is skipped if present among the ancestors. `Kernel` and `BasicObject`
+are still checked though.
+
+2. If the lookup fails, `const_missing` is invoked in the parent. The default
+implementation of `const_missing` raises `NameError`, but it can be overridden.
+
+INFO. In Ruby < 2.5 `String::Hash` evaluates to `Hash` and the interpreter
+issues a warning: "toplevel constant Hash referenced by String::Hash". Starting
+with 2.5, `String::Hash` raises `NameError` because `Object` is skipped.
+
+As you see, this algorithm is simpler than the one for relative constants. In
+particular, the nesting plays no role here, and modules are not special-cased,
+if neither they nor their ancestors have the constants, `Object` is **not**
+checked.
+
+Rails autoloading **does not emulate this algorithm**, but its starting point is
+the name of the constant to be autoloaded, and the parent. See more in
+[Qualified References](#autoloading-algorithms-qualified-references).
+
+
+Vocabulary
+----------
+
+### Parent Namespaces
+
+Given a string with a constant path we define its *parent namespace* to be the
+string that results from removing its rightmost segment.
+
+For example, the parent namespace of the string "A::B::C" is the string "A::B",
+the parent namespace of "A::B" is "A", and the parent namespace of "A" is "".
+
+The interpretation of a parent namespace when thinking about classes and modules
+is tricky though. Let's consider a module M named "A::B":
+
+* The parent namespace, "A", may not reflect nesting at a given spot.
+
+* The constant `A` may no longer exist, some code could have removed it from
+`Object`.
+
+* If `A` exists, the class or module that was originally in `A` may not be there
+anymore. For example, if after a constant removal there was another constant
+assignment there would generally be a different object in there.
+
+* In such case, it could even happen that the reassigned `A` held a new class or
+module called also "A"!
+
+* In the previous scenarios M would no longer be reachable through `A::B` but
+the module object itself could still be alive somewhere and its name would
+still be "A::B".
+
+The idea of a parent namespace is at the core of the autoloading algorithms
+and helps explain and understand their motivation intuitively, but as you see
+that metaphor leaks easily. Given an edge case to reason about, take always into
+account that by "parent namespace" the guide means exactly that specific string
+derivation.
+
+### Loading Mechanism
+
+Rails autoloads files with `Kernel#load` when `config.cache_classes` is false,
+the default in development mode, and with `Kernel#require` otherwise, the
+default in production mode.
+
+`Kernel#load` allows Rails to execute files more than once if [constant
+reloading](#constant-reloading) is enabled.
+
+This guide uses the word "load" freely to mean a given file is interpreted, but
+the actual mechanism can be `Kernel#load` or `Kernel#require` depending on that
+flag.
+
+
+Autoloading Availability
+------------------------
+
+Rails is always able to autoload provided its environment is in place. For
+example the `runner` command autoloads:
+
+```
+$ rails runner 'p User.column_names'
+["id", "email", "created_at", "updated_at"]
+```
+
+The console autoloads, the test suite autoloads, and of course the application
+autoloads.
+
+By default, Rails eager loads the application files when it boots in production
+mode, so most of the autoloading going on in development does not happen. But
+autoloading may still be triggered during eager loading.
+
+For example, given
+
+```ruby
+class BeachHouse < House
+end
+```
+
+if `House` is still unknown when `app/models/beach_house.rb` is being eager
+loaded, Rails autoloads it.
+
+
+autoload_paths and eager_load_paths
+-----------------------------------
+
+As you probably know, when `require` gets a relative file name:
+
+```ruby
+require 'erb'
+```
+
+Ruby looks for the file in the directories listed in `$LOAD_PATH`. That is, Ruby
+iterates over all its directories and for each one of them checks whether they
+have a file called "erb.rb", or "erb.so", or "erb.o", or "erb.dll". If it finds
+any of them, the interpreter loads it and ends the search. Otherwise, it tries
+again in the next directory of the list. If the list gets exhausted, `LoadError`
+is raised.
+
+We are going to cover how constant autoloading works in more detail later, but
+the idea is that when a constant like `Post` is hit and missing, if there's a
+`post.rb` file for example in `app/models` Rails is going to find it, evaluate
+it, and have `Post` defined as a side-effect.
+
+All right, Rails has a collection of directories similar to `$LOAD_PATH` in which
+to look up `post.rb`. That collection is called `autoload_paths` and by
+default it contains:
+
+* All subdirectories of `app` in the application and engines present at boot
+ time. For example, `app/controllers`. They do not need to be the default
+ ones, any custom directories like `app/workers` belong automatically to
+ `autoload_paths`.
+
+* Any existing second level directories called `app/*/concerns` in the
+ application and engines.
+
+* The directory `test/mailers/previews`.
+
+`eager_load_paths` is initially the `app` paths above
+
+How files are autoloaded depends on `eager_load` and `cache_classes` config settings which typically vary in development, production, and test modes:
+
+ * In **development**, you want quicker startup with incremental loading of application code. So `eager_load` should be set to `false`, and Rails will autoload files as needed (see [Autoloading Algorithms](#autoloading-algorithms) below) -- and then reload them when they change (see [Constant Reloading](#constant-reloading) below).
+ * In **production**, however, you want consistency and thread-safety and can live with a longer boot time. So `eager_load` is set to `true`, and then during boot (before the app is ready to receive requests) Rails loads all files in the `eager_load_paths` and then turns off auto loading (NB: autoloading may be needed during eager loading). Not autoloading after boot is a `good thing`, as autoloading can cause the app to be have thread-safety problems.
+ * In **test**, for speed of execution (of individual tests) `eager_load` is `false`, so Rails follows development behaviour.
+
+What is described above are the defaults with a newly generated Rails app. There are multiple ways this can be configured differently (see [Configuring Rails Applications](configuring.html#rails-general-configuration).
+). But using `autoload_paths` on its own in the past (before Rails 5) developers might configure `autoload_paths` to add in extra locations (e.g. `lib` which used to be an autoload path list years ago, but no longer is). However this is now discouraged for most purposes, as it is likely to lead to production-only errors. It is possible to add new locations to both `config.eager_load_paths` and `config.autoload_paths` but use at your own risk.
+
+See also [Autoloading in the Test Environment](#autoloading-in-the-test-environment).
+
+`config.autoload_paths` is not changeable from environment-specific configuration files.
+
+The value of `autoload_paths` can be inspected. In a just-generated application
+it is (edited):
+
+```
+$ rails r 'puts ActiveSupport::Dependencies.autoload_paths'
+.../app/assets
+.../app/channels
+.../app/controllers
+.../app/controllers/concerns
+.../app/helpers
+.../app/jobs
+.../app/mailers
+.../app/models
+.../app/models/concerns
+.../activestorage/app/assets
+.../activestorage/app/controllers
+.../activestorage/app/javascript
+.../activestorage/app/jobs
+.../activestorage/app/models
+.../actioncable/app/assets
+.../actionview/app/assets
+.../test/mailers/previews
+```
+
+INFO. `autoload_paths` is computed and cached during the initialization process.
+The application needs to be restarted to reflect any changes in the directory
+structure.
+
+
+Autoloading Algorithms
+----------------------
+
+### Relative References
+
+A relative constant reference may appear in several places, for example, in
+
+```ruby
+class PostsController < ApplicationController
+ def index
+ @posts = Post.all
+ end
+end
+```
+
+all three constant references are relative.
+
+#### Constants after the `class` and `module` Keywords
+
+Ruby performs a lookup for the constant that follows a `class` or `module`
+keyword because it needs to know if the class or module is going to be created
+or reopened.
+
+If the constant is not defined at that point it is not considered to be a
+missing constant, autoloading is **not** triggered.
+
+So, in the previous example, if `PostsController` is not defined when the file
+is interpreted Rails autoloading is not going to be triggered, Ruby will just
+define the controller.
+
+#### Top-Level Constants
+
+On the contrary, if `ApplicationController` is unknown, the constant is
+considered missing and an autoload is going to be attempted by Rails.
+
+In order to load `ApplicationController`, Rails iterates over `autoload_paths`.
+First it checks if `app/assets/application_controller.rb` exists. If it does not,
+which is normally the case, it continues and finds
+`app/controllers/application_controller.rb`.
+
+If the file defines the constant `ApplicationController` all is fine, otherwise
+`LoadError` is raised:
+
+```
+unable to autoload constant ApplicationController, expected
+<full path to application_controller.rb> to define it (LoadError)
+```
+
+INFO. Rails does not require the value of autoloaded constants to be a class or
+module object. For example, if the file `app/models/max_clients.rb` defines
+`MAX_CLIENTS = 100` autoloading `MAX_CLIENTS` works just fine.
+
+#### Namespaces
+
+Autoloading `ApplicationController` looks directly under the directories of
+`autoload_paths` because the nesting in that spot is empty. The situation of
+`Post` is different, the nesting in that line is `[PostsController]` and support
+for namespaces comes into play.
+
+The basic idea is that given
+
+```ruby
+module Admin
+ class BaseController < ApplicationController
+ @@all_roles = Role.all
+ end
+end
+```
+
+to autoload `Role` we are going to check if it is defined in the current or
+parent namespaces, one at a time. So, conceptually we want to try to autoload
+any of
+
+```
+Admin::BaseController::Role
+Admin::Role
+Role
+```
+
+in that order. That's the idea. To do so, Rails looks in `autoload_paths`
+respectively for file names like these:
+
+```
+admin/base_controller/role.rb
+admin/role.rb
+role.rb
+```
+
+modulus some additional directory lookups we are going to cover soon.
+
+INFO. `'Constant::Name'.underscore` gives the relative path without extension of
+the file name where `Constant::Name` is expected to be defined.
+
+Let's see how Rails autoloads the `Post` constant in the `PostsController`
+above assuming the application has a `Post` model defined in
+`app/models/post.rb`.
+
+First it checks for `posts_controller/post.rb` in `autoload_paths`:
+
+```
+app/assets/posts_controller/post.rb
+app/controllers/posts_controller/post.rb
+app/helpers/posts_controller/post.rb
+...
+test/mailers/previews/posts_controller/post.rb
+```
+
+Since the lookup is exhausted without success, a similar search for a directory
+is performed, we are going to see why in the [next section](#automatic-modules):
+
+```
+app/assets/posts_controller/post
+app/controllers/posts_controller/post
+app/helpers/posts_controller/post
+...
+test/mailers/previews/posts_controller/post
+```
+
+If all those attempts fail, then Rails starts the lookup again in the parent
+namespace. In this case only the top-level remains:
+
+```
+app/assets/post.rb
+app/controllers/post.rb
+app/helpers/post.rb
+app/mailers/post.rb
+app/models/post.rb
+```
+
+A matching file is found in `app/models/post.rb`. The lookup stops there and the
+file is loaded. If the file actually defines `Post` all is fine, otherwise
+`LoadError` is raised.
+
+### Qualified References
+
+When a qualified constant is missing Rails does not look for it in the parent
+namespaces. But there is a caveat: when a constant is missing, Rails is
+unable to tell if the trigger was a relative reference or a qualified one.
+
+For example, consider
+
+```ruby
+module Admin
+ User
+end
+```
+
+and
+
+```ruby
+Admin::User
+```
+
+If `User` is missing, in either case all Rails knows is that a constant called
+"User" was missing in a module called "Admin".
+
+If there is a top-level `User` Ruby would resolve it in the former example, but
+wouldn't in the latter. In general, Rails does not emulate the Ruby constant
+resolution algorithms, but in this case it tries using the following heuristic:
+
+> If none of the parent namespaces of the class or module has the missing
+> constant then Rails assumes the reference is relative. Otherwise qualified.
+
+For example, if this code triggers autoloading
+
+```ruby
+Admin::User
+```
+
+and the `User` constant is already present in `Object`, it is not possible that
+the situation is
+
+```ruby
+module Admin
+ User
+end
+```
+
+because otherwise Ruby would have resolved `User` and no autoloading would have
+been triggered in the first place. Thus, Rails assumes a qualified reference and
+considers the file `admin/user.rb` and directory `admin/user` to be the only
+valid options.
+
+In practice, this works quite well as long as the nesting matches all parent
+namespaces respectively and the constants that make the rule apply are known at
+that time.
+
+However, autoloading happens on demand. If by chance the top-level `User` was
+not yet loaded, then Rails assumes a relative reference by contract.
+
+Naming conflicts of this kind are rare in practice, but if one occurs,
+`require_dependency` provides a solution by ensuring that the constant needed
+to trigger the heuristic is defined in the conflicting place.
+
+### Automatic Modules
+
+When a module acts as a namespace, Rails does not require the application to
+define a file for it, a directory matching the namespace is enough.
+
+Suppose an application has a back office whose controllers are stored in
+`app/controllers/admin`. If the `Admin` module is not yet loaded when
+`Admin::UsersController` is hit, Rails needs first to autoload the constant
+`Admin`.
+
+If `autoload_paths` has a file called `admin.rb` Rails is going to load that
+one, but if there's no such file and a directory called `admin` is found, Rails
+creates an empty module and assigns it to the `Admin` constant on the fly.
+
+### Generic Procedure
+
+Relative references are reported to be missing in the cref where they were hit,
+and qualified references are reported to be missing in their parent (see
+[Resolution Algorithm for Relative
+Constants](#resolution-algorithm-for-relative-constants) at the beginning of
+this guide for the definition of *cref*, and [Resolution Algorithm for Qualified
+Constants](#resolution-algorithm-for-qualified-constants) for the definition of
+*parent*).
+
+The procedure to autoload constant `C` in an arbitrary situation is as follows:
+
+```
+if the class or module in which C is missing is Object
+ let ns = ''
+else
+ let M = the class or module in which C is missing
+
+ if M is anonymous
+ let ns = ''
+ else
+ let ns = M.name
+ end
+end
+
+loop do
+ # Look for a regular file.
+ for dir in autoload_paths
+ if the file "#{dir}/#{ns.underscore}/c.rb" exists
+ load/require "#{dir}/#{ns.underscore}/c.rb"
+
+ if C is now defined
+ return
+ else
+ raise LoadError
+ end
+ end
+ end
+
+ # Look for an automatic module.
+ for dir in autoload_paths
+ if the directory "#{dir}/#{ns.underscore}/c" exists
+ if ns is an empty string
+ let C = Module.new in Object and return
+ else
+ let C = Module.new in ns.constantize and return
+ end
+ end
+ end
+
+ if ns is empty
+ # We reached the top-level without finding the constant.
+ raise NameError
+ else
+ if C exists in any of the parent namespaces
+ # Qualified constants heuristic.
+ raise NameError
+ else
+ # Try again in the parent namespace.
+ let ns = the parent namespace of ns and retry
+ end
+ end
+end
+```
+
+
+require_dependency
+------------------
+
+Constant autoloading is triggered on demand and therefore code that uses a
+certain constant may have it already defined or may trigger an autoload. That
+depends on the execution path and it may vary between runs.
+
+There are times, however, in which you want to make sure a certain constant is
+known when the execution reaches some code. `require_dependency` provides a way
+to load a file using the current [loading mechanism](#loading-mechanism), and
+keeping track of constants defined in that file as if they were autoloaded to
+have them reloaded as needed.
+
+`require_dependency` is rarely needed, but see a couple of use cases in
+[Autoloading and STI](#autoloading-and-sti) and [When Constants aren't
+Triggered](#when-constants-aren-t-missed).
+
+WARNING. Unlike autoloading, `require_dependency` does not expect the file to
+define any particular constant. Exploiting this behavior would be a bad practice
+though, file and constant paths should match.
+
+
+Constant Reloading
+------------------
+
+When `config.cache_classes` is false Rails is able to reload autoloaded
+constants.
+
+For example, if you're in a console session and edit some file behind the
+scenes, the code can be reloaded with the `reload!` command:
+
+```
+> reload!
+```
+
+When the application runs, code is reloaded when something relevant to this
+logic changes. In order to do that, Rails monitors a number of things:
+
+* `config/routes.rb`.
+
+* Locales.
+
+* Ruby files under `autoload_paths`.
+
+* `db/schema.rb` and `db/structure.sql`.
+
+If anything in there changes, there is a middleware that detects it and reloads
+the code.
+
+Autoloading keeps track of autoloaded constants. Reloading is implemented by
+removing them all from their respective classes and modules using
+`Module#remove_const`. That way, when the code goes on, those constants are
+going to be unknown again, and files reloaded on demand.
+
+INFO. This is an all-or-nothing operation, Rails does not attempt to reload only
+what changed since dependencies between classes makes that really tricky.
+Instead, everything is wiped.
+
+Common Gotchas
+--------------
+
+### Nesting and Qualified Constants
+
+Let's consider
+
+```ruby
+module Admin
+ class UsersController < ApplicationController
+ def index
+ @users = User.all
+ end
+ end
+end
+```
+
+and
+
+```ruby
+class Admin::UsersController < ApplicationController
+ def index
+ @users = User.all
+ end
+end
+```
+
+To resolve `User` Ruby checks `Admin` in the former case, but it does not in
+the latter because it does not belong to the nesting (see [Nesting](#nesting)
+and [Resolution Algorithms](#resolution-algorithms)).
+
+Unfortunately Rails autoloading does not know the nesting in the spot where the
+constant was missing and so it is not able to act as Ruby would. In particular,
+`Admin::User` will get autoloaded in either case.
+
+Albeit qualified constants with `class` and `module` keywords may technically
+work with autoloading in some cases, it is preferable to use relative constants
+instead:
+
+```ruby
+module Admin
+ class UsersController < ApplicationController
+ def index
+ @users = User.all
+ end
+ end
+end
+```
+
+### Autoloading and STI
+
+Single Table Inheritance (STI) is a feature of Active Record that enables
+storing a hierarchy of models in one single table. The API of such models is
+aware of the hierarchy and encapsulates some common needs. For example, given
+these classes:
+
+```ruby
+# app/models/polygon.rb
+class Polygon < ApplicationRecord
+end
+
+# app/models/triangle.rb
+class Triangle < Polygon
+end
+
+# app/models/rectangle.rb
+class Rectangle < Polygon
+end
+```
+
+`Triangle.create` creates a row that represents a triangle, and
+`Rectangle.create` creates a row that represents a rectangle. If `id` is the
+ID of an existing record, `Polygon.find(id)` returns an object of the correct
+type.
+
+Methods that operate on collections are also aware of the hierarchy. For
+example, `Polygon.all` returns all the records of the table, because all
+rectangles and triangles are polygons. Active Record takes care of returning
+instances of their corresponding class in the result set.
+
+Types are autoloaded as needed. For example, if `Polygon.first` is a rectangle
+and `Rectangle` has not yet been loaded, Active Record autoloads it and the
+record is correctly instantiated.
+
+All good, but if instead of performing queries based on the root class we need
+to work on some subclass, things get interesting.
+
+While working with `Polygon` you do not need to be aware of all its descendants,
+because anything in the table is by definition a polygon, but when working with
+subclasses Active Record needs to be able to enumerate the types it is looking
+for. Let's see an example.
+
+`Rectangle.all` only loads rectangles by adding a type constraint to the query:
+
+```sql
+SELECT "polygons".* FROM "polygons"
+WHERE "polygons"."type" IN ("Rectangle")
+```
+
+Let's introduce now a subclass of `Rectangle`:
+
+```ruby
+# app/models/square.rb
+class Square < Rectangle
+end
+```
+
+`Rectangle.all` should now return rectangles **and** squares:
+
+```sql
+SELECT "polygons".* FROM "polygons"
+WHERE "polygons"."type" IN ("Rectangle", "Square")
+```
+
+But there's a caveat here: How does Active Record know that the class `Square`
+exists at all?
+
+Even if the file `app/models/square.rb` exists and defines the `Square` class,
+if no code yet used that class, `Rectangle.all` issues the query
+
+```sql
+SELECT "polygons".* FROM "polygons"
+WHERE "polygons"."type" IN ("Rectangle")
+```
+
+That is not a bug, the query includes all *known* descendants of `Rectangle`.
+
+A way to ensure this works correctly regardless of the order of execution is to
+manually load the direct subclasses at the bottom of the file that defines each
+intermediate class:
+
+```ruby
+# app/models/rectangle.rb
+class Rectangle < Polygon
+end
+require_dependency 'square'
+```
+
+This needs to happen for every intermediate (non-root and non-leaf) class. The
+root class does not scope the query by type, and therefore does not necessarily
+have to know all its descendants.
+
+### Autoloading and `require`
+
+Files defining constants to be autoloaded should never be `require`d:
+
+```ruby
+require 'user' # DO NOT DO THIS
+
+class UsersController < ApplicationController
+ ...
+end
+```
+
+There are two possible gotchas here in development mode:
+
+1. If `User` is autoloaded before reaching the `require`, `app/models/user.rb`
+runs again because `load` does not update `$LOADED_FEATURES`.
+
+2. If the `require` runs first Rails does not mark `User` as an autoloaded
+constant and changes to `app/models/user.rb` aren't reloaded.
+
+Just follow the flow and use constant autoloading always, never mix
+autoloading and `require`. As a last resort, if some file absolutely needs to
+load a certain file use `require_dependency` to play nice with constant
+autoloading. This option is rarely needed in practice, though.
+
+Of course, using `require` in autoloaded files to load ordinary 3rd party
+libraries is fine, and Rails is able to distinguish their constants, they are
+not marked as autoloaded.
+
+### Autoloading and Initializers
+
+Consider this assignment in `config/initializers/set_auth_service.rb`:
+
+```ruby
+AUTH_SERVICE = if Rails.env.production?
+ RealAuthService
+else
+ MockedAuthService
+end
+```
+
+The purpose of this setup would be that the application uses the class that
+corresponds to the environment via `AUTH_SERVICE`. In development mode
+`MockedAuthService` gets autoloaded when the initializer runs. Let's suppose
+we do some requests, change its implementation, and hit the application again.
+To our surprise the changes are not reflected. Why?
+
+As [we saw earlier](#constant-reloading), Rails removes autoloaded constants,
+but `AUTH_SERVICE` stores the original class object. Stale, non-reachable
+using the original constant, but perfectly functional.
+
+The following code summarizes the situation:
+
+```ruby
+class C
+ def quack
+ 'quack!'
+ end
+end
+
+X = C
+Object.instance_eval { remove_const(:C) }
+X.new.quack # => quack!
+X.name # => C
+C # => uninitialized constant C (NameError)
+```
+
+Because of that, it is not a good idea to autoload constants on application
+initialization.
+
+In the case above we could implement a dynamic access point:
+
+```ruby
+# app/models/auth_service.rb
+class AuthService
+ if Rails.env.production?
+ def self.instance
+ RealAuthService
+ end
+ else
+ def self.instance
+ MockedAuthService
+ end
+ end
+end
+```
+
+and have the application use `AuthService.instance` instead. `AuthService`
+would be loaded on demand and be autoload-friendly.
+
+### `require_dependency` and Initializers
+
+As we saw before, `require_dependency` loads files in an autoloading-friendly
+way. Normally, though, such a call does not make sense in an initializer.
+
+One could think about doing some [`require_dependency`](#require-dependency)
+calls in an initializer to make sure certain constants are loaded upfront, for
+example as an attempt to address the [gotcha with STIs](#autoloading-and-sti).
+
+Problem is, in development mode [autoloaded constants are wiped](#constant-reloading)
+if there is any relevant change in the file system. If that happens then
+we are in the very same situation the initializer wanted to avoid!
+
+Calls to `require_dependency` have to be strategically written in autoloaded
+spots.
+
+### When Constants aren't Missed
+
+#### Relative References
+
+Let's consider a flight simulator. The application has a default flight model
+
+```ruby
+# app/models/flight_model.rb
+class FlightModel
+end
+```
+
+that can be overridden by each airplane, for instance
+
+```ruby
+# app/models/bell_x1/flight_model.rb
+module BellX1
+ class FlightModel < FlightModel
+ end
+end
+
+# app/models/bell_x1/aircraft.rb
+module BellX1
+ class Aircraft
+ def initialize
+ @flight_model = FlightModel.new
+ end
+ end
+end
+```
+
+The initializer wants to create a `BellX1::FlightModel` and nesting has
+`BellX1`, that looks good. But if the default flight model is loaded and the
+one for the Bell-X1 is not, the interpreter is able to resolve the top-level
+`FlightModel` and autoloading is thus not triggered for `BellX1::FlightModel`.
+
+That code depends on the execution path.
+
+These kind of ambiguities can often be resolved using qualified constants:
+
+```ruby
+module BellX1
+ class Plane
+ def flight_model
+ @flight_model ||= BellX1::FlightModel.new
+ end
+ end
+end
+```
+
+Also, `require_dependency` is a solution:
+
+```ruby
+require_dependency 'bell_x1/flight_model'
+
+module BellX1
+ class Plane
+ def flight_model
+ @flight_model ||= FlightModel.new
+ end
+ end
+end
+```
+
+#### Qualified References
+
+WARNING. This gotcha is only possible in Ruby < 2.5.
+
+Given
+
+```ruby
+# app/models/hotel.rb
+class Hotel
+end
+
+# app/models/image.rb
+class Image
+end
+
+# app/models/hotel/image.rb
+class Hotel
+ class Image < Image
+ end
+end
+```
+
+the expression `Hotel::Image` is ambiguous because it depends on the execution
+path.
+
+As [we saw before](#resolution-algorithm-for-qualified-constants), Ruby looks
+up the constant in `Hotel` and its ancestors. If `app/models/image.rb` has
+been loaded but `app/models/hotel/image.rb` hasn't, Ruby does not find `Image`
+in `Hotel`, but it does in `Object`:
+
+```
+$ rails r 'Image; p Hotel::Image' 2>/dev/null
+Image # NOT Hotel::Image!
+```
+
+The code evaluating `Hotel::Image` needs to make sure
+`app/models/hotel/image.rb` has been loaded, possibly with
+`require_dependency`.
+
+In these cases the interpreter issues a warning though:
+
+```
+warning: toplevel constant Image referenced by Hotel::Image
+```
+
+This surprising constant resolution can be observed with any qualifying class:
+
+```
+2.1.5 :001 > String::Array
+(irb):1: warning: toplevel constant Array referenced by String::Array
+ => Array
+```
+
+WARNING. To find this gotcha the qualifying namespace has to be a class,
+`Object` is not an ancestor of modules.
+
+### Autoloading within Singleton Classes
+
+Let's suppose we have these class definitions:
+
+```ruby
+# app/models/hotel/services.rb
+module Hotel
+ class Services
+ end
+end
+
+# app/models/hotel/geo_location.rb
+module Hotel
+ class GeoLocation
+ class << self
+ Services
+ end
+ end
+end
+```
+
+If `Hotel::Services` is known by the time `app/models/hotel/geo_location.rb`
+is being loaded, `Services` is resolved by Ruby because `Hotel` belongs to the
+nesting when the singleton class of `Hotel::GeoLocation` is opened.
+
+But if `Hotel::Services` is not known, Rails is not able to autoload it, the
+application raises `NameError`.
+
+The reason is that autoloading is triggered for the singleton class, which is
+anonymous, and as [we saw before](#generic-procedure), Rails only checks the
+top-level namespace in that edge case.
+
+An easy solution to this caveat is to qualify the constant:
+
+```ruby
+module Hotel
+ class GeoLocation
+ class << self
+ Hotel::Services
+ end
+ end
+end
+```
+
+### Autoloading in `BasicObject`
+
+Direct descendants of `BasicObject` do not have `Object` among their ancestors
+and cannot resolve top-level constants:
+
+```ruby
+class C < BasicObject
+ String # NameError: uninitialized constant C::String
+end
+```
+
+When autoloading is involved that plot has a twist. Let's consider:
+
+```ruby
+class C < BasicObject
+ def user
+ User # WRONG
+ end
+end
+```
+
+Since Rails checks the top-level namespace `User` gets autoloaded just fine the
+first time the `user` method is invoked. You only get the exception if the
+`User` constant is known at that point, in particular in a *second* call to
+`user`:
+
+```ruby
+c = C.new
+c.user # surprisingly fine, User
+c.user # NameError: uninitialized constant C::User
+```
+
+because it detects that a parent namespace already has the constant (see [Qualified
+References](#autoloading-algorithms-qualified-references)).
+
+As with pure Ruby, within the body of a direct descendant of `BasicObject` use
+always absolute constant paths:
+
+```ruby
+class C < BasicObject
+ ::String # RIGHT
+
+ def user
+ ::User # RIGHT
+ end
+end
+```
+
+### Autoloading in the Test Environment
+
+When configuring the `test` environment for autoloading you might consider multiple factors.
+
+For example it might be worth running your tests with an identical setup to production (`config.eager_load = true`, `config.cache_classes = true`) in order to catch any problems before they hit production (this is compensation for the lack of dev-prod parity). However this will slow down the boot time for individual tests on a dev machine (and is not immediately compatible with spring see below). So one possibility is to do this on a
+[CI](https://en.wikipedia.org/wiki/Continuous_integration) machine only (which should run without spring).
+
+On a development machine you can then have your tests running with whatever is fastest (ideally `config.eager_load = false`).
+
+With the [Spring](https://github.com/rails/spring) pre-loader (included with new Rails apps), you ideally keep `config.eager_load = false` as per development. Sometimes you may end up with a hybrid configuration (`config.eager_load = true`, `config.cache_classes = true` AND `config.enable_dependency_loading = true`), see [spring issue](https://github.com/rails/spring/issues/519#issuecomment-348324369). However it might be simpler to keep the same configuration as development, and work out whatever it is that is causing autoloading to fail (perhaps by the results of your CI test results).
+
+Occasionally you may need to explicitly eager_load by using `Rails
+.application.eager_load!` in the setup of your tests -- this might occur if your [tests involve multithreading](https://stackoverflow.com/questions/25796409/in-rails-how-can-i-eager-load-all-code-before-a-specific-rspec-test).
+
+## Troubleshooting
+
+### Tracing Autoloads
+
+Active Support is able to report constants as they are autoloaded. To enable these traces in a Rails application, put the following two lines in some initializer:
+
+```ruby
+ActiveSupport::Dependencies.logger = Rails.logger
+ActiveSupport::Dependencies.verbose = true
+```
+
+### Where is a Given Autoload Triggered?
+
+If constant `Foo` is being autoloaded, and you'd like to know where is that autoload coming from, just throw
+
+```ruby
+puts caller
+```
+
+at the top of `foo.rb` and inspect the printed stack trace.
+
+### Which Constants Have Been Autoloaded?
+
+At any given time,
+
+```ruby
+ActiveSupport::Dependencies.autoloaded_constants
+```
+
+has the collection of constants that have been autoloaded so far.
diff --git a/guides/source/command_line.md b/guides/source/command_line.md
index 55f8c84b66..60d0de17bc 100644
--- a/guides/source/command_line.md
+++ b/guides/source/command_line.md
@@ -92,6 +92,28 @@ $ rails new commandsapp
Rails will set you up with what seems like a huge amount of stuff for such a tiny command! You've got the entire Rails directory structure now with all the code you need to run our simple application right out of the box.
+If you wish to skip some files or components from being generated, you can append the following arguments to your `rails new` command:
+
+| Argument | Description |
+| ----------------------- | ----------------------------------------------------------- |
+| `--skip-gemfile` | Don't create a Gemfile |
+| `--skip-git` | Skip .gitignore file |
+| `--skip-keeps` | Skip source control .keep files |
+| `--skip-action-mailer` | Skip Action Mailer files |
+| `--skip-action-text` | Skip Action Text gem |
+| `--skip-active-record` | Skip Active Record files |
+| `--skip-active-storage` | Skip Active Storage files |
+| `--skip-puma` | Skip Puma related files |
+| `--skip-action-cable` | Skip Action Cable files |
+| `--skip-sprockets` | Skip Sprockets files |
+| `--skip-spring` | Don't install Spring application preloader |
+| `--skip-listen` | Don't generate configuration that depends on the listen gem |
+| `--skip-javascript` | Skip JavaScript files |
+| `--skip-turbolinks` | Skip turbolinks gem |
+| `--skip-test` | Skip test files |
+| `--skip-system-test` | Skip system test files |
+| `--skip-bootsnap` | Skip bootsnap gem |
+
### `rails server`
The `rails server` command launches a web server named Puma which comes bundled with Rails. You'll use this any time you want to access your application through a web browser.
@@ -579,6 +601,8 @@ The `tmp:` namespaced commands will help you clear and create the `Rails.root/tm
### Miscellaneous
+* `rails initializers` prints out all defined initializers in the order they are invoked by Rails.
+* `rails middleware` lists Rack middleware stack enabled for your app.
* `rails stats` is great for looking at statistics on your code, displaying things like KLOCs (thousands of lines of code) and your code to test ratio.
* `rails secret` will give you a pseudo-random key to use for your session secret.
* `rails time:zones:all` lists all the timezones Rails knows about.
diff --git a/guides/source/configuring.md b/guides/source/configuring.md
index 3863323bd2..c5d3d09bd0 100644
--- a/guides/source/configuring.md
+++ b/guides/source/configuring.md
@@ -69,7 +69,7 @@ These configuration methods are to be called on a `Rails::Railtie` object, such
* `config.cache_classes` controls whether or not application classes and modules should be reloaded on each request. Defaults to `false` in development mode, and `true` in test and production modes.
* `config.beginning_of_week` sets the default beginning of week for the
-application. Accepts a valid week day symbol (e.g. `:monday`).
+application. Accepts a valid day of week as a symbol (e.g. `:monday`).
* `config.cache_store` configures which cache store to use for Rails caching. Options include one of the symbols `:memory_store`, `:file_store`, `:mem_cache_store`, `:null_store`, `:redis_cache_store`, or an object that implements the cache API. Defaults to `:file_store`.
@@ -145,7 +145,7 @@ defaults to `:debug` for all environments. The available log levels are: `:debug
* `secret_key_base` is used for specifying a key which allows sessions for the application to be verified against a known secure key to prevent tampering. Applications get a random generated key in test and development environments, other environments should set one in `config/credentials.yml.enc`.
-* `config.public_file_server.enabled` configures Rails to serve static files from the public directory. This option defaults to `true`, but in the production environment it is set to `false` because the server software (e.g. NGINX or Apache) used to run the application should serve static files instead. If you are running or testing your app in production mode using WEBrick (it is not recommended to use WEBrick in production) set the option to `true.` Otherwise, you won't be able to use page caching and request for files that exist under the public directory.
+* `config.public_file_server.enabled` configures Rails to serve static files from the public directory. This option defaults to `true`, but in the production environment it is set to `false` because the server software (e.g. NGINX or Apache) used to run the application should serve static files instead. If you are running or testing your app in production mode using WEBrick (it is not recommended to use WEBrick in production) set the option to `true`. Otherwise, you won't be able to use page caching and request for files that exist under the public directory.
* `config.session_store` specifies what class to use to store the session. Possible values are `:cookie_store` which is the default, `:mem_cache_store`, and `:disabled`. The last one tells Rails not to deal with sessions. Defaults to a cookie store with application name as the session key. Custom session stores can also be specified:
@@ -157,6 +157,13 @@ defaults to `:debug` for all environments. The available log levels are: `:debug
* `config.time_zone` sets the default time zone for the application and enables time zone awareness for Active Record.
+* `config.autoloader` sets the autoloading mode. This option defaults to `:zeitwerk` if `6.0` is specified in `config.load_defaults`. Applications can still use the classic autoloader by setting this value to `:classic` after loading the framework defaults:
+
+ ```ruby
+ config.load_defaults "6.0"
+ config.autoloader = :classic
+ ```
+
### Configuring Assets
* `config.assets.enabled` a flag that controls whether the asset
@@ -346,7 +353,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 `:nsec`.
+* `config.active_record.cache_timestamp_format` controls the format of the timestamp value in the cache key. Default is `:usec`.
* `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`.
@@ -383,6 +390,12 @@ All these configuration options are delegated to the `I18n` library.
having to send a query to the database to get this information.
Defaults to `true`.
+* `config.active_record.collection_cache_versioning` enables the same cache key
+ to be reused when the object being cached of type `ActiveRecord::Relation`
+ changes by moving the volatile information (max updated at and count) of
+ the relation's cache key into the cache version to support recycling cache key.
+ Defaults to `false`.
+
The MySQL adapter adds one additional configuration option:
* `ActiveRecord::ConnectionAdapters::Mysql2Adapter.emulate_booleans` controls whether Active Record will consider all `tinyint(1)` columns as booleans. Defaults to `true`.
@@ -540,6 +553,10 @@ Defaults to `'signed cookie'`.
Any exceptions that are not configured will be mapped to 500 Internal Server Error.
+* `config.action_dispatch.return_only_media_type_on_content_type` change the
+ return value of `ActionDispatch::Response#content_type` to the Content-Type
+ header without modification. Defaults to `false`.
+
* `ActionDispatch::Callbacks.before` takes a block of code to run before the request.
* `ActionDispatch::Callbacks.after` takes a block of code to run after the request.
@@ -822,10 +839,12 @@ You can find more detailed configuration options in the
config.active_storage.paths[:ffprobe] = '/usr/local/bin/ffprobe'
```
-* `config.active_storage.variable_content_types` accepts an array of strings indicating the content types that Active Storage can transform through ImageMagick. The default is `%w(image/png image/gif image/jpg image/jpeg image/pjpeg image/tiff image/vnd.adobe.photoshop image/vnd.microsoft.icon)`.
+* `config.active_storage.variable_content_types` accepts an array of strings indicating the content types that Active Storage can transform through ImageMagick. The default is `%w(image/png image/gif image/jpg image/jpeg image/pjpeg image/tiff image/bmp image/vnd.adobe.photoshop image/vnd.microsoft.icon)`.
* `config.active_storage.content_types_to_serve_as_binary` accepts an array of strings indicating the content types that Active Storage will always serve as an attachment, rather than inline. The default is `%w(text/html
-text/javascript image/svg+xml application/postscript application/x-shockwave-flash text/xml application/xml application/xhtml+xml)`.
+text/javascript image/svg+xml application/postscript application/x-shockwave-flash text/xml application/xml application/xhtml+xml application/mathml+xml text/cache-manifest)`.
+
+* `config.active_storage.content_types_allowed_inline` accepts an array of strings indicating the content types that Active Storage allows to serve as inline. The default is `%w(image/png image/gif image/jpg image/jpeg image/vnd.adobe.photoshop image/vnd.microsoft.icon application/pdf)`.
* `config.active_storage.queues.analysis` accepts a symbol indicating the Active Job queue to use for analysis jobs. When this option is `nil`, analysis jobs are sent to the default Active Job queue (see `config.active_job.default_queue_name`).
@@ -839,6 +858,12 @@ text/javascript image/svg+xml application/postscript application/x-shockwave-fla
config.active_storage.queues.purge = :low_priority
```
+* `config.active_storage.queues.mirror` accepts a symbol indicating the Active Job queue to use for direct upload mirroring jobs. The default is `:active_storage_mirror`.
+
+ ```ruby
+ config.active_storage.queues.mirror = :low_priority
+ ```
+
* `config.active_storage.logger` can be used to set the logger used by Active Storage. Accepts a logger conforming to the interface of Log4r or the default Ruby Logger class.
```ruby
@@ -858,7 +883,11 @@ text/javascript image/svg+xml application/postscript application/x-shockwave-fla
config.active_storage.routes_prefix = '/files'
```
- The default is `/rails/active_storage`
+ The default is `/rails/active_storage`.
+
+* `config.active_storage.replace_on_assign_to_many` determines whether assigning to a collection of attachments declared with `has_many_attached` replaces any existing attachments or appends to them. The default is `true`.
+
+* `config.active_storage.draw_routes` can be used to toggle Active Storage route generation. The default is `true`.
### Results of `load_defaults`
@@ -878,7 +907,7 @@ text/javascript image/svg+xml application/postscript application/x-shockwave-fla
#### With '5.2':
- `config.active_record.cache_versioning`: `true`
-- `action_dispatch.use_authenticated_cookie_encryption`: `true`
+- `config.action_dispatch.use_authenticated_cookie_encryption`: `true`
- `config.active_support.use_authenticated_message_encryption`: `true`
- `config.active_support.use_sha1_digests`: `true`
- `config.action_controller.default_protect_from_forgery`: `true`
@@ -886,12 +915,16 @@ text/javascript image/svg+xml application/postscript application/x-shockwave-fla
#### With '6.0':
+- `config.autoloader`: `:zeitwerk`
- `config.action_view.default_enforce_utf8`: `false`
- `config.action_dispatch.use_cookies_with_metadata`: `true`
+- `config.action_dispatch.return_only_media_type_on_content_type`: `false`
- `config.action_mailer.delivery_job`: `"ActionMailer::MailDeliveryJob"`
- `config.active_job.return_false_on_aborted_enqueue`: `true`
- `config.active_storage.queues.analysis`: `:active_storage_analysis`
- `config.active_storage.queues.purge`: `:active_storage_purge`
+- `config.active_storage.replace_on_assign_to_many`: `true`
+- `config.active_record.collection_cache_versioning`: `true`
### Configuring a Database
@@ -1515,7 +1548,7 @@ Disallow: /
```
To block just specific pages, it's necessary to use a more complex syntax. Learn
-it on the [official documentation](http://www.robotstxt.org/robotstxt.html).
+it on the [official documentation](https://www.robotstxt.org/robotstxt.html).
Evented File System Monitor
---------------------------
diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md
index f86589bdf1..9c28ff6a9c 100644
--- a/guides/source/contributing_to_ruby_on_rails.md
+++ b/guides/source/contributing_to_ruby_on_rails.md
@@ -13,7 +13,7 @@ After reading this guide, you will know:
* How to contribute to the Ruby on Rails documentation.
* How to contribute to the Ruby on Rails code.
-Ruby on Rails is not "someone else's framework." Over the years, thousands of people have contributed to Ruby on Rails ranging from a single character to massive architectural changes or significant documentation - all with the goal of making Ruby on Rails better for everyone. Even if you don't feel up to writing code or documentation yet, there are a variety of other ways that you can contribute, from reporting issues to testing patches.
+Ruby on Rails is not "someone else's framework". Over the years, thousands of people have contributed to Ruby on Rails ranging from a single character to massive architectural changes or significant documentation - all with the goal of making Ruby on Rails better for everyone. Even if you don't feel up to writing code or documentation yet, there are a variety of other ways that you can contribute, from reporting issues to testing patches.
As mentioned in [Rails'
README](https://github.com/rails/rails/blob/master/README.md), everyone interacting in Rails and its sub-projects' codebases, issue trackers, chat rooms, and mailing lists is expected to follow the Rails [code of conduct](https://rubyonrails.org/conduct/).
@@ -76,7 +76,7 @@ a patch, please send an email to the [rails-core mailing
list](https://groups.google.com/forum/?fromgroups#!forum/rubyonrails-core). You
might get no response, which means that everyone is indifferent. You might find
someone who's also interested in building that feature. You might get a "This
-won't be accepted." But it's the proper place to discuss new ideas. GitHub
+won't be accepted". But it's the proper place to discuss new ideas. GitHub
Issues are not a particularly good venue for the sometimes long and involved
discussions new features require.
@@ -139,7 +139,7 @@ changes to the master branch.
When working with documentation, please take into account the [API Documentation Guidelines](api_documentation_guidelines.html) and the [Ruby on Rails Guides Guidelines](ruby_on_rails_guides_guidelines.html).
-NOTE: To help our CI servers you should add [ci skip] to your documentation commit message to skip build on that commit. Please remember to use it for commits containing only documentation changes.
+NOTE: For documentation changes, your commit message should include [ci skip]. This will skip running the test suite, helping us to cut down on our server costs. Keep in mind that you should only skip CI when your change touches documentation exclusively.
Translating Rails Guides
------------------------
@@ -340,7 +340,7 @@ $ TEST_DIR=generators bundle exec rake test
You can run the tests for a particular file by using:
```bash
-$ cd actionpack
+$ cd actionview
$ bundle exec ruby -w -Itest test/template/form_helper_test.rb
```
diff --git a/guides/source/documents.yaml b/guides/source/documents.yaml
index 1e67b2bce7..da11236064 100644
--- a/guides/source/documents.yaml
+++ b/guides/source/documents.yaml
@@ -139,9 +139,13 @@
url: initialization.html
description: This guide explains the internals of the Rails initialization process.
-
- name: Autoloading and Reloading Constants
+ name: Autoloading and Reloading Constants (Zeitwerk Mode)
url: autoloading_and_reloading_constants.html
- description: This guide documents how autoloading and reloading constants work.
+ description: This guide documents how autoloading and reloading constants work (Zeitwerk mode).
+ -
+ name: Autoloading and Reloading Constants (Classic Mode)
+ url: autoloading_and_reloading_constants_classic_mode.html
+ description: This guide documents how autoloading and reloading constants work (Classic mode).
-
name: "Caching with Rails: An Overview"
url: caching_with_rails.html
@@ -160,6 +164,11 @@
work_in_progress: true
url: active_record_postgresql.html
description: This guide covers PostgreSQL specific usage of Active Record.
+ -
+ name: Multiple Databases with Active Record
+ work_in_progress: true
+ url: active_record_multiple_databases.html
+ description: This guide covers using multiple databases in your application.
-
name: Extending Rails
@@ -193,7 +202,7 @@
-
name: Contributing to Ruby on Rails
url: contributing_to_ruby_on_rails.html
- description: Rails is not 'somebody else's framework.' This guide covers a variety of ways that you can get involved in the ongoing development of Rails.
+ description: Rails is not "someone else's framework". This guide covers a variety of ways that you can get involved in the ongoing development of Rails.
-
name: API Documentation Guidelines
url: api_documentation_guidelines.html
diff --git a/guides/source/engines.md b/guides/source/engines.md
index 3031c62928..8961a079b5 100644
--- a/guides/source/engines.md
+++ b/guides/source/engines.md
@@ -220,7 +220,7 @@ Inside the `app` directory are the standard `assets`, `controllers`, `helpers`,
`jobs`, `mailers`, `models`, and `views` directories that you should be familiar with
from an application. We'll look more into models in a future section, when we're writing the engine.
-Within the `app/assets` directory, there are the `images`, `javascripts` and
+Within the `app/assets` directory, there are the `images` and
`stylesheets` directories which, again, you should be familiar with due to their
similarity to an application. One difference here, however, is that each
directory contains a sub-directory with the engine name. Because this engine is
@@ -1511,34 +1511,35 @@ These are the hooks you can use in your own code.
To hook into the initialization process of one of the following classes use the available hook.
-| Class | Available Hooks |
-| --------------------------------- | ------------------------------------ |
-| `ActionCable` | `action_cable` |
-| `ActionCable::Channel::Base` | `action_cable_channel` |
-| `ActionCable::Connection::Base` | `action_cable_connection` |
-| `ActionController::API` | `action_controller_api` |
-| `ActionController::API` | `action_controller` |
-| `ActionController::Base` | `action_controller_base` |
-| `ActionController::Base` | `action_controller` |
-| `ActionController::TestCase` | `action_controller_test_case` |
-| `ActionDispatch::IntegrationTest` | `action_dispatch_integration_test` |
-| `ActionDispatch::SystemTestCase` | `action_dispatch_system_test_case` |
-| `ActionMailbox::Base` | `action_mailbox` |
-| `ActionMailbox::InboundEmail` | `action_mailbox_inbound_email` |
-| `ActionMailbox::TestCase` | `action_mailbox_test_case` |
-| `ActionMailer::Base` | `action_mailer` |
-| `ActionMailer::TestCase` | `action_mailer_test_case` |
-| `ActionText::Content` | `action_text_content` |
-| `ActionText::RichText` | `action_text_rich_text` |
-| `ActionView::Base` | `action_view` |
-| `ActionView::TestCase` | `action_view_test_case` |
-| `ActiveJob::Base` | `active_job` |
-| `ActiveJob::TestCase` | `active_job_test_case` |
-| `ActiveRecord::Base` | `active_record` |
-| `ActiveStorage::Attachment` | `active_storage_attachment` |
-| `ActiveStorage::Blob` | `active_storage_blob` |
-| `ActiveSupport::TestCase` | `active_support_test_case` |
-| `i18n` | `i18n` |
+| Class | Available Hooks |
+| -------------------------------------| ------------------------------------ |
+| `ActionCable` | `action_cable` |
+| `ActionCable::Channel::Base` | `action_cable_channel` |
+| `ActionCable::Connection::Base` | `action_cable_connection` |
+| `ActionCable::Connection::TestCase` | `action_cable_connection_test_case` |
+| `ActionController::API` | `action_controller_api` |
+| `ActionController::API` | `action_controller` |
+| `ActionController::Base` | `action_controller_base` |
+| `ActionController::Base` | `action_controller` |
+| `ActionController::TestCase` | `action_controller_test_case` |
+| `ActionDispatch::IntegrationTest` | `action_dispatch_integration_test` |
+| `ActionDispatch::SystemTestCase` | `action_dispatch_system_test_case` |
+| `ActionMailbox::Base` | `action_mailbox` |
+| `ActionMailbox::InboundEmail` | `action_mailbox_inbound_email` |
+| `ActionMailbox::TestCase` | `action_mailbox_test_case` |
+| `ActionMailer::Base` | `action_mailer` |
+| `ActionMailer::TestCase` | `action_mailer_test_case` |
+| `ActionText::Content` | `action_text_content` |
+| `ActionText::RichText` | `action_text_rich_text` |
+| `ActionView::Base` | `action_view` |
+| `ActionView::TestCase` | `action_view_test_case` |
+| `ActiveJob::Base` | `active_job` |
+| `ActiveJob::TestCase` | `active_job_test_case` |
+| `ActiveRecord::Base` | `active_record` |
+| `ActiveStorage::Attachment` | `active_storage_attachment` |
+| `ActiveStorage::Blob` | `active_storage_blob` |
+| `ActiveSupport::TestCase` | `active_support_test_case` |
+| `i18n` | `i18n` |
## Configuration hooks
diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md
index 7000fa408c..ce45dbb2a7 100644
--- a/guides/source/getting_started.md
+++ b/guides/source/getting_started.md
@@ -28,7 +28,7 @@ curve diving straight into Rails. There are several curated lists of online reso
for learning Ruby:
* [Official Ruby Programming Language website](https://www.ruby-lang.org/en/documentation/)
-* [List of Free Programming Books](https://github.com/vhf/free-programming-books/blob/master/free-programming-books.md#ruby)
+* [List of Free Programming Books](https://github.com/EbookFoundation/free-programming-books/blob/master/free-programming-books.md#ruby)
Be aware that some resources, while still excellent, cover versions of Ruby as old as
1.6, and commonly 1.8, and will not include some syntax that you will see in day-to-day
@@ -55,7 +55,7 @@ The Rails philosophy includes two major guiding principles:
* **Don't Repeat Yourself:** DRY is a principle of software development which
states that "Every piece of knowledge must have a single, unambiguous, authoritative
- representation within a system." By not writing the same information over and over
+ representation within a system". By not writing the same information over and over
again, our code is more maintainable, more extensible, and less buggy.
* **Convention Over Configuration:** Rails has opinions about the best way to do many
things in a web application, and defaults to this set of conventions, rather than
@@ -207,7 +207,7 @@ folder directly to the Ruby interpreter e.g. `ruby bin\rails server`.
TIP: JavaScript asset compression requires you
have a JavaScript runtime available on your system, in the absence
-of a runtime you will see an `execjs` error during asset compilation.
+of a runtime you will see an `execjs` error during asset compression.
Usually macOS and Windows come with a JavaScript runtime installed.
`therubyrhino` is the recommended runtime for JRuby users and is added by
default to the `Gemfile` in apps generated under JRuby. You can investigate
diff --git a/guides/source/initialization.md b/guides/source/initialization.md
index c41eae18cf..556c85cc0f 100644
--- a/guides/source/initialization.md
+++ b/guides/source/initialization.md
@@ -108,6 +108,8 @@ A standard Rails application depends on several gems, specifically:
* activerecord
* activestorage
* activesupport
+* actionmailbox
+* actiontext
* arel
* builder
* bundler
@@ -160,8 +162,8 @@ namespace and executes the command if found.
If Rails doesn't recognize the command, it hands the reins over to Rake
to run a task of the same name.
-As shown, `Rails::Command` displays the help output automatically if the `args`
-are empty.
+As shown, `Rails::Command` displays the help output automatically if the `namespace`
+is empty.
```ruby
module Rails::Command
@@ -289,7 +291,7 @@ def default_options
environment: (ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development").dup,
daemonize: false,
caching: nil,
- pid: Options::DEFAULT_PID_PATH,
+ pid: ENV.fetch("PIDFILE", Options::DEFAULT_PIDFILE).dup,
restart_cmd: restart_command)
end
```
@@ -538,6 +540,8 @@ require "rails"
action_mailer/railtie
active_job/railtie
action_cable/engine
+ action_mailbox/engine
+ action_text/engine
rails/test_unit/railtie
sprockets/railtie
).each do |railtie|
diff --git a/guides/source/layouts_and_rendering.md b/guides/source/layouts_and_rendering.md
index 39935cd2ef..ce90a60e36 100644
--- a/guides/source/layouts_and_rendering.md
+++ b/guides/source/layouts_and_rendering.md
@@ -149,25 +149,6 @@ Rails knows that this view belongs to a different controller because of the embe
render template: "products/show"
```
-#### Rendering an Arbitrary File
-
-The `render` method can also use a view that's entirely outside of your application:
-
-```ruby
-render file: "/u/apps/warehouse_app/current/app/views/products/show"
-```
-
-The `:file` option takes an absolute file-system path. Of course, you need to have rights
-to the view that you're using to render the content.
-
-NOTE: Using the `:file` option in combination with users input can lead to security problems
-since an attacker could use this action to access security sensitive files in your file system.
-
-NOTE: By default, the file is rendered using the current layout.
-
-TIP: If you're running Rails on Microsoft Windows, you should use the `:file` option to
-render a file, because Windows filenames do not have the same format as Unix filenames.
-
#### Wrapping it up
The above three ways of rendering (rendering another template within the controller, rendering a template within another controller, and rendering an arbitrary file on the file system) are actually variants of the same action.
@@ -178,17 +159,9 @@ In fact, in the BooksController class, inside of the update action where we want
render :edit
render action: :edit
render "edit"
-render "edit.html.erb"
render action: "edit"
-render action: "edit.html.erb"
render "books/edit"
-render "books/edit.html.erb"
render template: "books/edit"
-render template: "books/edit.html.erb"
-render "/path/to/rails/app/views/books/edit"
-render "/path/to/rails/app/views/books/edit.html.erb"
-render file: "/path/to/rails/app/views/books/edit"
-render file: "/path/to/rails/app/views/books/edit.html.erb"
```
Which one you use is really a matter of style and convention, but the rule of thumb is to use the simplest one that makes sense for the code you are writing.
@@ -287,6 +260,23 @@ time.
NOTE: Unless overridden, your response returned from this render option will be
`text/plain`, as that is the default content type of Action Dispatch response.
+#### Rendering raw file
+
+Rails can render a raw file from an absolute path. This is useful for
+conditionally rendering static files like error pages.
+
+```ruby
+render file: "#{Rails.root}/public/404.html", layout: false
+```
+
+This renders the raw file (it doesn't support ERB or other handlers). By
+default it is rendered within the current layout.
+
+WARNING: Using the `:file` option in combination with users input can lead to security problems
+since an attacker could use this action to access security sensitive files in your file system.
+
+TIP: `send_file` is often a faster and better option if a layout isn't required.
+
#### Options for `render`
Calls to the `render` method generally accept five options:
@@ -303,7 +293,7 @@ Calls to the `render` method generally accept five options:
By default, Rails will serve the results of a rendering operation with the MIME content-type of `text/html` (or `application/json` if you use the `:json` option, or `application/xml` for the `:xml` option.). There are times when you might like to change this, and you can do so by setting the `:content_type` option:
```ruby
-render file: filename, content_type: "application/rss"
+render template: "feed", content_type: "application/rss"
```
##### The `:layout` Option
diff --git a/guides/source/rails_application_templates.md b/guides/source/rails_application_templates.md
index 982df26987..e0e79fc41b 100644
--- a/guides/source/rails_application_templates.md
+++ b/guides/source/rails_application_templates.md
@@ -82,10 +82,10 @@ end
Adds the given source to the generated application's `Gemfile`.
-For example, if you need to source a gem from `"http://code.whytheluckystiff.net"`:
+For example, if you need to source a gem from `"http://gems.github.com"`:
```ruby
-add_source "http://code.whytheluckystiff.net"
+add_source "http://gems.github.com"
```
If block is given, gem entries in block are wrapped into the source group.
diff --git a/guides/source/routing.md b/guides/source/routing.md
index e3a6bbb138..4aeb9ee585 100644
--- a/guides/source/routing.md
+++ b/guides/source/routing.md
@@ -508,7 +508,7 @@ end
This will recognize `/photos/1/preview` with GET, and route to the `preview` action of `PhotosController`, with the resource id value passed in `params[:id]`. It will also create the `preview_photo_url` and `preview_photo_path` helpers.
-Within the block of member routes, each route name specifies the HTTP verb
+Within the block of member routes, each route name specifies the HTTP verb that
will be recognized. You can use `get`, `patch`, `put`, `post`, or `delete` here
. If you don't have multiple `member` routes, you can also pass `:on` to a
route, eliminating the block:
diff --git a/guides/source/security.md b/guides/source/security.md
index 22c122d4b9..5bb7a51524 100644
--- a/guides/source/security.md
+++ b/guides/source/security.md
@@ -1211,4 +1211,4 @@ The security landscape shifts and it is important to keep up to date, because mi
* Subscribe to the Rails security [mailing list](https://groups.google.com/forum/#!forum/rubyonrails-security).
* [Brakeman - Rails Security Scanner](https://brakemanscanner.org/) - To perform static security analysis for Rails applications.
* [Keep up to date on the other application layers](http://secunia.com/) (they have a weekly newsletter, too).
-* A [good security blog](https://www.owasp.org) including the [Cross-Site scripting Cheat Sheet](https://www.owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet).
+* A [good security blog](https://www.owasp.org) including the [Cross-Site scripting Cheat Sheet](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.md).
diff --git a/guides/source/testing.md b/guides/source/testing.md
index 18eecf49fa..41bc54b924 100644
--- a/guides/source/testing.md
+++ b/guides/source/testing.md
@@ -781,7 +781,7 @@ This can be helpful for viewing the browser at the point a test failed, or
to view screenshots later for debugging.
Two methods are provided: `take_screenshot` and `take_failed_screenshot`.
-`take_failed_screenshot` is automatically included in `after_teardown` inside
+`take_failed_screenshot` is automatically included in `before_teardown` inside
Rails.
The `take_screenshot` helper method can be included anywhere in your tests to
@@ -1144,7 +1144,7 @@ test "ajax request" do
get article_url(article), xhr: true
assert_equal 'hello world', @response.body
- assert_equal "text/javascript", @response.content_type
+ assert_equal "text/javascript", @response.media_type
end
```
diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md
index 7e4152aa51..05980d1614 100644
--- a/guides/source/upgrading_ruby_on_rails.md
+++ b/guides/source/upgrading_ruby_on_rails.md
@@ -85,13 +85,14 @@ Rails 6.1. You are encouraged to enable `config.force_ssl` to enforce HTTPS
connections throughout your application. If you need to exempt certain endpoints
from redirection, you can use `config.ssl_options` to configure that behavior.
-### Purpose in signed or encrypted cookie is now embedded within cookies
+### Purpose and expiry metadata is now embedded inside signed and encrypted cookies for increased security
+
+To improve security, Rails embeds the purpose and expiry metadata inside encrypted or signed cookies value.
-To improve security, Rails embeds the purpose information in encrypted or signed cookies value.
Rails can then thwart attacks that attempt to copy the signed/encrypted value
of a cookie and use it as the value of another cookie.
-This new embed information make those cookies incompatible with versions of Rails older than 6.0.
+This new embed metadata make those cookies incompatible with versions of Rails older than 6.0.
If you require your cookies to be read by Rails 5.2 and older, or you are still validating your 6.0 deploy and want
to be able to rollback set
@@ -133,6 +134,318 @@ Action Cable JavaScript API:
+ ActionCable.logger.enabled = false
```
+### `ActionDispatch::Response#content_type` now returns the Content-Type header without modification
+
+Previously, the return value of `ActionDispatch::Response#content_type` did NOT contain the charset part.
+This behavior has changed to include the previously omitted charset part as well.
+
+If you want just the MIME type, please use `ActionDispatch::Response#media_type` instead.
+
+Before:
+
+```ruby
+resp = ActionDispatch::Response.new(200, "Content-Type" => "text/csv; header=present; charset=utf-16")
+resp.content_type #=> "text/csv; header=present"
+```
+
+After:
+
+```ruby
+resp = ActionDispatch::Response.new(200, "Content-Type" => "text/csv; header=present; charset=utf-16")
+resp.content_type #=> "text/csv; header=present; charset=utf-16"
+resp.media_type #=> "text/csv"
+```
+
+### Autoloading
+
+The default configuration for Rails 6
+
+```ruby
+# config/application.rb
+
+config.load_defaults "6.0"
+```
+
+enables `zeitwerk` autoloading mode on CRuby. In that mode, autoloading, reloading, and eager loading are managed by [Zeitwerk](https://github.com/fxn/zeitwerk).
+
+#### Public API
+
+In general, applications do not need to use the API of Zeitwerk directly. Rails sets things up according to the existing contract: `config.autoload_paths`, `config.cache_classes`, etc.
+
+While applications should stick to that interface, the actual Zeitwerk loader object can be accessed as
+
+```ruby
+Rails.autoloaders.main
+```
+
+That may be handy if you need to preload STIs or configure a custom inflector, for example.
+
+#### Project Structure
+
+If the application being upgraded autoloads correctly, the project structure should be already mostly compatible.
+
+However, `classic` mode infers file names from missing constant names (`underscore`), whereas `zeitwerk` mode infers constant names from file names (`camelize`). These helpers are not always inverse of each other, in particular if acronyms are involved. For instance, `"FOO".underscore` is `"foo"`, but `"foo".camelize` is `"Foo"`, not `"FOO"`.
+
+Compatibility can be checked with the `zeitwerk:check` task:
+
+```
+$ bin/rails zeitwerk:check
+Hold on, I am eager loading the application.
+All is good!
+```
+
+#### require_dependency
+
+All known use cases of `require_dependency` have been eliminated, you should grep the project and delete them.
+
+If your application has STIs, please check their section in the guide [Autoloading and Reloading Constants (Zeitwerk Mode)](autoloading_and_reloading_constants.html#single-table-inheritance).
+
+#### Qualified names in class and module definitions
+
+You can now robustly use constant paths in class and module definitions:
+
+```ruby
+# Autoloading in this class' body matches Ruby semantics now.
+class Admin::UsersController < ApplicationController
+ # ...
+end
+```
+
+A gotcha to be aware of is that, depending on the order of execution, the classic autoloader could sometimes be able to autoload `Foo::Wadus` in
+
+```ruby
+class Foo::Bar
+ Wadus
+end
+```
+
+That does not match Ruby semantics because `Foo` is not in the nesting, and won't work at all in `zeitwerk` mode. If you find such corner case you can use the qualified name `Foo::Wadus`:
+
+```ruby
+class Foo::Bar
+ Foo::Wadus
+end
+```
+
+or add `Foo` to the nesting:
+
+```ruby
+module Foo
+ class Bar
+ Wadus
+ end
+end
+```
+
+#### Concerns
+
+You can autoload and eager load from a standard structure like
+
+```
+app/models
+app/models/concerns
+```
+
+In that case, `app/models/concerns` is assumed to be a root directory (because it belongs to the autoload paths), and it is ignored as namespace. So, `app/models/concerns/foo.rb` should define `Foo`, not `Concerns::Foo`.
+
+The `Concerns::` namespace worked with the classic autoloader as a side-effect of the implementation, but it was not really an intended behavior. An application using `Concerns::` needs to rename those classes and modules to be able to run in `zeitwerk` mode.
+
+#### Having `app` in the autoload paths
+
+Some projects want something like `app/api/base.rb` to define `API::Base`, and add `app` to the autoload paths to accomplish that in `classic` mode. Since Rails adds all subdirectories of `app` to the autoload paths automatically, we have another situation in which there are nested root directories, so that setup no longer works. Similar principle we explained above with `concerns`.
+
+If you want to keep that structure, you'll need to delete the subdirectory from the autoload paths in an initializer:
+
+```ruby
+ActiveSupport::Dependencies.autoload_paths.delete("#{Rails.root}/app/api")
+```
+
+#### Autoloaded Constants and Explicit Namespaces
+
+If a namespace is defined in a file, as `Hotel` is here:
+
+```
+app/models/hotel.rb # Defines Hotel.
+app/models/hotel/pricing.rb # Defines Hotel::Pricing.
+```
+
+the `Hotel` constant has to be set using the `class` or `module` keywords. For example:
+
+```ruby
+class Hotel
+end
+```
+
+is good.
+
+Alternatives like
+
+```ruby
+Hotel = Class.new
+```
+
+or
+
+```ruby
+Hotel = Struct.new
+```
+
+won't work, child objects like `Hotel::Pricing` won't be found.
+
+This restriction only applies to explicit namespaces. Classes and modules not defining a namespace can be defined using those idioms.
+
+#### One file, one constant (at the same top-level)
+
+In `classic` mode you could technically define several constants at the same top-level and have them all reloaded. For example, given
+
+```ruby
+# app/models/foo.rb
+
+class Foo
+end
+
+class Bar
+end
+```
+
+while `Bar` could not be autoloaded, autoloading `Foo` would mark `Bar` as autoloaded too. This is not the case in `zeitwerk` mode, you need to move `Bar` to its own file `bar.rb`. One file, one constant.
+
+This affects only to constants at the same top-level as in the example above. Inner classes and modules are fine. For example, consider
+
+```ruby
+# app/models/foo.rb
+
+class Foo
+ class InnerClass
+ end
+end
+```
+
+If the application reloads `Foo`, it will reload `Foo::InnerClass` too.
+
+#### Spring and the `test` Environment
+
+Spring reloads the application code if something changes. In the `test` environment you need to enable reloading for that to work:
+
+```ruby
+# config/environments/test.rb
+
+config.cache_classes = false
+```
+
+Otherwise you'll get this error:
+
+```
+reloading is disabled because config.cache_classes is true
+```
+
+#### Bootsnap
+
+Bootsnap should be at least version 1.4.2.
+
+In addition to that, Bootsnap needs to disable the iseq cache due to a bug in the interpreter if running Ruby 2.5. Please make sure to depend on at least Bootsnap 1.4.4 in that case.
+
+#### `config.add_autoload_paths_to_load_path`
+
+The new configuration point
+
+```ruby
+config.add_autoload_paths_to_load_path
+```
+
+is `true` by default for backwards compatibility, but allows you to opt-out from adding the autoload paths to `$LOAD_PATH`.
+
+This makes sense in most applications, since you never should require a file in `app/models`, for example, and Zeitwerk only uses absolute file names internally.
+
+By opting-out you optimize `$LOAD_PATH` lookups (less directories to check), and save Bootsnap work and memory consumption, since it does not need to build an index for these directories.
+
+#### Thread-safety
+
+In classic mode, constant autoloading is not thread-safe, though Rails has locks in place for example to make web requests thread-safe when autoloading is enabled, as it is common in `development` mode.
+
+Constant autoloading is thread-safe in `zeitwerk` mode. For example, you can now autoload in multi-threaded scripts executed by the `runner` command.
+
+#### Globs in config.autoload_paths
+
+Beware of configurations like
+
+```ruby
+config.autoload_paths += Dir["#{config.root}/lib/**/"]
+```
+
+Every element of `config.autoload_paths` should represent the top-level namespace (`Object`) and they cannot be nested in consequence (with the exception of `concerns` directories explained above).
+
+To fix this, just remove the wildcards:
+
+```ruby
+config.autoload_paths << "#{config.root}/lib"
+```
+
+#### Eager loading and autoloading are consistent
+
+In `classic` mode, if `app/models/foo.rb` defines `Bar`, you won't be able to autoload that file, but eager loading will work because it loads files recursively blindly. This can be a source of errors if you test things first eager loading, execution may fail later autoloading.
+
+In `zeitwerk` mode both loading modes are consistent, they fail and err in the same files.
+
+#### How to Use the Classic Autoloader in Rails 6
+
+Applications can load Rails 6 defaults and still use the classic autoloader by setting `config.autoloader` this way:
+
+```ruby
+# config/application.rb
+
+config.load_defaults "6.0"
+config.autoloader = :classic
+```
+
+### Active Storage assignment behavior change
+
+In Rails 5.2, assigning to a collection of attachments declared with `has_many_attached` appended new files:
+
+```ruby
+class User < ApplicationRecord
+ has_many_attached :highlights
+end
+
+user.highlights.attach(filename: "funky.jpg", ...)
+user.higlights.count # => 1
+
+blob = ActiveStorage::Blob.create_after_upload!(filename: "town.jpg", ...)
+user.update!(highlights: [ blob ])
+
+user.highlights.count # => 2
+user.highlights.first.filename # => "funky.jpg"
+user.highlights.second.filename # => "town.jpg"
+```
+
+With the default configuration for Rails 6.0, assigning to a collection of attachments replaces existing files
+instead of appending to them. This matches Active Record behavior when assigning to a collection association:
+
+```ruby
+user.highlights.attach(filename: "funky.jpg", ...)
+user.highlights.count # => 1
+
+blob = ActiveStorage::Blob.create_after_upload!(filename: "town.jpg", ...)
+user.update!(highlights: [ blob ])
+
+user.highlights.count # => 1
+user.highlights.first.filename # => "town.jpg"
+```
+
+`#attach` can be used to add new attachments without removing the existing ones:
+
+```ruby
+blob = ActiveStorage::Blob.create_after_upload!(filename: "town.jpg", ...)
+user.highlights.attach(blob)
+
+user.highlights.count # => 2
+user.highlights.first.filename # => "funky.jpg"
+user.highlights.second.filename # => "town.jpg"
+```
+
+Opt in to the new default behavior by setting `config.active_storage.replace_on_assign_to_many` to `true`.
+The old behavior will be deprecated in Rails 6.1 and removed in a subsequent release.
+
Upgrading from Rails 5.1 to Rails 5.2
-------------------------------------
@@ -1557,7 +1870,7 @@ config.assets.enabled = true
config.assets.version = '1.0'
```
-If your application is using an "/assets" route for a resource you may want change the prefix used for assets to avoid conflicts:
+If your application is using an "/assets" route for a resource you may want to change the prefix used for assets to avoid conflicts:
```ruby
# Defaults to '/assets'
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 7bc7391f9e..cfb30719da 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,3 +1,5 @@
+* Support using environment variable to set pidfile
+ *Ben Thorner*
Please check [6-0-stable](https://github.com/rails/rails/blob/6-0-stable/railties/CHANGELOG.md) for previous changes.
diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb
index 1f533a8c04..440d2953c3 100644
--- a/railties/lib/rails.rb
+++ b/railties/lib/rails.rb
@@ -5,7 +5,6 @@ require "rails/ruby_version_check"
require "pathname"
require "active_support"
-require "active_support/dependencies/autoload"
require "active_support/core_ext/kernel/reporting"
require "active_support/core_ext/module/delegation"
require "active_support/core_ext/array/extract_options"
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index 038284ebdd..cbaab6cc33 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -270,7 +270,9 @@ module Rails
"action_dispatch.use_cookies_with_metadata" => config.action_dispatch.use_cookies_with_metadata,
"action_dispatch.content_security_policy" => config.content_security_policy,
"action_dispatch.content_security_policy_report_only" => config.content_security_policy_report_only,
- "action_dispatch.content_security_policy_nonce_generator" => config.content_security_policy_nonce_generator
+ "action_dispatch.content_security_policy_nonce_generator" => config.content_security_policy_nonce_generator,
+ "action_dispatch.content_security_policy_nonce_directives" => config.content_security_policy_nonce_directives,
+ "action_dispatch.feature_policy" => config.feature_policy,
)
end
end
@@ -501,7 +503,6 @@ module Rails
end
protected
-
alias :build_middleware_stack :app
def run_tasks_blocks(app) #:nodoc:
@@ -581,7 +582,6 @@ module Rails
end
private
-
def generate_development_secret
if secrets.secret_key_base.nil?
key_file = Rails.root.join("tmp/development_secret.txt")
@@ -623,7 +623,6 @@ module Rails
end
private
-
def convert_key(key)
unless key.kind_of?(Symbol)
ActiveSupport::Deprecation.warn(<<~MESSAGE.squish)
diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb
index e3c0759f95..1fdc7b2d71 100644
--- a/railties/lib/rails/application/bootstrap.rb
+++ b/railties/lib/rails/application/bootstrap.rb
@@ -19,14 +19,14 @@ module Rails
initializer :set_eager_load, group: :all do
if config.eager_load.nil?
- warn <<-INFO
-config.eager_load is set to nil. Please update your config/environments/*.rb files accordingly:
+ warn <<~INFO
+ config.eager_load is set to nil. Please update your config/environments/*.rb files accordingly:
- * development - set it to false
- * test - set it to false (unless you use a tool that preloads your test environment)
- * production - set it to true
+ * development - set it to false
+ * test - set it to false (unless you use a tool that preloads your test environment)
+ * production - set it to true
-INFO
+ INFO
config.eager_load = config.cache_classes
end
end
@@ -34,20 +34,12 @@ INFO
# Initialize the logger early in the stack in case we need to log some deprecation.
initializer :initialize_logger, group: :all do
Rails.logger ||= config.logger || begin
- path = config.paths["log"].first
- unless File.exist? File.dirname path
- FileUtils.mkdir_p File.dirname path
- end
-
- f = File.open path, "a"
- f.binmode
- f.sync = config.autoflush_log # if true make sure every write flushes
-
- logger = ActiveSupport::Logger.new f
+ logger = ActiveSupport::Logger.new(config.default_log_file)
logger.formatter = config.log_formatter
logger = ActiveSupport::TaggedLogging.new(logger)
logger
rescue StandardError
+ path = config.paths["log"].first
logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDERR))
logger.level = ActiveSupport::Logger::WARN
logger.warn(
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index 0b758dd3dd..934578e9f1 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -18,8 +18,8 @@ module Rails
:session_options, :time_zone, :reload_classes_only_on_change,
:beginning_of_week, :filter_redirect, :x, :enable_dependency_loading,
:read_encrypted_secrets, :log_level, :content_security_policy_report_only,
- :content_security_policy_nonce_generator, :require_master_key, :credentials,
- :disable_sandbox, :add_autoload_paths_to_load_path
+ :content_security_policy_nonce_generator, :content_security_policy_nonce_directives,
+ :require_master_key, :credentials, :disable_sandbox, :add_autoload_paths_to_load_path
attr_reader :encoding, :api_only, :loaded_config_version, :autoloader
@@ -60,6 +60,7 @@ module Rails
@content_security_policy = nil
@content_security_policy_report_only = false
@content_security_policy_nonce_generator = nil
+ @content_security_policy_nonce_directives = nil
@require_master_key = false
@loaded_config_version = nil
@credentials = ActiveSupport::OrderedOptions.new
@@ -68,6 +69,7 @@ module Rails
@autoloader = :classic
@disable_sandbox = false
@add_autoload_paths_to_load_path = true
+ @feature_policy = nil
end
def load_defaults(target_version)
@@ -129,6 +131,7 @@ module Rails
if respond_to?(:action_dispatch)
action_dispatch.use_cookies_with_metadata = true
+ action_dispatch.return_only_media_type_on_content_type = false
end
if respond_to?(:action_mailer)
@@ -142,6 +145,8 @@ module Rails
if respond_to?(:active_storage)
active_storage.queues.analysis = :active_storage_analysis
active_storage.queues.purge = :active_storage_purge
+
+ active_storage.replace_on_assign_to_many = true
end
if respond_to?(:active_record)
@@ -207,7 +212,7 @@ module Rails
yaml = Pathname.new(path)
erb = DummyERB.new(yaml.read)
- YAML.load(erb.result)
+ YAML.load(erb.result) || {}
else
{}
end
@@ -299,6 +304,14 @@ module Rails
end
end
+ def feature_policy(&block)
+ if block_given?
+ @feature_policy = ActionDispatch::FeaturePolicy.new(&block)
+ else
+ @feature_policy
+ end
+ end
+
def autoloader=(autoloader)
case autoloader
when :classic
@@ -311,6 +324,18 @@ module Rails
end
end
+ def default_log_file
+ path = paths["log"].first
+ unless File.exist? File.dirname path
+ FileUtils.mkdir_p File.dirname path
+ end
+
+ f = File.open path, "a"
+ f.binmode
+ f.sync = autoflush_log # if true make sure every write flushes
+ f
+ end
+
class Custom #:nodoc:
def initialize
@configurations = Hash.new
diff --git a/railties/lib/rails/application/default_middleware_stack.rb b/railties/lib/rails/application/default_middleware_stack.rb
index 9800b19274..572f51fca2 100644
--- a/railties/lib/rails/application/default_middleware_stack.rb
+++ b/railties/lib/rails/application/default_middleware_stack.rb
@@ -68,6 +68,7 @@ module Rails
unless config.api_only
middleware.use ::ActionDispatch::ContentSecurityPolicy::Middleware
+ middleware.use ::ActionDispatch::FeaturePolicy::Middleware
end
middleware.use ::Rack::Head
@@ -79,7 +80,6 @@ module Rails
end
private
-
def load_rack_cache
rack_cache = config.action_dispatch.rack_cache
return unless rack_cache
diff --git a/railties/lib/rails/application/dummy_erb_compiler.rb b/railties/lib/rails/application/dummy_erb_compiler.rb
index c4659123bb..028e790292 100644
--- a/railties/lib/rails/application/dummy_erb_compiler.rb
+++ b/railties/lib/rails/application/dummy_erb_compiler.rb
@@ -11,9 +11,8 @@ end
class DummyCompiler < ERB::Compiler # :nodoc:
def compile_content(stag, out)
- case stag
- when "<%="
- out.push "_erbout << 'dummy_compiler'"
+ if stag == "<%="
+ out.push "_erbout << ''"
end
end
end
diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb
index 109c560c80..9f4009ad20 100644
--- a/railties/lib/rails/application/finisher.rb
+++ b/railties/lib/rails/application/finisher.rb
@@ -39,8 +39,14 @@ module Rails
example = autoloaded.first
example_klass = example.constantize.class
- ActiveSupport::DescendantsTracker.clear
- ActiveSupport::Dependencies.clear
+ if config.autoloader == :zeitwerk
+ ActiveSupport::DescendantsTracker.clear
+ ActiveSupport::Dependencies.clear
+
+ unload_message = "#{these} autoloaded #{constants} #{have} been unloaded."
+ else
+ unload_message = "`config.autoloader` is set to `#{config.autoloader}`. #{these} autoloaded #{constants} would have been unloaded if `config.autoloader` had been set to `:zeitwerk`."
+ end
ActiveSupport::Deprecation.warn(<<~WARNING)
Initialization autoloaded the #{constants} #{enum}.
@@ -52,7 +58,7 @@ module Rails
initialization does not run again. So, if you reload #{example}, for example,
the expected changes won't be reflected in that stale #{example_klass} object.
- #{these} autoloaded #{constants} #{have} been unloaded.
+ #{unload_message}
Please, check the "Autoloading and Reloading Constants" guide for solutions.
WARNING
diff --git a/railties/lib/rails/application/routes_reloader.rb b/railties/lib/rails/application/routes_reloader.rb
index 3ecb8e264e..1070362253 100644
--- a/railties/lib/rails/application/routes_reloader.rb
+++ b/railties/lib/rails/application/routes_reloader.rb
@@ -25,7 +25,6 @@ module Rails
end
private
-
def updater
@updater ||= ActiveSupport::FileUpdateChecker.new(paths) { reload! }
end
diff --git a/railties/lib/rails/application_controller.rb b/railties/lib/rails/application_controller.rb
index b3fe822218..8c00633515 100644
--- a/railties/lib/rails/application_controller.rb
+++ b/railties/lib/rails/application_controller.rb
@@ -12,7 +12,6 @@ class Rails::ApplicationController < ActionController::Base # :nodoc:
end
private
-
def require_local!
unless local_request?
render html: "<p>For security purposes, this information is only available to local requests.</p>".html_safe, status: :forbidden
diff --git a/railties/lib/rails/command.rb b/railties/lib/rails/command.rb
index f09aa3ae0d..7e6e968c92 100644
--- a/railties/lib/rails/command.rb
+++ b/railties/lib/rails/command.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require "active_support"
-require "active_support/dependencies/autoload"
require "active_support/core_ext/enumerable"
require "active_support/core_ext/object/blank"
diff --git a/railties/lib/rails/command/spellchecker.rb b/railties/lib/rails/command/spellchecker.rb
index 085d5b16df..c5d0253185 100644
--- a/railties/lib/rails/command/spellchecker.rb
+++ b/railties/lib/rails/command/spellchecker.rb
@@ -13,7 +13,6 @@ module Rails
end
private
-
# This code is based directly on the Text gem implementation.
# Copyright (c) 2006-2013 Paul Battley, Michael Neumann, Tim Fletcher.
#
diff --git a/railties/lib/rails/commands/server/server_command.rb b/railties/lib/rails/commands/server/server_command.rb
index 982b83ead5..84248e03c1 100644
--- a/railties/lib/rails/commands/server/server_command.rb
+++ b/railties/lib/rails/commands/server/server_command.rb
@@ -99,7 +99,7 @@ module Rails
RACK_SERVERS = %w(cgi fastcgi webrick lsws scgi thin puma unicorn)
DEFAULT_PORT = 3000
- DEFAULT_PID_PATH = "tmp/pids/server.pid"
+ DEFAULT_PIDFILE = "tmp/pids/server.pid"
argument :using, optional: true
@@ -114,8 +114,8 @@ module Rails
desc: "Runs server as a Daemon."
class_option :using, aliases: "-u", type: :string,
desc: "Specifies the Rack server used to run the application (thin/puma/webrick).", banner: :name
- class_option :pid, aliases: "-P", type: :string, default: DEFAULT_PID_PATH,
- desc: "Specifies the PID file."
+ class_option :pid, aliases: "-P", type: :string,
+ desc: "Specifies the PID file - defaults to #{DEFAULT_PIDFILE}."
class_option :dev_caching, aliases: "-C", type: :boolean, default: nil,
desc: "Specifies whether to perform caching in development."
class_option :restart, type: :boolean, default: nil, hide: true
@@ -207,6 +207,7 @@ module Rails
end
user_supplied_options << :Host if ENV["HOST"] || ENV["BINDING"]
user_supplied_options << :Port if ENV["PORT"]
+ user_supplied_options << :pid if ENV["PIDFILE"]
user_supplied_options.uniq
end
end
@@ -253,7 +254,7 @@ module Rails
end
def pid
- File.expand_path(options[:pid])
+ File.expand_path(options[:pid] || ENV.fetch("PIDFILE", DEFAULT_PIDFILE))
end
def self.banner(*)
@@ -261,7 +262,7 @@ module Rails
end
def prepare_restart
- FileUtils.rm_f(options[:pid]) if options[:restart]
+ FileUtils.rm_f(pid) if options[:restart]
end
def deprecate_positional_rack_server_and_rewrite_to_option(original_options)
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index d1b8c7803f..46f1d38b96 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -654,14 +654,12 @@ module Rails
end
protected
-
def run_tasks_blocks(*) #:nodoc:
super
paths["lib/tasks"].existent.sort.each { |ext| load(ext) }
end
private
-
def load_config_initializer(initializer) # :doc:
ActiveSupport::Notifications.instrument("load_config_initializer.railties", initializer: initializer) do
load(initializer)
diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb
index 4143b3c881..612bd170c6 100644
--- a/railties/lib/rails/engine/configuration.rb
+++ b/railties/lib/rails/engine/configuration.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require "rails/railtie/configuration"
+require "yaml"
module Rails
class Engine
@@ -40,7 +41,7 @@ module Rails
paths.add "app", eager_load: true,
glob: "{*,*/concerns}",
- exclude: %w(assets javascript)
+ exclude: ["assets", webpacker_path]
paths.add "app/assets", glob: "*"
paths.add "app/controllers", eager_load: true
paths.add "app/channels", eager_load: true, glob: "**/*_channel.rb"
@@ -85,6 +86,14 @@ module Rails
def autoload_paths
@autoload_paths ||= paths.autoload_paths
end
+
+ def webpacker_path
+ if File.file?("#{Rails.root}/config/webpacker.yml")
+ YAML.load_file("#{Rails.root}/config/webpacker.yml")[Rails.env]["source_path"]&.gsub("app/", "")
+ else
+ "javascript"
+ end
+ end
end
end
end
diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb
index 0be00d5151..436315ce1e 100644
--- a/railties/lib/rails/generators.rb
+++ b/railties/lib/rails/generators.rb
@@ -6,8 +6,6 @@ $:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.inc
require "thor/group"
require "rails/command"
-require "active_support"
-require "active_support/core_ext/object/blank"
require "active_support/core_ext/kernel/singleton_class"
require "active_support/core_ext/array/extract_options"
require "active_support/core_ext/hash/deep_merge"
@@ -287,7 +285,6 @@ module Rails
end
private
-
def print_list(base, namespaces) # :doc:
namespaces = namespaces.reject { |n| hidden_namespaces.include?(n) }
super
diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb
index 1a5f2ff203..b6225cd8c0 100644
--- a/railties/lib/rails/generators/actions.rb
+++ b/railties/lib/rails/generators/actions.rb
@@ -40,8 +40,7 @@ module Rails
in_root do
str = "gem #{parts.join(", ")}"
str = indentation + str
- str = "\n" + str
- append_file "Gemfile", str, verbose: false
+ append_file_with_newline "Gemfile", str, verbose: false
end
end
@@ -58,9 +57,9 @@ module Rails
log :gemfile, "group #{str}"
in_root do
- append_file "Gemfile", "\ngroup #{str} do", force: true
+ append_file_with_newline "Gemfile", "\ngroup #{str} do", force: true
with_indentation(&block)
- append_file "Gemfile", "\nend\n", force: true
+ append_file_with_newline "Gemfile", "end", force: true
end
end
@@ -71,9 +70,13 @@ module Rails
log :github, "github #{str}"
in_root do
- append_file "Gemfile", "\n#{indentation}github #{str} do", force: true
+ if @indentation.zero?
+ append_file_with_newline "Gemfile", "\ngithub #{str} do", force: true
+ else
+ append_file_with_newline "Gemfile", "#{indentation}github #{str} do", force: true
+ end
with_indentation(&block)
- append_file "Gemfile", "\n#{indentation}end", force: true
+ append_file_with_newline "Gemfile", "#{indentation}end", force: true
end
end
@@ -91,9 +94,9 @@ module Rails
in_root do
if block
- append_file "Gemfile", "\nsource #{quote(source)} do", force: true
+ append_file_with_newline "Gemfile", "\nsource #{quote(source)} do", force: true
with_indentation(&block)
- append_file "Gemfile", "\nend\n", force: true
+ append_file_with_newline "Gemfile", "end", force: true
else
prepend_file "Gemfile", "source #{quote(source)}\n", verbose: false
end
@@ -268,7 +271,6 @@ module Rails
end
private
-
# Define log for backwards compatibility. If just one argument is sent,
# invoke say, otherwise invoke say_status. Differently from say and
# similarly to say_status, this method respects the quiet? option given.
@@ -345,6 +347,13 @@ module Rails
ensure
@indentation -= 1
end
+
+ # Append string to a file with a newline if necessary
+ def append_file_with_newline(path, str, options = {})
+ gsub_file path, /\n?\z/, options do |match|
+ match.end_with?("\n") ? "" : "\n#{str}\n"
+ end
+ end
end
end
end
diff --git a/railties/lib/rails/generators/actions/create_migration.rb b/railties/lib/rails/generators/actions/create_migration.rb
index 05bc242447..67a8139cd3 100644
--- a/railties/lib/rails/generators/actions/create_migration.rb
+++ b/railties/lib/rails/generators/actions/create_migration.rb
@@ -40,7 +40,6 @@ module Rails
alias :exists? :existing_migration
private
-
def on_conflict_behavior # :doc:
options = base.options.merge(config)
if identical?
diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index 7e3560d9d2..dbfb7337f0 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -108,7 +108,6 @@ module Rails
end
private
-
def gemfile_entry(name, *args) # :doc:
options = args.extract_options!
version = args.first
@@ -307,7 +306,7 @@ module Rails
def assets_gemfile_entry
return [] if options[:skip_sprockets]
- GemfileEntry.version("sass-rails", "~> 5", "Use SCSS for stylesheets")
+ GemfileEntry.version("sass-rails", ">= 5", "Use SCSS for stylesheets")
end
def webpacker_gemfile_entry
@@ -322,7 +321,7 @@ module Rails
def jbuilder_gemfile_entry
comment = "Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder"
- GemfileEntry.new "jbuilder", "~> 2.5", comment, {}, options[:api]
+ GemfileEntry.new "jbuilder", "~> 2.7", comment, {}, options[:api]
end
def javascript_gemfile_entry
diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb
index 5523a3f659..a153923ce3 100644
--- a/railties/lib/rails/generators/base.rb
+++ b/railties/lib/rails/generators/base.rb
@@ -20,6 +20,8 @@ module Rails
class_option :skip_namespace, type: :boolean, default: false,
desc: "Skip namespace (affects only isolated applications)"
+ class_option :skip_collision_check, type: :boolean, default: false,
+ desc: "Skip collision check"
add_runtime_options!
strict_args_position!
@@ -245,11 +247,11 @@ module Rails
end
private
-
# Check whether the given class names are already taken by user
# application or Ruby on Rails.
def class_collisions(*class_names)
return unless behavior == :invoke
+ return if options.skip_collision_check?
class_names.flatten.each do |class_name|
class_name = class_name.to_s
@@ -262,8 +264,8 @@ module Rails
if last && last.const_defined?(last_name.camelize, false)
raise Error, "The name '#{class_name}' is either already used in your application " \
- "or reserved by Ruby on Rails. Please choose an alternative and run " \
- "this generator again."
+ "or reserved by Ruby on Rails. Please choose an alternative or use --skip-collision-check " \
+ "to skip this check and run this generator again."
end
end
end
diff --git a/railties/lib/rails/generators/erb.rb b/railties/lib/rails/generators/erb.rb
index ba20bcd32a..aab2d634d3 100644
--- a/railties/lib/rails/generators/erb.rb
+++ b/railties/lib/rails/generators/erb.rb
@@ -6,7 +6,6 @@ module Erb # :nodoc:
module Generators # :nodoc:
class Base < Rails::Generators::NamedBase #:nodoc:
private
-
def formats
[format]
end
diff --git a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb
index 997602cb8c..f66be1ee44 100644
--- a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb
+++ b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb
@@ -29,7 +29,6 @@ module Erb # :nodoc:
end
private
-
def formats
[:text, :html]
end
diff --git a/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb
index 2fc04e4094..6d3bccab0b 100644
--- a/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb
+++ b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb
@@ -24,7 +24,6 @@ module Erb # :nodoc:
end
private
-
def available_views
%w(index edit show new _form)
end
diff --git a/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb.tt b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb.tt
index 6b216001d2..d3f996188c 100644
--- a/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb.tt
+++ b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb.tt
@@ -4,7 +4,7 @@
<p>
<strong><%= attribute.human_name %>:</strong>
<% if attribute.attachment? -%>
- <%%= link_to @<%= singular_table_name %>.<%= attribute.column_name %>.filename, @<%= singular_table_name %>.<%= attribute.column_name %> %>
+ <%%= link_to @<%= singular_table_name %>.<%= attribute.column_name %>.filename, @<%= singular_table_name %>.<%= attribute.column_name %> if @<%= singular_table_name %>.<%= attribute.column_name %>.attached? %>
<% elsif attribute.attachments? -%>
<%% @<%= singular_table_name %>.<%= attribute.column_name %>.each do |<%= attribute.singular_name %>| %>
<div><%%= link_to <%= attribute.singular_name %>.filename, <%= attribute.singular_name %> %></div>
diff --git a/railties/lib/rails/generators/generated_attribute.rb b/railties/lib/rails/generators/generated_attribute.rb
index 1a80e71eae..4e348be9be 100644
--- a/railties/lib/rails/generators/generated_attribute.rb
+++ b/railties/lib/rails/generators/generated_attribute.rb
@@ -39,7 +39,6 @@ module Rails
end
private
-
# parse possible attribute options like :limit for string/text/binary/integer, :precision/:scale for decimals or :polymorphic for references/belongs_to
# when declaring options curly brackets should be used
def parse_type_and_options(type)
diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb
index 42e64cd11f..d6732f8ff1 100644
--- a/railties/lib/rails/generators/named_base.rb
+++ b/railties/lib/rails/generators/named_base.rb
@@ -187,7 +187,6 @@ module Rails
def attributes_names # :doc:
@attributes_names ||= attributes.each_with_object([]) do |a, names|
- next if a.attachments?
names << a.column_name
names << "password_confirmation" if a.password_digest?
names << "#{a.name}_type" if a.polymorphic?
diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb
index f2f46d6e25..ea3968bf39 100644
--- a/railties/lib/rails/generators/rails/app/app_generator.rb
+++ b/railties/lib/rails/generators/rails/app/app_generator.rb
@@ -243,7 +243,9 @@ module Rails
# can change in Ruby 1.8.7 when we FileUtils.cd.
RAILS_DEV_PATH = File.expand_path("../../../../../..", __dir__)
- class AppGenerator < AppBase # :nodoc:
+ class AppGenerator < AppBase
+ # :stopdoc:
+
WEBPACKS = %w( react vue angular elm stimulus )
add_shared_options_for "application"
@@ -492,8 +494,9 @@ module Rails
"rails new #{arguments.map(&:usage).join(' ')} [options]"
end
- private
+ # :startdoc:
+ private
# Define file as an alias to create_file for backwards compatibility.
def file(*args, &block)
create_file(*args, &block)
@@ -538,7 +541,6 @@ module Rails
end
private
-
def handle_version_request!(argument)
if ["--version", "-v"].include?(argument)
require "rails/version"
diff --git a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt
index 9a7267c783..b8c1f21c0b 100644
--- a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt
@@ -6,7 +6,7 @@
<%%= csp_meta_tag %>
<%- if options[:skip_javascript] -%>
- <%%= stylesheet_link_tag 'application', media: 'all' %>
+ <%%= stylesheet_link_tag 'application', media: 'all' %>
<%- else -%>
<%- unless options[:skip_turbolinks] -%>
<%%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt
index 371415e6a8..006b0a74c3 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt
@@ -1,4 +1,4 @@
-# SQLite version 3.x
+# SQLite. Versions 3.8.0 and up are supported.
# gem 'activerecord-jdbcsqlite3-adapter'
#
# Configure Using Gemfile
diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt
index 9510568124..a7c2bf2eac 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt
@@ -1,4 +1,4 @@
-# SQLite version 3.x
+# SQLite. Versions 3.8.0 and up are supported.
# gem install sqlite3
#
# Ensure the SQLite 3 gem is defined in your Gemfile
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt
index c517b0f96b..3d468f7633 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt
@@ -23,6 +23,9 @@
# If you are using UJS then enable automatic nonce generation
# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
+# Set the nonce only to specific directives
+# Rails.application.config.content_security_policy_nonce_directives = %w(script-src)
+
# Report CSP violations to a specified URI
# For further information see the following documentation:
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/feature_policy.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/feature_policy.rb.tt
new file mode 100644
index 0000000000..a1c46695d2
--- /dev/null
+++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/feature_policy.rb.tt
@@ -0,0 +1,11 @@
+# Define an application-wide HTTP feature policy. For further
+# information see https://developers.google.com/web/updates/2018/06/feature-policy
+#
+# Rails.application.config.feature_policy do |f|
+# f.camera :none
+# f.gyroscope :none
+# f.microphone :none
+# f.usb :none
+# f.fullscreen :self
+# f.payment :self, "https://secure.example.com"
+# end
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt
index 4a994e1e7b..eea99edb65 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt
@@ -1,4 +1,6 @@
# Be sure to restart your server when you modify this file.
# Configure sensitive parameters which will be filtered from the log file.
-Rails.application.config.filter_parameters += [:password]
+Rails.application.config.filter_parameters += [
+ :password, :secret, :token, :_key, :auth, :crypt, :salt, :certificate, :otp, :access, :private, :protected, :ssn
+]
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_6_0.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_6_0.rb.tt
index d25552e923..2510ab906f 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_6_0.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_6_0.rb.tt
@@ -16,6 +16,9 @@
# It's best enabled when your entire app is migrated and stable on 6.0.
# Rails.application.config.action_dispatch.use_cookies_with_metadata = true
+# Change the return value of `ActionDispatch::Response#content_type` to Content-Type header without modification.
+# Rails.application.config.action_dispatch.return_only_media_type_on_content_type = true
+
# Return false instead of self when enqueuing is aborted from a callback.
# Rails.application.config.active_job.return_false_on_aborted_enqueue = true
@@ -23,6 +26,10 @@
# Rails.application.config.active_storage.queues.analysis = :active_storage_analysis
# Rails.application.config.active_storage.queues.purge = :active_storage_purge
+# When assigning to a collection of attachments declared via `has_many_attached`, replace existing
+# attachments instead of appending. Use #attach to add new attachments without replacing existing ones.
+# Rails.application.config.active_storage.replace_on_assign_to_many = true
+
# Use ActionMailer::MailDeliveryJob for sending parameterized and normal mail.
#
# The default delivery jobs (ActionMailer::Parameterized::DeliveryJob, ActionMailer::DeliveryJob),
@@ -31,3 +38,8 @@
# MailDeliveryJob to ensure all delivery jobs are processed properly.
# Make sure your entire app is migrated and stable on 6.0 before using this setting.
# Rails.application.config.action_mailer.delivery_job = "ActionMailer::MailDeliveryJob"
+
+# Enable the same cache key to be reused when the object being cached of type
+# `ActiveRecord::Relation` changes by moving the volatile information (max updated at and count)
+# of the relation's cache key into the cache version to support recycling cache key.
+# Rails.application.config.active_record.collection_cache_versioning = true
diff --git a/railties/lib/rails/generators/rails/app/templates/config/puma.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/puma.rb.tt
index 649253aeca..5ed4437744 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/puma.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/puma.rb.tt
@@ -16,6 +16,9 @@ port ENV.fetch("PORT") { 3000 }
#
environment ENV.fetch("RAILS_ENV") { "development" }
+# Specifies the `pidfile` that Puma will use.
+pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
+
# Specifies the number of `workers` to boot in clustered mode.
# Workers are forked web server processes. If using threads and workers together
# the concurrency of the application would be max `threads` * `workers`.
diff --git a/railties/lib/rails/generators/rails/app/templates/public/robots.txt b/railties/lib/rails/generators/rails/app/templates/public/robots.txt
index 37b576a4a0..c19f78ab68 100644
--- a/railties/lib/rails/generators/rails/app/templates/public/robots.txt
+++ b/railties/lib/rails/generators/rails/app/templates/public/robots.txt
@@ -1 +1 @@
-# See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
+# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
diff --git a/railties/lib/rails/generators/rails/controller/controller_generator.rb b/railties/lib/rails/generators/rails/controller/controller_generator.rb
index eb75e7e661..88729545f3 100644
--- a/railties/lib/rails/generators/rails/controller/controller_generator.rb
+++ b/railties/lib/rails/generators/rails/controller/controller_generator.rb
@@ -25,7 +25,6 @@ module Rails
end
private
-
def file_name
@_file_name ||= remove_possible_suffix(super)
end
diff --git a/railties/lib/rails/generators/rails/generator/generator_generator.rb b/railties/lib/rails/generators/rails/generator/generator_generator.rb
index 747acd68d1..b0146641b4 100644
--- a/railties/lib/rails/generators/rails/generator/generator_generator.rb
+++ b/railties/lib/rails/generators/rails/generator/generator_generator.rb
@@ -15,7 +15,6 @@ module Rails
hook_for :test_framework
private
-
def generator_dir
if options[:namespace]
File.join("lib", "generators", regular_class_path, file_name)
diff --git a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb
index 895b3b2e92..4c18bdb430 100644
--- a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb
+++ b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb
@@ -269,7 +269,6 @@ task default: :test
end
private
-
def create_dummy_app(path = nil)
dummy_path(path) if path
diff --git a/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb b/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb
index 8b46eb88ae..b2cdeee6d1 100644
--- a/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb
+++ b/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb
@@ -34,11 +34,16 @@ module Rails
end
private
-
def permitted_params
- params = attributes_names.map { |name| ":#{name}" }.join(", ")
- params += attributes.select(&:attachments?).map { |a| ", #{a.name}: []" }.join
- params
+ attachments, others = attributes_names.partition { |name| attachments?(name) }
+ params = others.map { |name| ":#{name}" }
+ params += attachments.map { |name| "#{name}: []" }
+ params.join(", ")
+ end
+
+ def attachments?(name)
+ attribute = attributes.find { |attr| attr.name == name }
+ attribute&.attachments?
end
end
end
diff --git a/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb.tt b/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb.tt
index ff41fef9e9..a69a24e281 100644
--- a/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb.tt
+++ b/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb.tt
@@ -16,7 +16,7 @@ class <%= class_name %>ControllerTest < ActionDispatch::IntegrationTest
get <%= url_helper_prefix %>_<%= action %>_url
assert_response :success
end
-
+<%= "\n" unless action == actions.last -%>
<% end -%>
<% end -%>
end
diff --git a/railties/lib/rails/generators/test_unit/generator/generator_generator.rb b/railties/lib/rails/generators/test_unit/generator/generator_generator.rb
index 19be4f2f51..ae7e28580e 100644
--- a/railties/lib/rails/generators/test_unit/generator/generator_generator.rb
+++ b/railties/lib/rails/generators/test_unit/generator/generator_generator.rb
@@ -15,7 +15,6 @@ module TestUnit # :nodoc:
end
private
-
def generator_path
if options[:namespace]
File.join("generators", regular_class_path, file_name, "#{file_name}_generator")
diff --git a/railties/lib/rails/generators/test_unit/integration/integration_generator.rb b/railties/lib/rails/generators/test_unit/integration/integration_generator.rb
index ba27ed329b..86fea3f677 100644
--- a/railties/lib/rails/generators/test_unit/integration/integration_generator.rb
+++ b/railties/lib/rails/generators/test_unit/integration/integration_generator.rb
@@ -12,7 +12,6 @@ module TestUnit # :nodoc:
end
private
-
def file_name
@_file_name ||= super.sub(/_test\z/i, "")
end
diff --git a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb
index 6df50c3217..a4bc81cad6 100644
--- a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb
+++ b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb
@@ -38,7 +38,6 @@ module TestUnit # :nodoc:
end
private
-
def attributes_string
attributes_hash.map { |k, v| "#{k}: #{v}" }.join(", ")
end
@@ -49,16 +48,21 @@ module TestUnit # :nodoc:
attributes_names.map do |name|
if %w(password password_confirmation).include?(name) && attributes.any?(&:password_digest?)
["#{name}", "'secret'"]
- else
+ elsif !virtual?(name)
["#{name}", "@#{singular_table_name}.#{name}"]
end
- end.sort.to_h
+ end.compact.sort.to_h
end
def boolean?(name)
attribute = attributes.find { |attr| attr.name == name }
attribute&.type == :boolean
end
+
+ def virtual?(name)
+ attribute = attributes.find { |attr| attr.name == name }
+ attribute&.virtual?
+ end
end
end
end
diff --git a/railties/lib/rails/generators/testing/behaviour.rb b/railties/lib/rails/generators/testing/behaviour.rb
index ec29ad12ba..a092faec89 100644
--- a/railties/lib/rails/generators/testing/behaviour.rb
+++ b/railties/lib/rails/generators/testing/behaviour.rb
@@ -88,7 +88,6 @@ module Rails
end
private
-
def destination_root_is_set?
raise "You need to configure your Rails::Generators::TestCase destination root." unless destination_root
end
diff --git a/railties/lib/rails/info_controller.rb b/railties/lib/rails/info_controller.rb
index f74d979721..d51010d422 100644
--- a/railties/lib/rails/info_controller.rb
+++ b/railties/lib/rails/info_controller.rb
@@ -33,7 +33,6 @@ class Rails::InfoController < Rails::ApplicationController # :nodoc:
end
private
-
def match_route
_routes.routes.select { |route|
yield route.path
diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb
index 8367ac8980..0664338e0b 100644
--- a/railties/lib/rails/paths.rb
+++ b/railties/lib/rails/paths.rb
@@ -98,7 +98,6 @@ module Rails
end
private
-
def filter_by(&block)
all_paths.find_all(&block).flat_map { |path|
paths = path.existent
@@ -223,14 +222,11 @@ module Rails
alias to_a expanded
private
-
def files_in(path)
- Dir.chdir(path) do
- files = Dir.glob(@glob)
- files -= @exclude if @exclude
- files.map! { |file| File.join(path, file) }
- files.sort
- end
+ files = Dir.glob(@glob, base: path)
+ files -= @exclude if @exclude
+ files.map! { |file| File.join(path, file) }
+ files.sort
end
end
end
diff --git a/railties/lib/rails/rack/logger.rb b/railties/lib/rails/rack/logger.rb
index 3a95b55811..8d69663dbd 100644
--- a/railties/lib/rails/rack/logger.rb
+++ b/railties/lib/rails/rack/logger.rb
@@ -30,7 +30,6 @@ module Rails
end
private
-
def call_app(request, env) # :doc:
instrumenter = ActiveSupport::Notifications.instrumenter
instrumenter.start "request.action_dispatch", request: request
diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb
index a67b90e285..178c584f95 100644
--- a/railties/lib/rails/railtie.rb
+++ b/railties/lib/rails/railtie.rb
@@ -228,7 +228,6 @@ module Rails
end
protected
-
def run_console_blocks(app) #:nodoc:
each_registered_block(:console) { |block| block.call(app) }
end
@@ -247,7 +246,6 @@ module Rails
end
private
-
# run `&block` in every registered block in `#register_block_for`
def each_registered_block(type, &block)
klass = self.class
diff --git a/railties/lib/rails/railtie/configurable.rb b/railties/lib/rails/railtie/configurable.rb
index 7f42fae10a..ba14089a2a 100644
--- a/railties/lib/rails/railtie/configurable.rb
+++ b/railties/lib/rails/railtie/configurable.rb
@@ -27,7 +27,6 @@ module Rails
end
private
-
def method_missing(*args, &block)
instance.send(*args, &block)
end
diff --git a/railties/lib/rails/railtie/configuration.rb b/railties/lib/rails/railtie/configuration.rb
index 70274b948c..c90fcac51a 100644
--- a/railties/lib/rails/railtie/configuration.rb
+++ b/railties/lib/rails/railtie/configuration.rb
@@ -87,7 +87,6 @@ module Rails
end
private
-
def method_missing(name, *args, &blk)
if name.to_s =~ /=$/
@@options[$`.to_sym] = args.first
diff --git a/railties/lib/rails/source_annotation_extractor.rb b/railties/lib/rails/source_annotation_extractor.rb
index 9ce22b96a6..77a99036ec 100644
--- a/railties/lib/rails/source_annotation_extractor.rb
+++ b/railties/lib/rails/source_annotation_extractor.rb
@@ -2,11 +2,6 @@
require "active_support/deprecation"
-# Remove this deprecated class in the next minor version
-#:nodoc:
-SourceAnnotationExtractor = ActiveSupport::Deprecation::DeprecatedConstantProxy.
- new("SourceAnnotationExtractor", "Rails::SourceAnnotationExtractor")
-
module Rails
# Implements the logic behind <tt>Rails::Command::NotesCommand</tt>. See <tt>rails notes --help</tt> for usage information.
#
@@ -160,3 +155,8 @@ module Rails
end
end
end
+
+# Remove this deprecated class in the next minor version
+#:nodoc:
+SourceAnnotationExtractor = ActiveSupport::Deprecation::DeprecatedConstantProxy.
+ new("SourceAnnotationExtractor", "Rails::SourceAnnotationExtractor")
diff --git a/railties/lib/rails/tasks/zeitwerk.rake b/railties/lib/rails/tasks/zeitwerk.rake
index b7f5cd154b..5421af6e8b 100644
--- a/railties/lib/rails/tasks/zeitwerk.rake
+++ b/railties/lib/rails/tasks/zeitwerk.rake
@@ -1,78 +1,66 @@
# frozen_string_literal: true
-ensure_classic_mode = ->() do
- if Rails.autoloaders.zeitwerk_enabled?
- abort <<~EOS
- Please, enable temporarily :classic mode:
-
- # config/application.rb
- config.autoloader = :classic
-
- and try again. When all is good, you can delete that line.
- EOS
+ensure_zeitwerk_mode = ->() do
+ unless Rails.autoloaders.zeitwerk_enabled?
+ abort "Please, enable :zeitwerk mode in config/application.rb and try again."
end
end
eager_load = ->() do
- Rails.configuration.eager_load_namespaces.each(&:eager_load!)
+ puts "Hold on, I am eager loading the application."
+ Zeitwerk::Loader.eager_load_all
end
-mismatches = []
-check_directory = ->(directory, parent) do
- # test/mailers/previews might not exist.
- return unless File.exist?(directory)
-
- Dir.foreach(directory) do |entry|
- next if entry.start_with?(".")
- next if parent == Object && entry == "concerns"
+report_not_checked = ->(not_checked) do
+ puts
+ puts <<~EOS
+ WARNING: The files in these directories cannot be checked because they
+ are not eager loaded:
+ EOS
+ puts
- abspath = File.join(directory, entry)
+ not_checked.each { |dir| puts " #{dir}" }
+ puts
- if File.directory?(abspath) || abspath.end_with?(".rb")
- print "."
- cname = File.basename(abspath, ".rb").camelize.to_sym
- if parent.const_defined?(cname, false)
- if File.directory?(abspath)
- check_directory[abspath, parent.const_get(cname)]
- end
- else
- mismatches << [abspath, parent, cname]
- end
- end
- end
+ puts <<~EOS
+ You may verify them manually, or add them to config.eager_load_paths
+ in config/application.rb and run zeitwerk:check again.
+ EOS
+ puts
end
-report = ->() do
- puts
- if mismatches.empty?
- puts "All is good!"
- puts "Please, remember to delete `config.autoloader = :classic` from config/application.rb."
+report = ->(not_checked) do
+ if not_checked.any?
+ report_not_checked[not_checked]
+ puts "Otherwise, all is good!"
else
- mismatches.each do |abspath, parent, cname|
- relpath = abspath.sub(%r{\A#{Regexp.escape(Rails.root.to_path)}/}, "")
- cpath = parent == Object ? cname : "#{parent.name}::#{cname}"
- puts "expected #{relpath} to define #{cpath}"
- end
- puts
- puts <<~EOS
- Please revise the reported mismatches. You can normally fix them by adding
- acronyms to config/initializers/inflections.rb or renaming the constants.
- EOS
+ puts "All is good!"
end
end
namespace :zeitwerk do
desc "Checks project structure for Zeitwerk compatibility"
task check: :environment do
- ensure_classic_mode[]
- eager_load[]
+ ensure_zeitwerk_mode[]
- $stdout.sync = true
- ActiveSupport::Dependencies.autoload_paths.each do |autoload_path|
- check_directory[autoload_path, Object]
+ begin
+ eager_load[]
+ rescue NameError => e
+ if e.message =~ /expected file .*? to define constant \S+/
+ abort $&.sub(/#{Regexp.escape(Rails.root.to_s)}./, "")
+ else
+ raise
+ end
end
- puts
- report[]
+ eager_load_paths = Rails.configuration.eager_load_namespaces.map do |eln|
+ eln.config.eager_load_paths if eln.respond_to?(:config)
+ end.compact.flatten
+
+ not_checked = ActiveSupport::Dependencies.autoload_paths - eager_load_paths
+ not_checked.select! { |dir| Dir.exist?(dir) }
+ not_checked.reject! { |dir| Dir.empty?(dir) }
+
+ report[not_checked]
end
end
diff --git a/railties/lib/rails/test_unit/runner.rb b/railties/lib/rails/test_unit/runner.rb
index d38952bb30..7b294751fc 100644
--- a/railties/lib/rails/test_unit/runner.rb
+++ b/railties/lib/rails/test_unit/runner.rb
@@ -45,7 +45,7 @@ module Rails
patterns = extract_filters(argv)
tests = Rake::FileList[patterns.any? ? patterns : "test/**/*_test.rb"]
- tests.exclude("test/system/**/*") if patterns.empty?
+ tests.exclude("test/system/**/*", "test/dummy/**/*") if patterns.empty?
tests.to_a.each { |path| require File.expand_path(path) }
end
diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb
index a80581211b..a7dd233f3d 100644
--- a/railties/test/application/assets_test.rb
+++ b/railties/test/application/assets_test.rb
@@ -491,7 +491,6 @@ module ApplicationTests
end
private
-
def app_with_assets_in_view
app_file "app/assets/javascripts/application.js", "//= require_tree ."
app_file "app/assets/javascripts/xmlhr.js", "function f1() { alert(); }"
diff --git a/railties/test/application/bin_setup_test.rb b/railties/test/application/bin_setup_test.rb
index aa0da0931d..d84ab61cf9 100644
--- a/railties/test/application/bin_setup_test.rb
+++ b/railties/test/application/bin_setup_test.rb
@@ -31,7 +31,7 @@ module ApplicationTests
Dir.chdir(app_path) do
# SQLite3 seems to auto-create the database on first checkout.
rails "db:system:change", "--to=postgresql"
- rails "db:drop"
+ rails "db:drop", allow_failure: true
app_file "db/schema.rb", ""
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index 7c613585e0..38dda20bec 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -1607,6 +1607,13 @@ module ApplicationTests
assert_not_nil Rails::SourceAnnotationExtractor::Annotation.extensions[/\.(coffee)$/]
end
+ test "config.default_log_file returns a File instance" do
+ app "development"
+
+ assert_instance_of File, app.config.default_log_file
+ assert_equal Rails.application.config.paths["log"].first, app.config.default_log_file.path
+ end
+
test "rake_tasks block works at instance level" do
app_file "config/environments/development.rb", <<-RUBY
Rails.application.configure do
@@ -1701,7 +1708,7 @@ module ApplicationTests
app "development"
ActiveSupport::Dependencies.autoload_paths.each do |path|
assert_not_operator path, :ends_with?, "app/assets"
- assert_not_operator path, :ends_with?, "app/javascript"
+ assert_not_operator path, :ends_with?, "app/#{Rails.configuration.webpacker_path}"
end
end
@@ -1786,6 +1793,11 @@ module ApplicationTests
assert_equal [X, D], C.descendants
end
+ test "load_database_yaml returns blank hash if configuration file is blank" do
+ app_file "config/database.yml", ""
+ app "development"
+ assert_equal({}, Rails.application.config.load_database_yaml)
+ end
test "raises with proper error message if no database configuration found" do
FileUtils.rm("#{app_path}/config/database.yml")
@@ -2429,6 +2441,33 @@ module ApplicationTests
assert_nil ActiveStorage.queues[:purge]
end
+ test "ActionDispatch::Response.return_only_media_type_on_content_type is false by default" do
+ app "development"
+
+ assert_equal false, ActionDispatch::Response.return_only_media_type_on_content_type
+ end
+
+ test "ActionDispatch::Response.return_only_media_type_on_content_type is true in the 5.x defaults" do
+ remove_from_config '.*config\.load_defaults.*\n'
+ add_to_config 'config.load_defaults "5.2"'
+
+ app "development"
+
+ assert_equal true, ActionDispatch::Response.return_only_media_type_on_content_type
+ end
+
+ test "ActionDispatch::Response.return_only_media_type_on_content_type can be configured in the new framework defaults" do
+ remove_from_config '.*config\.load_defaults.*\n'
+
+ app_file "config/initializers/new_framework_defaults_6_0.rb", <<-RUBY
+ Rails.application.config.action_dispatch.return_only_media_type_on_content_type = true
+ RUBY
+
+ app "development"
+
+ assert_equal true, ActionDispatch::Response.return_only_media_type_on_content_type
+ end
+
test "ActionMailbox.logger is Rails.logger by default" do
app "development"
@@ -2554,6 +2593,21 @@ module ApplicationTests
MESSAGE
end
+ test "ActiveStorage.draw_routes can be configured via config.active_storage.draw_routes" do
+ app_file "config/environments/development.rb", <<-RUBY
+ Rails.application.configure do
+ config.active_storage.draw_routes = false
+ end
+ RUBY
+
+ output = rails("routes")
+ assert_not_includes(output, "rails_service_blob")
+ assert_not_includes(output, "rails_blob_representation")
+ assert_not_includes(output, "rails_disk_service")
+ assert_not_includes(output, "update_rails_disk_service")
+ assert_not_includes(output, "rails_direct_uploads")
+ end
+
test "hosts include .localhost in development" do
app "development"
assert_includes Rails.application.config.hosts, ".localhost"
diff --git a/railties/test/application/content_security_policy_test.rb b/railties/test/application/content_security_policy_test.rb
index 0d28df16f8..0bb6ee917a 100644
--- a/railties/test/application/content_security_policy_test.rb
+++ b/railties/test/application/content_security_policy_test.rb
@@ -119,6 +119,38 @@ module ApplicationTests
assert_policy "default-src 'self' https:", report_only: true
end
+ test "global content security policy nonce directives in an initializer" do
+ controller :pages, <<-RUBY
+ class PagesController < ApplicationController
+ def index
+ render html: "<h1>Welcome to Rails!</h1>"
+ end
+ end
+ RUBY
+
+ app_file "config/initializers/content_security_policy.rb", <<-RUBY
+ Rails.application.config.content_security_policy do |p|
+ p.default_src :self, :https
+ p.script_src :self, :https
+ p.style_src :self, :https
+ end
+
+ Rails.application.config.content_security_policy_nonce_generator = proc { "iyhD0Yc0W+c=" }
+ Rails.application.config.content_security_policy_nonce_directives = %w(script-src)
+ RUBY
+
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ root to: "pages#index"
+ end
+ RUBY
+
+ app("development")
+
+ get "/"
+ assert_policy "default-src 'self' https:; script-src 'self' https: 'nonce-iyhD0Yc0W+c='; style-src 'self' https:"
+ end
+
test "override content security policy in a controller" do
controller :pages, <<-RUBY
class PagesController < ApplicationController
@@ -204,7 +236,6 @@ module ApplicationTests
end
private
-
def assert_policy(expected, report_only: false)
assert_equal 200, last_response.status
diff --git a/railties/test/application/feature_policy_test.rb b/railties/test/application/feature_policy_test.rb
new file mode 100644
index 0000000000..e751d782ee
--- /dev/null
+++ b/railties/test/application/feature_policy_test.rb
@@ -0,0 +1,191 @@
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+require "rack/test"
+
+module ApplicationTests
+ class FeaturePolicyTest < ActiveSupport::TestCase
+ include ActiveSupport::Testing::Isolation
+ include Rack::Test::Methods
+
+ def setup
+ build_app
+ end
+
+ def teardown
+ teardown_app
+ end
+
+ test "feature policy is not enabled by default" do
+ controller :pages, <<-RUBY
+ class PagesController < ApplicationController
+ def index
+ render html: "<h1>Welcome to Rails!</h1>"
+ end
+ end
+ RUBY
+
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ root to: "pages#index"
+ end
+ RUBY
+
+ app("development")
+
+ get "/"
+ assert_nil last_response.headers["Feature-Policy"]
+ end
+
+ test "global feature policy in an initializer" do
+ controller :pages, <<-RUBY
+ class PagesController < ApplicationController
+ def index
+ render html: "<h1>Welcome to Rails!</h1>"
+ end
+ end
+ RUBY
+
+ app_file "config/initializers/feature_policy.rb", <<-RUBY
+ Rails.application.config.feature_policy do |p|
+ p.geolocation :none
+ end
+ RUBY
+
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ root to: "pages#index"
+ end
+ RUBY
+
+ app("development")
+
+ get "/"
+ assert_policy "geolocation 'none'"
+ end
+
+ test "override feature policy using same directive in a controller" do
+ controller :pages, <<-RUBY
+ class PagesController < ApplicationController
+ feature_policy do |p|
+ p.geolocation "https://example.com"
+ end
+
+ def index
+ render html: "<h1>Welcome to Rails!</h1>"
+ end
+ end
+ RUBY
+
+ app_file "config/initializers/feature_policy.rb", <<-RUBY
+ Rails.application.config.feature_policy do |p|
+ p.geolocation :none
+ end
+ RUBY
+
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ root to: "pages#index"
+ end
+ RUBY
+
+ app("development")
+
+ get "/"
+ assert_policy "geolocation https://example.com"
+ end
+
+ test "override feature policy by unsetting a directive in a controller" do
+ controller :pages, <<-RUBY
+ class PagesController < ApplicationController
+ feature_policy do |p|
+ p.geolocation nil
+ end
+
+ def index
+ render html: "<h1>Welcome to Rails!</h1>"
+ end
+ end
+ RUBY
+
+ app_file "config/initializers/feature_policy.rb", <<-RUBY
+ Rails.application.config.feature_policy do |p|
+ p.geolocation :none
+ end
+ RUBY
+
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ root to: "pages#index"
+ end
+ RUBY
+
+ app("development")
+
+ get "/"
+ assert_equal 200, last_response.status
+ assert_nil last_response.headers["Feature-Policy"]
+ end
+
+ test "override feature policy using different directives in a controller" do
+ controller :pages, <<-RUBY
+ class PagesController < ApplicationController
+ feature_policy do |p|
+ p.geolocation nil
+ p.payment "https://secure.example.com"
+ p.autoplay :none
+ end
+
+ def index
+ render html: "<h1>Welcome to Rails!</h1>"
+ end
+ end
+ RUBY
+
+ app_file "config/initializers/feature_policy.rb", <<-RUBY
+ Rails.application.config.feature_policy do |p|
+ p.geolocation :none
+ end
+ RUBY
+
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ root to: "pages#index"
+ end
+ RUBY
+
+ app("development")
+
+ get "/"
+ assert_policy "payment https://secure.example.com; autoplay 'none'"
+ end
+
+ test "global feature policy added to rack app" do
+ app_file "config/initializers/feature_policy.rb", <<-RUBY
+ Rails.application.config.feature_policy do |p|
+ p.payment :none
+ end
+ RUBY
+
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ app = ->(env) {
+ [200, { "Content-Type" => "text/html" }, ["<p>Hello, World!</p>"]]
+ }
+ root to: app
+ end
+ RUBY
+
+ app("development")
+
+ get "/"
+ assert_policy "payment 'none'"
+ end
+
+ private
+ def assert_policy(expected)
+ assert_equal 200, last_response.status
+ assert_equal expected, last_response.headers["Feature-Policy"]
+ end
+ end
+end
diff --git a/railties/test/application/generators_test.rb b/railties/test/application/generators_test.rb
index e5e557d204..8ec26db772 100644
--- a/railties/test/application/generators_test.rb
+++ b/railties/test/application/generators_test.rb
@@ -198,5 +198,15 @@ module ApplicationTests
assert_no_match "active_record:migration", output
end
end
+
+ test "skip collision check" do
+ rails("generate", "model", "post", "title:string")
+
+ output = rails("generate", "model", "post", "title:string", "body:string")
+ assert_match(/The name 'Post' is either already used in your application or reserved/, output)
+
+ output = rails("generate", "model", "post", "title:string", "body:string", "--skip-collision-check")
+ assert_no_match(/The name 'Post' is either already used in your application or reserved/, output)
+ end
end
end
diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb
index a35247fc43..05978e1d99 100644
--- a/railties/test/application/initializers/frameworks_test.rb
+++ b/railties/test/application/initializers/frameworks_test.rb
@@ -218,8 +218,9 @@ module ApplicationTests
rails %w(generate model post title:string)
rails %w(db:migrate db:schema:cache:dump)
require "#{app_path}/config/environment"
- ActiveRecord::Base.connection.drop_table("posts") # force drop posts table for test.
assert ActiveRecord::Base.connection.schema_cache.data_sources("posts")
+ ensure
+ ActiveRecord::Base.connection.drop_table("posts", if_exists: true) # force drop posts table for test.
end
test "expire schema cache dump" do
diff --git a/railties/test/application/loading_test.rb b/railties/test/application/loading_test.rb
index 9c98489590..9ab400acfc 100644
--- a/railties/test/application/loading_test.rb
+++ b/railties/test/application/loading_test.rb
@@ -116,7 +116,7 @@ class LoadingTest < ActiveSupport::TestCase
RUBY
app_file "app/models/post.rb", <<-MODEL
- class Post < ActiveRecord::Base
+ class Post < ApplicationRecord
end
MODEL
@@ -133,11 +133,12 @@ class LoadingTest < ActiveSupport::TestCase
require "#{rails_root}/config/environment"
setup_ar!
- assert_equal [ActiveStorage::Blob, ActiveStorage::Attachment, ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata].collect(&:to_s).sort, ActiveRecord::Base.descendants.collect(&:to_s).sort
+ initial = [ActiveStorage::Blob, ActiveStorage::Attachment, ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata, ApplicationRecord, "primary::SchemaMigration"].collect(&:to_s).sort
+ assert_equal initial, ActiveRecord::Base.descendants.collect(&:to_s).sort
get "/load"
- assert_equal [ActiveStorage::Blob, ActiveStorage::Attachment, ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata, Post].collect(&:to_s).sort, ActiveRecord::Base.descendants.collect(&:to_s).sort
+ assert_equal [Post].collect(&:to_s).sort, ActiveRecord::Base.descendants.collect(&:to_s).sort - initial
get "/unload"
- assert_equal [ActiveStorage::Blob, ActiveStorage::Attachment, ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata].collect(&:to_s).sort, ActiveRecord::Base.descendants.collect(&:to_s).sort
+ assert_equal ["ActiveRecord::InternalMetadata", "ActiveRecord::SchemaMigration", "primary::SchemaMigration"], ActiveRecord::Base.descendants.collect(&:to_s).sort.uniq
end
test "initialize cant be called twice" do
@@ -454,7 +455,6 @@ class LoadingTest < ActiveSupport::TestCase
end
private
-
def setup_ar!
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Migration.verbose = false
diff --git a/railties/test/application/middleware/exceptions_test.rb b/railties/test/application/middleware/exceptions_test.rb
index 17df78ed4e..5fae521937 100644
--- a/railties/test/application/middleware/exceptions_test.rb
+++ b/railties/test/application/middleware/exceptions_test.rb
@@ -136,5 +136,21 @@ module ApplicationTests
assert_match(/boooom/, last_response.body)
assert_match(/測試テスト시험/, last_response.body)
end
+
+ test "displays diagnostics message when malformed query parameters are provided" do
+ controller :foo, <<-RUBY
+ class FooController < ActionController::Base
+ def index
+ end
+ end
+ RUBY
+
+ app.config.action_dispatch.show_exceptions = true
+ app.config.consider_all_requests_local = true
+
+ get "/foo?x[y]=1&x[y][][w]=2"
+ assert_equal 400, last_response.status
+ assert_match "Invalid query parameters", last_response.body
+ end
end
end
diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb
index 54b2e95d75..e93f2f5aa4 100644
--- a/railties/test/application/middleware_test.rb
+++ b/railties/test/application/middleware_test.rb
@@ -46,6 +46,7 @@ module ApplicationTests
"ActionDispatch::Session::CookieStore",
"ActionDispatch::Flash",
"ActionDispatch::ContentSecurityPolicy::Middleware",
+ "ActionDispatch::FeaturePolicy::Middleware",
"Rack::Head",
"Rack::ConditionalGet",
"Rack::ETag",
@@ -309,7 +310,6 @@ module ApplicationTests
end
private
-
def boot!
require "#{app_path}/config/environment"
end
diff --git a/railties/test/application/rake/dbs_test.rb b/railties/test/application/rake/dbs_test.rb
index 258066a7e6..c9931c45a6 100644
--- a/railties/test/application/rake/dbs_test.rb
+++ b/railties/test/application/rake/dbs_test.rb
@@ -40,6 +40,15 @@ module ApplicationTests
end
end
+ def db_create_with_warning(expected_database)
+ Dir.chdir(app_path) do
+ output = rails("db:create")
+ assert_match(/Rails couldn't infer whether you are using multiple databases/, output)
+ assert_match(/Created database/, output)
+ assert File.exist?(expected_database)
+ end
+ end
+
test "db:create and db:drop without database URL" do
require "#{app_path}/config/environment"
db_create_and_drop ActiveRecord::Base.configurations[Rails.env]["database"]
@@ -86,6 +95,25 @@ module ApplicationTests
db_create_and_drop("db/development.sqlite3", environment_loaded: false)
end
+ test "db:create and db:drop show warning but doesn't raise errors when loading YAML with alias ERB" do
+ app_file "config/database.yml", <<-YAML
+ sqlite: &sqlite
+ adapter: sqlite3
+ database: db/development.sqlite3
+
+ development:
+ <<: *<%= ENV["DB"] || "sqlite" %>
+ YAML
+
+ app_file "config/environments/development.rb", <<-RUBY
+ Rails.application.configure do
+ config.database = "db/development.sqlite3"
+ end
+ RUBY
+
+ db_create_with_warning("db/development.sqlite3")
+ end
+
test "db:create and db:drop don't raise errors when loading YAML containing conditional statements in ERB" do
app_file "config/database.yml", <<-YAML
development:
@@ -122,6 +150,39 @@ module ApplicationTests
db_create_and_drop("db/development.sqlite3", environment_loaded: false)
end
+ test "db:create and db:drop dont raise errors when loading YAML with FIXME ERB" do
+ app_file "config/database.yml", <<-YAML
+ development:
+ <%= Rails.application.config.database ? 'database: db/development.sqlite3' : 'database: db/development.sqlite3' %>
+ adapter: sqlite3
+ YAML
+
+ app_file "config/environments/development.rb", <<-RUBY
+ Rails.application.configure do
+ config.database = "db/development.sqlite3"
+ end
+ RUBY
+
+ db_create_and_drop("db/development.sqlite3", environment_loaded: false)
+ end
+
+ test "db:create and db:drop don't raise errors when loading YAML which contains a key's value as an ERB statement" do
+ app_file "config/database.yml", <<-YAML
+ development:
+ database: <%= Rails.application.config.database ? 'db/development.sqlite3' : 'db/development.sqlite3' %>
+ custom_option: <%= ENV['CUSTOM_OPTION'] %>
+ adapter: sqlite3
+ YAML
+
+ app_file "config/environments/development.rb", <<-RUBY
+ Rails.application.configure do
+ config.database = "db/development.sqlite3"
+ end
+ RUBY
+
+ db_create_and_drop("db/development.sqlite3", environment_loaded: false)
+ end
+
def with_database_existing
Dir.chdir(app_path) do
set_database_url
@@ -569,6 +630,22 @@ module ApplicationTests
assert_match(/CreateRecipes: migrated/, output)
end
end
+
+ test "db:prepare does not touch schema when dumping is disabled" do
+ Dir.chdir(app_path) do
+ rails "generate", "model", "book", "title:string"
+ rails "db:create", "db:migrate"
+
+ app_file "db/schema.rb", "Not touched"
+ app_file "config/initializers/disable_dumping_schema.rb", <<-RUBY
+ Rails.application.config.active_record.dump_schema_after_migration = false
+ RUBY
+
+ rails "db:prepare"
+
+ assert_equal("Not touched", File.read("db/schema.rb").strip)
+ end
+ end
end
end
end
diff --git a/railties/test/application/rake/multi_dbs_test.rb b/railties/test/application/rake/multi_dbs_test.rb
index 31ea2246a9..2606e64424 100644
--- a/railties/test/application/rake/multi_dbs_test.rb
+++ b/railties/test/application/rake/multi_dbs_test.rb
@@ -299,10 +299,56 @@ module ApplicationTests
db_migrate_and_schema_cache_dump_and_schema_cache_clear
end
+ test "db:abort_if_pending_migrations works on all databases" do
+ require "#{app_path}/config/environment"
+
+ app_file "db/animals_migrate/02_two_migration.rb", <<-MIGRATION
+ class TwoMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
+
+ output = rails("db:abort_if_pending_migrations", allow_failure: true)
+ assert_match(/You have 1 pending migration/, output)
+ end
+
+ test "db:abort_if_pending_migrations:namespace works" do
+ require "#{app_path}/config/environment"
+
+ app_file "db/animals_migrate/02_two_migration.rb", <<-MIGRATION
+ class TwoMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
+
+ output = rails("db:abort_if_pending_migrations:primary")
+ assert_no_match(/You have \d+ pending migration/, output)
+ output = rails("db:abort_if_pending_migrations:animals", allow_failure: true)
+ assert_match(/You have 1 pending migration/, output)
+ end
+
test "db:prepare works on all databases" do
require "#{app_path}/config/environment"
db_prepare
end
+
+ test "db:prepare setups missing database without clearing existing one" do
+ require "#{app_path}/config/environment"
+ Dir.chdir(app_path) do
+ # Bug not visible on SQLite3. Can be simplified when https://github.com/rails/rails/issues/36383 resolved
+ use_postgresql(multi_db: true)
+ generate_models_for_animals
+
+ rails "db:create:animals", "db:migrate:animals", "db:create:primary", "db:migrate:primary", "db:schema:dump"
+ rails "db:drop:primary"
+ Dog.create!
+ output = rails("db:prepare")
+
+ assert_match(/Created database/, output)
+ assert_equal 1, Dog.count
+ ensure
+ Dog.connection.disconnect!
+ rails "db:drop" rescue nil
+ end
+ end
end
end
end
diff --git a/railties/test/application/rake/notes_test.rb b/railties/test/application/rake/notes_test.rb
index 60802ef7c4..47822e55b9 100644
--- a/railties/test/application/rake/notes_test.rb
+++ b/railties/test/application/rake/notes_test.rb
@@ -159,7 +159,6 @@ module ApplicationTests
end
private
-
def run_rake_notes(command = "bin/rake notes")
Dir.chdir(app_path) do
output = `#{command}`
diff --git a/railties/test/application/system_test_case_test.rb b/railties/test/application/system_test_case_test.rb
new file mode 100644
index 0000000000..d15a0d9210
--- /dev/null
+++ b/railties/test/application/system_test_case_test.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require "isolation/abstract_unit"
+require "rack/test"
+
+class SystemTestCaseTest < ActiveSupport::TestCase
+ include ActiveSupport::Testing::Isolation
+
+ def setup
+ build_app
+ end
+
+ def teardown
+ teardown_app
+ end
+
+ test "url helpers are delegated to a proxy class" do
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ get 'foo', to: 'foo#index', as: 'test_foo'
+ end
+ RUBY
+
+ app("test")
+
+ assert_not_includes(ActionDispatch::SystemTestCase.runnable_methods, :test_foo_url)
+ end
+
+ test "system tests set the Capybara host in the url_options by default" do
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ get 'foo', to: 'foo#index', as: 'test_foo'
+ end
+ RUBY
+
+ app("test")
+ system_test = ActionDispatch::SystemTestCase.new("my_test")
+ previous_app_host = ::Capybara.app_host
+ ::Capybara.app_host = "https://my_test_example.com"
+
+ assert_equal("https://my_test_example.com/foo", system_test.test_foo_url)
+ ensure
+ ::Capybara.app_host = previous_app_host
+ end
+end
diff --git a/railties/test/application/test_runner_test.rb b/railties/test/application/test_runner_test.rb
index 1ab45abcd0..7fc918898b 100644
--- a/railties/test/application/test_runner_test.rb
+++ b/railties/test/application/test_runner_test.rb
@@ -564,6 +564,24 @@ module ApplicationTests
assert_no_match "create_table(:users)", output
end
+ def test_run_in_parallel_with_process_worker_crash
+ exercise_parallelization_regardless_of_machine_core_count(with: :processes)
+
+ file_name = app_file("test/models/parallel_test.rb", <<-RUBY)
+ require 'test_helper'
+
+ class ParallelTest < ActiveSupport::TestCase
+ def test_crash
+ Kernel.exit 1
+ end
+ end
+ RUBY
+
+ output = run_test_command(file_name)
+
+ assert_match %r{Queue not empty, but all workers have finished. This probably means that a worker crashed and 1 tests were missed.}, output
+ end
+
def test_run_in_parallel_with_threads
exercise_parallelization_regardless_of_machine_core_count(with: :threads)
diff --git a/railties/test/application/zeitwerk_integration_test.rb b/railties/test/application/zeitwerk_integration_test.rb
index 9146222f73..ff8c06b479 100644
--- a/railties/test/application/zeitwerk_integration_test.rb
+++ b/railties/test/application/zeitwerk_integration_test.rb
@@ -98,6 +98,15 @@ class ZeitwerkIntegrationTest < ActiveSupport::TestCase
assert_nil deps.safe_constantize("Admin")
end
+ test "autoloaded? and overridden class names" do
+ invalid_constant_name = Module.new do
+ def self.name
+ "primary::SchemaMigration"
+ end
+ end
+ assert_not deps.autoloaded?(invalid_constant_name)
+ end
+
test "unloadable constants (main)" do
app_file "app/models/user.rb", "class User; end"
app_file "app/models/post.rb", "class Post; end"
diff --git a/railties/test/commands/console_test.rb b/railties/test/commands/console_test.rb
index f6df2b694a..ee4335e31d 100644
--- a/railties/test/commands/console_test.rb
+++ b/railties/test/commands/console_test.rb
@@ -116,7 +116,6 @@ class Rails::ConsoleTest < ActiveSupport::TestCase
private :output
private
-
def start(argv = [])
rails_console = Rails::Console.new(app, parse_arguments(argv))
@output = capture(:stdout) { rails_console.start }
diff --git a/railties/test/commands/dbconsole_test.rb b/railties/test/commands/dbconsole_test.rb
index 76a7cd055f..45b72fd909 100644
--- a/railties/test/commands/dbconsole_test.rb
+++ b/railties/test/commands/dbconsole_test.rb
@@ -275,7 +275,6 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase
private :aborted, :output
private
-
def app_db_config(results)
Rails.application.config.stub(:database_configuration, results || {}) do
yield
diff --git a/railties/test/commands/server_test.rb b/railties/test/commands/server_test.rb
index b78370a233..c9026e2d95 100644
--- a/railties/test/commands/server_test.rb
+++ b/railties/test/commands/server_test.rb
@@ -116,6 +116,13 @@ class Rails::Command::ServerCommandTest < ActiveSupport::TestCase
end
end
+ def test_environment_with_pidfile
+ switch_env "PIDFILE", "/tmp/rails.pid" do
+ options = parse_arguments
+ assert_equal "/tmp/rails.pid", options[:pid]
+ end
+ end
+
def test_caching_without_option
args = []
options = parse_arguments(args)
@@ -234,6 +241,12 @@ class Rails::Command::ServerCommandTest < ActiveSupport::TestCase
options = parse_arguments(args)
assert_equal "127.0.0.1", options[:Host]
end
+
+ switch_env "PIDFILE", "/tmp/rails.pid" do
+ args = ["-P", "/somewhere/else.pid"]
+ options = parse_arguments(args)
+ assert_equal "/somewhere/else.pid", options[:pid]
+ end
end
def test_records_user_supplied_options
@@ -253,6 +266,16 @@ class Rails::Command::ServerCommandTest < ActiveSupport::TestCase
server_options = parse_arguments
assert_equal [:Host], server_options[:user_supplied_options]
end
+
+ switch_env "PORT", "3001" do
+ server_options = parse_arguments
+ assert_equal [:Port], server_options[:user_supplied_options]
+ end
+
+ switch_env "PIDFILE", "/tmp/server.pid" do
+ server_options = parse_arguments
+ assert_equal [:pid], server_options[:user_supplied_options]
+ end
end
def test_default_options
diff --git a/railties/test/configuration/middleware_stack_proxy_test.rb b/railties/test/configuration/middleware_stack_proxy_test.rb
index bc72b7f0c9..b67142f4c2 100644
--- a/railties/test/configuration/middleware_stack_proxy_test.rb
+++ b/railties/test/configuration/middleware_stack_proxy_test.rb
@@ -51,7 +51,6 @@ module Rails
end
private
-
def assert_playback(msg_name, args)
mock = Minitest::Mock.new
mock.expect :send, nil, [msg_name, args]
diff --git a/railties/test/env_helpers.rb b/railties/test/env_helpers.rb
index 336832b867..e3157e0c77 100644
--- a/railties/test/env_helpers.rb
+++ b/railties/test/env_helpers.rb
@@ -4,7 +4,6 @@ require "rails"
module EnvHelpers
private
-
def with_rails_env(env)
Rails.instance_variable_set :@_env, nil
switch_env "RAILS_ENV", env do
diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb
index d913bb5438..5d6d7f1595 100644
--- a/railties/test/generators/actions_test.rb
+++ b/railties/test/generators/actions_test.rb
@@ -43,7 +43,7 @@ class ActionsTest < Rails::Generators::TestCase
def test_add_source_adds_source_to_gemfile
run_generator
action :add_source, "http://gems.github.com"
- assert_file "Gemfile", /source 'http:\/\/gems\.github\.com'/
+ assert_file "Gemfile", /source 'http:\/\/gems\.github\.com'\n/
end
def test_add_source_with_block_adds_source_to_gemfile_with_gem
@@ -51,7 +51,7 @@ class ActionsTest < Rails::Generators::TestCase
action :add_source, "http://gems.github.com" do
gem "rspec-rails"
end
- assert_file "Gemfile", /source 'http:\/\/gems\.github\.com' do\n gem 'rspec-rails'\nend/
+ assert_file "Gemfile", /\n\nsource 'http:\/\/gems\.github\.com' do\n gem 'rspec-rails'\nend\n\z/
end
def test_add_source_with_block_adds_source_to_gemfile_after_gem
@@ -60,13 +60,25 @@ class ActionsTest < Rails::Generators::TestCase
action :add_source, "http://gems.github.com" do
gem "rspec-rails"
end
- assert_file "Gemfile", /gem 'will-paginate'\nsource 'http:\/\/gems\.github\.com' do\n gem 'rspec-rails'\nend/
+ assert_file "Gemfile", /\ngem 'will-paginate'\n\nsource 'http:\/\/gems\.github\.com' do\n gem 'rspec-rails'\nend\n\z/
+ end
+
+ def test_add_source_should_create_newline_between_blocks
+ run_generator
+ action :add_source, "http://gems.github.com" do
+ gem "rspec-rails"
+ end
+
+ action :add_source, "http://gems2.github.com" do
+ gem "fakeweb"
+ end
+ assert_file "Gemfile", /\n\nsource 'http:\/\/gems\.github\.com' do\n gem 'rspec-rails'\nend\n\nsource 'http:\/\/gems2\.github\.com' do\n gem 'fakeweb'\nend\n\z/
end
def test_gem_should_put_gem_dependency_in_gemfile
run_generator
action :gem, "will-paginate"
- assert_file "Gemfile", /gem 'will\-paginate'/
+ assert_file "Gemfile", /gem 'will\-paginate'\n\z/
end
def test_gem_with_version_should_include_version_in_gemfile
@@ -141,7 +153,7 @@ class ActionsTest < Rails::Generators::TestCase
gem "fakeweb"
end
- assert_file "Gemfile", /\ngroup :development, :test do\n gem 'rspec-rails'\nend\n\ngroup :test do\n gem 'fakeweb'\nend/
+ assert_file "Gemfile", /\n\ngroup :development, :test do\n gem 'rspec-rails'\nend\n\ngroup :test do\n gem 'fakeweb'\nend\n\z/
end
def test_github_should_create_an_indented_block
@@ -153,7 +165,7 @@ class ActionsTest < Rails::Generators::TestCase
gem "baz"
end
- assert_file "Gemfile", /\ngithub 'user\/repo' do\n gem 'foo'\n gem 'bar'\n gem 'baz'\nend/
+ assert_file "Gemfile", /\n\ngithub 'user\/repo' do\n gem 'foo'\n gem 'bar'\n gem 'baz'\nend\n\z/
end
def test_github_should_create_an_indented_block_with_options
@@ -165,7 +177,7 @@ class ActionsTest < Rails::Generators::TestCase
gem "baz"
end
- assert_file "Gemfile", /\ngithub 'user\/repo', a: 'correct', other: true do\n gem 'foo'\n gem 'bar'\n gem 'baz'\nend/
+ assert_file "Gemfile", /\n\ngithub 'user\/repo', a: 'correct', other: true do\n gem 'foo'\n gem 'bar'\n gem 'baz'\nend\n\z/
end
def test_github_should_create_an_indented_block_within_a_group
@@ -177,9 +189,73 @@ class ActionsTest < Rails::Generators::TestCase
gem "bar"
gem "baz"
end
+ github "user/repo2", a: "correct", other: true do
+ gem "foo"
+ gem "bar"
+ gem "baz"
+ end
+ end
+
+ assert_file "Gemfile", /\n\ngroup :magic do\n github 'user\/repo', a: 'correct', other: true do\n gem 'foo'\n gem 'bar'\n gem 'baz'\n end\n github 'user\/repo2', a: 'correct', other: true do\n gem 'foo'\n gem 'bar'\n gem 'baz'\n end\nend\n\z/
+ end
+
+ def test_github_should_create_newline_between_blocks
+ run_generator
+
+ action :github, "user/repo", a: "correct", other: true do
+ gem "foo"
+ gem "bar"
+ gem "baz"
+ end
+
+ action :github, "user/repo2", a: "correct", other: true do
+ gem "foo"
+ gem "bar"
+ gem "baz"
+ end
+
+ assert_file "Gemfile", /\n\ngithub 'user\/repo', a: 'correct', other: true do\n gem 'foo'\n gem 'bar'\n gem 'baz'\nend\n\ngithub 'user\/repo2', a: 'correct', other: true do\n gem 'foo'\n gem 'bar'\n gem 'baz'\nend\n\z/
+ end
+
+ def test_gem_with_gemfile_without_newline_at_the_end
+ run_generator
+ File.open("Gemfile", "a") { |f| f.write("gem 'rspec-rails'") }
+
+ action :gem, "will-paginate"
+ assert_file "Gemfile", /gem 'rspec-rails'\ngem 'will-paginate'\n\z/
+ end
+
+ def test_gem_group_with_gemfile_without_newline_at_the_end
+ run_generator
+ File.open("Gemfile", "a") { |f| f.write("gem 'rspec-rails'") }
+
+ action :gem_group, :test do
+ gem "fakeweb"
end
- assert_file "Gemfile", /\ngroup :magic do\n github 'user\/repo', a: 'correct', other: true do\n gem 'foo'\n gem 'bar'\n gem 'baz'\n end\nend\n/
+ assert_file "Gemfile", /gem 'rspec-rails'\n\ngroup :test do\n gem 'fakeweb'\nend\n\z/
+ end
+
+ def test_add_source_with_gemfile_without_newline_at_the_end
+ run_generator
+ File.open("Gemfile", "a") { |f| f.write("gem 'rspec-rails'") }
+
+ action :add_source, "http://gems.github.com" do
+ gem "fakeweb"
+ end
+
+ assert_file "Gemfile", /gem 'rspec-rails'\n\nsource 'http:\/\/gems\.github\.com' do\n gem 'fakeweb'\nend\n\z/
+ end
+
+ def test_github_with_gemfile_without_newline_at_the_end
+ run_generator
+ File.open("Gemfile", "a") { |f| f.write("gem 'rspec-rails'") }
+
+ action :github, "user/repo" do
+ gem "fakeweb"
+ end
+
+ assert_file "Gemfile", /gem 'rspec-rails'\n\ngithub 'user\/repo' do\n gem 'fakeweb'\nend\n\z/
end
def test_environment_should_include_data_in_environment_initializer_block
@@ -505,7 +581,6 @@ F
end
private
-
def action(*args, &block)
capture(:stdout) { generator.send(*args, &block) }
end
diff --git a/railties/test/generators/api_app_generator_test.rb b/railties/test/generators/api_app_generator_test.rb
index d03178da66..099bad8fb9 100644
--- a/railties/test/generators/api_app_generator_test.rb
+++ b/railties/test/generators/api_app_generator_test.rb
@@ -109,7 +109,6 @@ class ApiAppGeneratorTest < Rails::Generators::TestCase
end
private
-
def default_files
%w(.gitignore
.ruby-version
diff --git a/railties/test/generators/migration_generator_test.rb b/railties/test/generators/migration_generator_test.rb
index e6b614a935..080e54a1ca 100644
--- a/railties/test/generators/migration_generator_test.rb
+++ b/railties/test/generators/migration_generator_test.rb
@@ -270,6 +270,21 @@ class MigrationGeneratorTest < Rails::Generators::TestCase
end
end
+ def test_create_table_migration_with_timestamps
+ run_generator ["create_books", "title:string", "content:text"]
+ assert_migration "db/migrate/create_books.rb", /t.timestamps/
+ end
+
+ def test_create_table_timestamps_are_skipped
+ run_generator ["create_books", "title:string", "content:text", "--no-timestamps"]
+
+ assert_migration "db/migrate/create_books.rb" do |m|
+ assert_method :change, m do |change|
+ assert_no_match(/t.timestamps/, change)
+ end
+ end
+ end
+
def test_add_uuid_to_create_table_migration
run_generator ["create_books", "--primary_key_type=uuid"]
assert_migration "db/migrate/create_books.rb" do |content|
@@ -430,7 +445,6 @@ class MigrationGeneratorTest < Rails::Generators::TestCase
end
private
-
def with_singular_table_name
old_state = ActiveRecord::Base.pluralize_table_names
ActiveRecord::Base.pluralize_table_names = false
diff --git a/railties/test/generators/named_base_test.rb b/railties/test/generators/named_base_test.rb
index 4e61b660d7..1b45c58b0e 100644
--- a/railties/test/generators/named_base_test.rb
+++ b/railties/test/generators/named_base_test.rb
@@ -169,7 +169,6 @@ class NamedBaseTest < Rails::Generators::TestCase
end
private
-
def assert_name(generator, value, method)
assert_equal value, generator.send(method)
end
diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb
index f45464f8d0..db774f6ac1 100644
--- a/railties/test/generators/plugin_generator_test.rb
+++ b/railties/test/generators/plugin_generator_test.rb
@@ -713,7 +713,6 @@ class PluginGeneratorTest < Rails::Generators::TestCase
end
private
-
def action(*args, &block)
silence(:stdout) { generator.send(*args, &block) }
end
diff --git a/railties/test/generators/scaffold_controller_generator_test.rb b/railties/test/generators/scaffold_controller_generator_test.rb
index 1348744b0b..8278b72a5a 100644
--- a/railties/test/generators/scaffold_controller_generator_test.rb
+++ b/railties/test/generators/scaffold_controller_generator_test.rb
@@ -89,6 +89,15 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase
end
end
+ def test_controller_permit_attachments_attributes_only
+ run_generator ["Message", "photos:attachments"]
+
+ assert_file "app/controllers/messages_controller.rb" do |content|
+ assert_match(/def message_params/, content)
+ assert_match(/params\.require\(:message\)\.permit\(photos: \[\]\)/, content)
+ end
+ end
+
def test_helper_are_invoked_with_a_pluralized_name
run_generator
assert_file "app/helpers/users_helper.rb", /module UsersHelper/
diff --git a/railties/test/generators/scaffold_generator_test.rb b/railties/test/generators/scaffold_generator_test.rb
index bfa52a1beb..fa9a42215b 100644
--- a/railties/test/generators/scaffold_generator_test.rb
+++ b/railties/test/generators/scaffold_generator_test.rb
@@ -487,6 +487,36 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase
assert_match(/^\W{4}<%= form\.file_field :video %>/, content)
assert_match(/^\W{4}<%= form\.file_field :photos, multiple: true %>/, content)
end
+
+ assert_file "app/views/messages/show.html.erb" do |content|
+ assert_match(/^\W{2}<%= link_to @message\.video\.filename, @message\.video if @message\.video\.attached\? %>/, content)
+ assert_match(/^\W{4}<div><%= link_to photo\.filename, photo %>/, content)
+ end
+
+ assert_file "test/system/messages_test.rb" do |content|
+ assert_no_match(/fill_in "Video"/, content)
+ assert_no_match(/fill_in "Photos"/, content)
+ end
+ end
+
+ def test_scaffold_generator_rich_text
+ run_generator ["message", "content:rich_text"]
+
+ assert_file "app/models/message.rb", /rich_text :content/
+
+ assert_file "app/controllers/messages_controller.rb" do |content|
+ assert_instance_method :message_params, content do |m|
+ assert_match(/permit\(:content\)/, m)
+ end
+ end
+
+ assert_file "app/views/messages/_form.html.erb" do |content|
+ assert_match(/^\W{4}<%= form\.rich_text_area :content %>/, content)
+ end
+
+ assert_file "test/system/messages_test.rb" do |content|
+ assert_no_match(/fill_in "Content"/, content)
+ end
end
def test_scaffold_generator_database
diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb
index fab704944b..0fe62df8ba 100644
--- a/railties/test/isolation/abstract_unit.rb
+++ b/railties/test/isolation/abstract_unit.rb
@@ -448,18 +448,36 @@ module TestHelpers
$:.reject! { |path| path =~ %r'/(#{to_remove.join('|')})/' }
end
- def use_postgresql
- File.open("#{app_path}/config/database.yml", "w") do |f|
- f.puts <<-YAML
- default: &default
- adapter: postgresql
- pool: 5
- database: railties_test
- development:
- <<: *default
- test:
- <<: *default
- YAML
+ def use_postgresql(multi_db: false)
+ if multi_db
+ File.open("#{app_path}/config/database.yml", "w") do |f|
+ f.puts <<-YAML
+ default: &default
+ adapter: postgresql
+ pool: 5
+ development:
+ primary:
+ <<: *default
+ database: railties_test
+ animals:
+ <<: *default
+ database: railties_animals_test
+ migrations_paths: db/animals_migrate
+ YAML
+ end
+ else
+ File.open("#{app_path}/config/database.yml", "w") do |f|
+ f.puts <<-YAML
+ default: &default
+ adapter: postgresql
+ pool: 5
+ database: railties_test
+ development:
+ <<: *default
+ test:
+ <<: *default
+ YAML
+ end
end
end
end
diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb
index 8ce68dbcfa..7f05b9d9cf 100644
--- a/railties/test/railties/engine_test.rb
+++ b/railties/test/railties/engine_test.rb
@@ -34,7 +34,7 @@ module RailtiesTest
def migrations
migration_root = File.expand_path(ActiveRecord::Migrator.migrations_paths.first, app_path)
- ActiveRecord::MigrationContext.new(migration_root).migrations
+ ActiveRecord::MigrationContext.new(migration_root, ActiveRecord::SchemaMigration).migrations
end
test "serving sprocket's assets" do
diff --git a/tools/profile b/tools/profile
index 6fb571f43b..d38ba1dd84 100755
--- a/tools/profile
+++ b/tools/profile
@@ -68,7 +68,6 @@ module CodeTools
end
private
-
def assert_ruby_file_exists(path)
fail Error.new("No such file") unless File.exist?(path)
fail Error.new("#{path} is a directory") if File.directory?(path)