aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--actioncable/test/client_test.rb2
-rw-r--r--actionmailbox/test/dummy/config/initializers/backtrace_silencers.rb2
-rw-r--r--actionmailer/lib/action_mailer/base.rb2
-rw-r--r--actionpack/CHANGELOG.md11
-rw-r--r--actionpack/lib/abstract_controller/callbacks.rb2
-rw-r--r--actionpack/lib/action_controller/log_subscriber.rb3
-rw-r--r--actionpack/lib/action_controller/metal/head.rb2
-rw-r--r--actionpack/lib/action_controller/metal/http_authentication.rb2
-rw-r--r--actionpack/lib/action_controller/metal/instrumentation.rb14
-rw-r--r--actionpack/lib/action_controller/metal/mime_responds.rb2
-rw-r--r--actionpack/lib/action_controller/metal/params_wrapper.rb2
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb2
-rw-r--r--actionpack/lib/action_controller/metal/rescue.rb2
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb2
-rw-r--r--actionpack/lib/action_controller/renderer.rb7
-rw-r--r--actionpack/lib/action_controller/test_case.rb4
-rw-r--r--actionpack/lib/action_dispatch/http/cache.rb4
-rw-r--r--actionpack/lib/action_dispatch/http/content_security_policy.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/feature_policy.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/filter_parameters.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/filter_redirect.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/mime_negotiation.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/mime_type.rb10
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb6
-rw-r--r--actionpack/lib/action_dispatch/http/url.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/cookies.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/ssl.rb4
-rw-r--r--actionpack/lib/action_dispatch/middleware/static.rb27
-rw-r--r--actionpack/lib/action_dispatch/routing/inspector.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb18
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb2
-rw-r--r--actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb52
-rw-r--r--actionpack/test/controller/integration_test.rb2
-rw-r--r--actionpack/test/controller/log_subscriber_test.rb2
-rw-r--r--actionpack/test/dispatch/debug_exceptions_test.rb8
-rw-r--r--actionpack/test/dispatch/exception_wrapper_test.rb2
-rw-r--r--actionpack/test/dispatch/mime_type_test.rb6
-rw-r--r--actionpack/test/dispatch/request/json_params_parsing_test.rb2
-rw-r--r--actionpack/test/dispatch/request_test.rb2
-rw-r--r--actionpack/test/dispatch/routing_test.rb10
-rw-r--r--actionpack/test/dispatch/ssl_test.rb4
-rw-r--r--actionpack/test/dispatch/system_testing/screenshot_helper_test.rb79
-rw-r--r--actiontext/lib/action_text/attachables/remote_image.rb2
-rw-r--r--actiontext/lib/action_text/attachment_gallery.rb2
-rw-r--r--actiontext/package.json2
-rw-r--r--actiontext/test/dummy/config/initializers/backtrace_silencers.rb2
-rw-r--r--actionview/lib/action_view/helpers/form_options_helper.rb4
-rw-r--r--actionview/lib/action_view/helpers/text_helper.rb2
-rw-r--r--actionview/lib/action_view/helpers/url_helper.rb4
-rw-r--r--actionview/lib/action_view/layouts.rb2
-rw-r--r--actionview/lib/action_view/lookup_context.rb2
-rw-r--r--actionview/test/activerecord/relation_cache_test.rb17
-rw-r--r--actionview/test/template/form_options_helper_test.rb2
-rw-r--r--actionview/test/template/output_safety_helper_test.rb8
-rw-r--r--actionview/test/template/url_helper_test.rb16
-rw-r--r--actionview/test/ujs/public/test/data-remote.js2
-rw-r--r--activemodel/lib/active_model/errors.rb2
-rw-r--r--activemodel/lib/active_model/type/helpers/timezone.rb2
-rw-r--r--activemodel/lib/active_model/validations/format.rb2
-rw-r--r--activemodel/lib/active_model/validations/validates.rb4
-rw-r--r--activerecord/CHANGELOG.md19
-rw-r--r--activerecord/lib/active_record/associations/association.rb4
-rw-r--r--activerecord/lib/active_record/associations/builder/has_one.rb19
-rw-r--r--activerecord/lib/active_record/associations/collection_proxy.rb2
-rw-r--r--activerecord/lib/active_record/attribute_methods/query.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb5
-rw-r--r--activerecord/lib/active_record/connection_adapters/connection_specification.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb3
-rw-r--r--activerecord/lib/active_record/database_configurations.rb9
-rw-r--r--activerecord/lib/active_record/errors.rb6
-rw-r--r--activerecord/lib/active_record/explain_subscriber.rb2
-rw-r--r--activerecord/lib/active_record/fixture_set/file.rb6
-rw-r--r--activerecord/lib/active_record/fixtures.rb45
-rw-r--r--activerecord/lib/active_record/persistence.rb10
-rw-r--r--activerecord/lib/active_record/query_cache.rb4
-rw-r--r--activerecord/lib/active_record/railties/databases.rake2
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb46
-rw-r--r--activerecord/lib/active_record/tasks/database_tasks.rb1
-rw-r--r--activerecord/lib/active_record/tasks/mysql_database_tasks.rb6
-rw-r--r--activerecord/lib/active_record/tasks/postgresql_database_tasks.rb6
-rw-r--r--activerecord/lib/arel/visitors/mysql.rb8
-rw-r--r--activerecord/lib/arel/visitors/oracle.rb4
-rw-r--r--activerecord/test/cases/arel/nodes/node_test.rb2
-rw-r--r--activerecord/test/cases/arel/select_manager_test.rb2
-rw-r--r--activerecord/test/cases/arel/visitors/mysql_test.rb46
-rw-r--r--activerecord/test/cases/associations/belongs_to_associations_test.rb7
-rw-r--r--activerecord/test/cases/associations/has_one_associations_test.rb25
-rw-r--r--activerecord/test/cases/associations/inner_join_association_test.rb37
-rw-r--r--activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb38
-rw-r--r--activerecord/test/cases/database_configurations_test.rb2
-rw-r--r--activerecord/test/cases/enum_test.rb4
-rw-r--r--activerecord/test/cases/fixtures_test.rb29
-rw-r--r--activerecord/test/cases/tasks/mysql_rake_test.rb6
-rw-r--r--activerecord/test/cases/tasks/postgresql_rake_test.rb2
-rw-r--r--activerecord/test/fixtures/other_books.yml26
-rw-r--r--activerecord/test/fixtures/parrots.yml8
-rw-r--r--activerecord/test/models/drink_designer.rb6
-rw-r--r--activerecord/test/schema/schema.rb2
-rw-r--r--activestorage/lib/active_storage/service/s3_service.rb16
-rw-r--r--activestorage/test/dummy/config/initializers/backtrace_silencers.rb2
-rw-r--r--activestorage/test/fixtures/files/racecar.tifbin33705838 -> 729182 bytes
-rw-r--r--activestorage/test/service/s3_service_test.rb17
-rw-r--r--activesupport/lib/active_support/backtrace_cleaner.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/name_error.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/string/access.rb26
-rw-r--r--activesupport/lib/active_support/dependencies.rb1
-rw-r--r--activesupport/lib/active_support/dependencies/zeitwerk_integration.rb13
-rw-r--r--activesupport/lib/active_support/inflector/methods.rb56
-rw-r--r--activesupport/lib/active_support/inflector/transliterate.rb3
-rw-r--r--activesupport/lib/active_support/logger.rb2
-rw-r--r--activesupport/lib/active_support/multibyte/chars.rb2
-rw-r--r--activesupport/lib/active_support/option_merger.rb2
-rw-r--r--activesupport/lib/active_support/parameter_filter.rb2
-rw-r--r--activesupport/lib/active_support/per_thread_registry.rb2
-rw-r--r--activesupport/lib/active_support/secure_compare_rotator.rb1
-rw-r--r--activesupport/lib/active_support/tagged_logging.rb15
-rw-r--r--activesupport/lib/active_support/values/time_zone.rb7
-rw-r--r--activesupport/test/cache/stores/mem_cache_store_test.rb2
-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/string_ext_test.rb32
-rw-r--r--activesupport/test/message_encryptor_test.rb4
-rw-r--r--activesupport/test/multibyte_chars_test.rb6
-rw-r--r--activesupport/test/parameter_filter_test.rb4
-rw-r--r--activesupport/test/time_zone_test.rb7
-rw-r--r--activesupport/test/transliterate_test.rb14
-rw-r--r--guides/rails_guides/kindle.rb2
-rw-r--r--guides/source/action_mailer_basics.md2
-rw-r--r--guides/source/autoloading_and_reloading_constants.md2
-rw-r--r--guides/source/working_with_javascript_in_rails.md6
-rw-r--r--railties/lib/rails/code_statistics.rb2
-rw-r--r--railties/lib/rails/code_statistics_calculator.rb10
-rw-r--r--railties/lib/rails/command/base.rb2
-rw-r--r--railties/lib/rails/command/behavior.rb2
-rw-r--r--railties/lib/rails/command/environment_argument.rb2
-rw-r--r--railties/lib/rails/engine.rb2
-rw-r--r--railties/lib/rails/generators/app_base.rb2
-rw-r--r--railties/lib/rails/generators/base.rb2
-rw-r--r--railties/lib/rails/generators/generated_attribute.rb2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/Gemfile.tt2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt1
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/backtrace_silencers.rb.tt2
-rw-r--r--railties/lib/rails/tasks/framework.rake2
-rw-r--r--railties/lib/rails/test_unit/runner.rb2
-rw-r--r--railties/test/application/assets_test.rb2
-rw-r--r--railties/test/application/configuration_test.rb4
-rw-r--r--railties/test/application/rake/multi_dbs_test.rb19
-rw-r--r--railties/test/application/zeitwerk_integration_test.rb29
-rw-r--r--railties/test/commands/credentials_test.rb9
-rw-r--r--railties/test/generators/app_generator_test.rb6
-rw-r--r--railties/test/generators/namespaced_generators_test.rb4
-rw-r--r--railties/test/railties/engine_test.rb2
153 files changed, 845 insertions, 374 deletions
diff --git a/README.md b/README.md
index 98ade9b445..fe3b5b9d9a 100644
--- a/README.md
+++ b/README.md
@@ -25,7 +25,7 @@ the [Active Model](activemodel/README.rdoc) module.
## Controller layer
The _**Controller layer**_ is responsible for handling incoming HTTP requests and
-providing a suitable response. Usually this means returning HTML, but Rails controllers
+providing a suitable response. Usually, this means returning HTML, but Rails controllers
can also generate XML, JSON, PDFs, mobile-specific views, and more. Controllers load and
manipulate models, and render view templates in order to generate the appropriate HTTP response.
In Rails, incoming requests are routed by Action Dispatch to an appropriate controller, and
@@ -37,7 +37,7 @@ are bundled together in [Action Pack](actionpack/README.rdoc).
The _**View layer**_ is composed of "templates" that are responsible for providing
appropriate representations of your application's resources. Templates can
come in a variety of formats, but most view templates are HTML with embedded
-Ruby code (ERB files). Views are typically rendered to generate a controller response,
+Ruby code (ERB files). Views are typically rendered to generate a controller response
or to generate the body of an email. In Rails, View generation is handled by [Action View](actionview/README.rdoc).
## Frameworks and libraries
diff --git a/actioncable/test/client_test.rb b/actioncable/test/client_test.rb
index bf141df458..eed514db10 100644
--- a/actioncable/test/client_test.rb
+++ b/actioncable/test/client_test.rb
@@ -91,7 +91,7 @@ class ClientTest < ActionCable::TestCase
rescue RuntimeError => ex
# Work around https://bugs.ruby-lang.org/issues/13239
- raise unless ex.message =~ /can't modify frozen IOError/
+ raise unless ex.message.match?(/can't modify frozen IOError/)
# Handle this as if it were the IOError: do the same as above.
server.binder.close
diff --git a/actionmailbox/test/dummy/config/initializers/backtrace_silencers.rb b/actionmailbox/test/dummy/config/initializers/backtrace_silencers.rb
index 59385cdf37..3c56b21b3c 100644
--- a/actionmailbox/test/dummy/config/initializers/backtrace_silencers.rb
+++ b/actionmailbox/test/dummy/config/initializers/backtrace_silencers.rb
@@ -1,7 +1,7 @@
# Be sure to restart your server when you modify this file.
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
-# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
+# Rails.backtrace_cleaner.add_silencer { |line| /my_noisy_library/.match?(line) }
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
# Rails.backtrace_cleaner.remove_silencers!
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index eb0885953b..78264d21d1 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -408,7 +408,7 @@ module ActionMailer
# really useful if you need to validate a self-signed and/or a wildcard certificate. You can use the name
# of an OpenSSL verify constant (<tt>'none'</tt> or <tt>'peer'</tt>) or directly the constant
# (<tt>OpenSSL::SSL::VERIFY_NONE</tt> or <tt>OpenSSL::SSL::VERIFY_PEER</tt>).
- # <tt>:ssl/:tls</tt> Enables the SMTP connection to use SMTP/TLS (SMTPS: SMTP over direct TLS connection)
+ # * <tt>:ssl/:tls</tt> Enables the SMTP connection to use SMTP/TLS (SMTPS: SMTP over direct TLS connection)
#
# * <tt>sendmail_settings</tt> - Allows you to override options for the <tt>:sendmail</tt> delivery method.
# * <tt>:location</tt> - The location of the sendmail executable. Defaults to <tt>/usr/sbin/sendmail</tt>.
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 8bb2c73e52..90217755bc 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,3 +1,12 @@
+* Allow system test screen shots to be taken more than once in
+ a test by prefixing the file name with an incrementing counter.
+
+ Add an environment variable `RAILS_SYSTEM_TESTING_SCREENSHOT_HTML` to
+ enable saving of HTML during a screenshot in addition to the image.
+ This uses the same image name, with the extension replaced with `.html`
+
+ *Tom Fakes*
+
* Add `Vary: Accept` header when using `Accept` header for response
For some requests like `/users/1`, Rails uses requests' `Accept`
@@ -80,7 +89,7 @@
*Gustavo Gutierrez*
-* Calling `ActionController::Parameters#transform_keys/!` without a block now returns
+* Calling `ActionController::Parameters#transform_keys`/`!` without a block now returns
an enumerator for the parameters instead of the underlying hash.
*Eugene Kenny*
diff --git a/actionpack/lib/abstract_controller/callbacks.rb b/actionpack/lib/abstract_controller/callbacks.rb
index 42bab411d2..983d65f944 100644
--- a/actionpack/lib/abstract_controller/callbacks.rb
+++ b/actionpack/lib/abstract_controller/callbacks.rb
@@ -37,7 +37,7 @@ module AbstractController
# Override <tt>AbstractController::Base#process_action</tt> to run the
# <tt>process_action</tt> callbacks around the normal behavior.
- def process_action(*args)
+ def process_action(*)
run_callbacks(:process_action) do
super
end
diff --git a/actionpack/lib/action_controller/log_subscriber.rb b/actionpack/lib/action_controller/log_subscriber.rb
index d8b04d8ddb..033ad10d4c 100644
--- a/actionpack/lib/action_controller/log_subscriber.rb
+++ b/actionpack/lib/action_controller/log_subscriber.rb
@@ -22,8 +22,7 @@ module ActionController
additions = ActionController::Base.log_process_action(payload)
status = payload[:status]
- if status.nil? && payload[:exception].present?
- exception_class_name = payload[:exception].first
+ if status.nil? && (exception_class_name = payload[:exception].first)
status = ActionDispatch::ExceptionWrapper.status_code_for_exception(exception_class_name)
end
diff --git a/actionpack/lib/action_controller/metal/head.rb b/actionpack/lib/action_controller/metal/head.rb
index 3c84bebb85..f290272055 100644
--- a/actionpack/lib/action_controller/metal/head.rb
+++ b/actionpack/lib/action_controller/metal/head.rb
@@ -29,7 +29,7 @@ module ActionController
content_type = options.delete(:content_type)
options.each do |key, value|
- headers[key.to_s.dasherize.split("-").each { |v| v[0] = v[0].chr.upcase }.join("-")] = value.to_s
+ headers[key.to_s.split(/[-_]/).each { |v| v[0] = v[0].upcase }.join("-")] = value.to_s
end
self.status = status
diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb
index 6a274d35cb..ec0c9ecc67 100644
--- a/actionpack/lib/action_controller/metal/http_authentication.rb
+++ b/actionpack/lib/action_controller/metal/http_authentication.rb
@@ -482,7 +482,7 @@ module ActionController
def raw_params(auth)
_raw_params = auth.sub(TOKEN_REGEX, "").split(/\s*#{AUTHN_PAIR_DELIMITERS}\s*/)
- if !(_raw_params.first =~ %r{\A#{TOKEN_KEY}})
+ if !(%r{\A#{TOKEN_KEY}}.match?(_raw_params.first))
_raw_params[0] = "#{TOKEN_KEY}#{_raw_params.first}"
end
diff --git a/actionpack/lib/action_controller/metal/instrumentation.rb b/actionpack/lib/action_controller/metal/instrumentation.rb
index 6f7fc0d624..594c4c1dc8 100644
--- a/actionpack/lib/action_controller/metal/instrumentation.rb
+++ b/actionpack/lib/action_controller/metal/instrumentation.rb
@@ -16,7 +16,7 @@ module ActionController
attr_internal :view_runtime
- def process_action(*args)
+ def process_action(*)
raw_payload = {
controller: self.class.name,
action: action_name,
@@ -27,18 +27,18 @@ module ActionController
path: request.fullpath
}
- ActiveSupport::Notifications.instrument("start_processing.action_controller", raw_payload.dup)
+ ActiveSupport::Notifications.instrument("start_processing.action_controller", raw_payload)
ActiveSupport::Notifications.instrument("process_action.action_controller", raw_payload) do |payload|
- super.tap do
- payload[:status] = response.status
- end
+ result = super
+ payload[:status] = response.status
+ result
ensure
append_info_to_payload(payload)
end
end
- def render(*args)
+ def render(*)
render_output = nil
self.view_runtime = cleanup_view_runtime do
Benchmark.ms { render_output = super }
@@ -59,7 +59,7 @@ module ActionController
end
end
- def redirect_to(*args)
+ def redirect_to(*)
ActiveSupport::Notifications.instrument("redirect_to.action_controller") do |payload|
result = super
payload[:status] = response.status
diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb
index 5c6f7fe396..a993c76af9 100644
--- a/actionpack/lib/action_controller/metal/mime_responds.rb
+++ b/actionpack/lib/action_controller/metal/mime_responds.rb
@@ -142,7 +142,7 @@ module ActionController #:nodoc:
#
# You can set the variant in a +before_action+:
#
- # request.variant = :tablet if request.user_agent =~ /iPad/
+ # request.variant = :tablet if /iPad/.match?(request.user_agent)
#
# Respond to variants in the action just like you respond to formats:
#
diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb
index 150ae2666c..15c9937405 100644
--- a/actionpack/lib/action_controller/metal/params_wrapper.rb
+++ b/actionpack/lib/action_controller/metal/params_wrapper.rb
@@ -240,7 +240,7 @@ module ActionController
# Performs parameters wrapping upon the request. Called automatically
# by the metal call stack.
- def process_action(*args)
+ def process_action(*)
_perform_parameter_wrapping if _wrapper_enabled?
super
end
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index 5a5c04234b..e923afb17c 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -280,7 +280,7 @@ module ActionController #:nodoc:
# Check for cross-origin JavaScript responses.
def non_xhr_javascript_response? # :doc:
- content_type =~ %r(\A(?:text|application)/javascript) && !request.xhr?
+ %r(\A(?:text|application)/javascript).match?(content_type) && !request.xhr?
end
AUTHENTICITY_TOKEN_LENGTH = 32
diff --git a/actionpack/lib/action_controller/metal/rescue.rb b/actionpack/lib/action_controller/metal/rescue.rb
index 44f7fb7a07..59704f2797 100644
--- a/actionpack/lib/action_controller/metal/rescue.rb
+++ b/actionpack/lib/action_controller/metal/rescue.rb
@@ -18,7 +18,7 @@ module ActionController #:nodoc:
end
private
- def process_action(*args)
+ def process_action(*)
super
rescue Exception => exception
request.env["action_dispatch.show_detailed_exceptions"] ||= show_detailed_exceptions?
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index 920ae52f2b..4c9eb20c65 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -225,7 +225,7 @@ module ActionController
class << self
def nested_attribute?(key, value) # :nodoc:
- key =~ /\A-?\d+\z/ && (value.is_a?(Hash) || value.is_a?(Parameters))
+ /\A-?\d+\z/.match?(key) && (value.is_a?(Hash) || value.is_a?(Parameters))
end
end
diff --git a/actionpack/lib/action_controller/renderer.rb b/actionpack/lib/action_controller/renderer.rb
index dadf6d3445..b48c7a1afa 100644
--- a/actionpack/lib/action_controller/renderer.rb
+++ b/actionpack/lib/action_controller/renderer.rb
@@ -65,7 +65,7 @@ module ActionController
def initialize(controller, env, defaults)
@controller = controller
@defaults = defaults
- @env = normalize_keys defaults.merge(env)
+ @env = normalize_keys defaults, env
end
# Render templates with any options from ActionController::Base#render_to_string.
@@ -97,8 +97,9 @@ module ActionController
end
private
- def normalize_keys(env)
+ def normalize_keys(defaults, env)
new_env = {}
+ defaults.each_pair { |k, v| new_env[rack_key_for(k)] = rack_value_for(k, v) }
env.each_pair { |k, v| new_env[rack_key_for(k)] = rack_value_for(k, v) }
new_env["rack.url_scheme"] = new_env["HTTPS"] == "on" ? "https" : "http"
new_env
@@ -120,7 +121,7 @@ module ActionController
}
def rack_key_for(key)
- RACK_KEY_TRANSLATION.fetch(key, key.to_s)
+ RACK_KEY_TRANSLATION[key] || key.to_s
end
def rack_value_for(key, value)
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 47e0099f20..1632ac3ae8 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -593,8 +593,8 @@ module ActionController
private
def scrub_env!(env)
- env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ }
- env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ }
+ env.delete_if { |k, v| k.match?(/^(action_dispatch|rack)\.request/) }
+ env.delete_if { |k, v| k.match?(/^action_dispatch\.rescue/) }
env.delete "action_dispatch.request.query_parameters"
env.delete "action_dispatch.request.request_parameters"
env["rack.input"] = StringIO.new
diff --git a/actionpack/lib/action_dispatch/http/cache.rb b/actionpack/lib/action_dispatch/http/cache.rb
index 7be30be77a..0258d85564 100644
--- a/actionpack/lib/action_dispatch/http/cache.rb
+++ b/actionpack/lib/action_dispatch/http/cache.rb
@@ -150,8 +150,8 @@ module ActionDispatch
directive, argument = segment.split("=", 2)
if SPECIAL_KEYS.include? directive
- key = directive.tr("-", "_")
- cache_control[key.to_sym] = argument || true
+ directive.tr!("-", "_")
+ cache_control[directive.to_sym] = argument || true
else
cache_control[:extras] ||= []
cache_control[:extras] << segment
diff --git a/actionpack/lib/action_dispatch/http/content_security_policy.rb b/actionpack/lib/action_dispatch/http/content_security_policy.rb
index 9c430b57e3..e8cf1b95a5 100644
--- a/actionpack/lib/action_dispatch/http/content_security_policy.rb
+++ b/actionpack/lib/action_dispatch/http/content_security_policy.rb
@@ -33,7 +33,7 @@ module ActionDispatch #:nodoc:
private
def html_response?(headers)
if content_type = headers[CONTENT_TYPE]
- content_type =~ /html/
+ /html/.match?(content_type)
end
end
diff --git a/actionpack/lib/action_dispatch/http/feature_policy.rb b/actionpack/lib/action_dispatch/http/feature_policy.rb
index 592b6e4393..78e982918d 100644
--- a/actionpack/lib/action_dispatch/http/feature_policy.rb
+++ b/actionpack/lib/action_dispatch/http/feature_policy.rb
@@ -33,7 +33,7 @@ module ActionDispatch #:nodoc:
private
def html_response?(headers)
if content_type = headers[CONTENT_TYPE]
- content_type =~ /html/
+ /html/.match?(content_type)
end
end
diff --git a/actionpack/lib/action_dispatch/http/filter_parameters.rb b/actionpack/lib/action_dispatch/http/filter_parameters.rb
index 7a7a493f64..7ad1ba3e0e 100644
--- a/actionpack/lib/action_dispatch/http/filter_parameters.rb
+++ b/actionpack/lib/action_dispatch/http/filter_parameters.rb
@@ -23,7 +23,7 @@ module ActionDispatch
# change { file: { code: "xxxx"} }
#
# env["action_dispatch.parameter_filter"] = -> (k, v) do
- # v.reverse! if k =~ /secret/i
+ # v.reverse! if k.match?(/secret/i)
# end
# => reverses the value to all keys matching /secret/i
module FilterParameters
diff --git a/actionpack/lib/action_dispatch/http/filter_redirect.rb b/actionpack/lib/action_dispatch/http/filter_redirect.rb
index d780d5f793..3bd1f5109d 100644
--- a/actionpack/lib/action_dispatch/http/filter_redirect.rb
+++ b/actionpack/lib/action_dispatch/http/filter_redirect.rb
@@ -27,7 +27,7 @@ module ActionDispatch
if String === filter
location.include?(filter)
elsif Regexp === filter
- location =~ filter
+ location.match?(filter)
end
end
end
diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
index ac0ff133eb..6bf4e652d3 100644
--- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb
+++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
@@ -162,7 +162,7 @@ module ActionDispatch
def valid_accept_header # :doc:
(xhr? && (accept.present? || content_mime_type)) ||
- (accept.present? && accept !~ BROWSER_LIKE_ACCEPTS)
+ (accept.present? && !accept.match?(BROWSER_LIKE_ACCEPTS))
end
def use_accept_header # :doc:
diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb
index ed1d50f3b9..60b78c0582 100644
--- a/actionpack/lib/action_dispatch/http/mime_type.rb
+++ b/actionpack/lib/action_dispatch/http/mime_type.rb
@@ -202,7 +202,7 @@ module Mime
# For an input of <tt>'application'</tt>, returns <tt>[Mime[:html], Mime[:js],
# Mime[:xml], Mime[:yaml], Mime[:atom], Mime[:json], Mime[:rss], Mime[:url_encoded_form]</tt>.
def parse_data_with_trailing_star(type)
- Mime::SET.select { |m| m =~ type }
+ Mime::SET.select { |m| m.match?(type) }
end
# This method is opposite of register method.
@@ -283,8 +283,14 @@ module Mime
@synonyms.any? { |synonym| synonym.to_s =~ regexp } || @string =~ regexp
end
+ def match?(mime_type)
+ return false unless mime_type
+ regexp = Regexp.new(Regexp.quote(mime_type.to_s))
+ @synonyms.any? { |synonym| synonym.to_s.match?(regexp) } || @string.match?(regexp)
+ end
+
def html?
- symbol == :html || @string =~ /html/
+ (symbol == :html) || /html/.match?(@string)
end
def all?; false; end
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 4ac7c5c2bd..54dbb536c1 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -85,7 +85,7 @@ module ActionDispatch
def controller_class_for(name)
if name
controller_param = name.underscore
- const_name = "#{controller_param.camelize}Controller"
+ const_name = controller_param.camelize << "Controller"
ActiveSupport::Dependencies.constantize(const_name)
else
PASS_NOT_FOUND
@@ -265,7 +265,7 @@ module ActionDispatch
# (case-insensitive), which may need to be manually added depending on the
# choice of JavaScript libraries and frameworks.
def xml_http_request?
- get_header("HTTP_X_REQUESTED_WITH") =~ /XMLHttpRequest/i
+ /XMLHttpRequest/i.match?(get_header("HTTP_X_REQUESTED_WITH"))
end
alias :xhr? :xml_http_request?
@@ -400,7 +400,7 @@ module ActionDispatch
# True if the request came from localhost, 127.0.0.1, or ::1.
def local?
- LOCALHOST =~ remote_addr && LOCALHOST =~ remote_ip
+ LOCALHOST.match?(remote_addr) && LOCALHOST.match?(remote_ip)
end
def request_parameters=(params)
diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb
index 3b0f6378ea..225ae0a497 100644
--- a/actionpack/lib/action_dispatch/http/url.rb
+++ b/actionpack/lib/action_dispatch/http/url.rb
@@ -133,7 +133,7 @@ module ActionDispatch
end
def named_host?(host)
- IP_HOST_REGEXP !~ host
+ !IP_HOST_REGEXP.match?(host)
end
def normalize_protocol(protocol)
diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index 9b5a5cf2b0..96bdf570af 100644
--- a/actionpack/lib/action_dispatch/middleware/cookies.rb
+++ b/actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -439,7 +439,7 @@ module ActionDispatch
# If host is not ip and matches domain regexp.
# (ip confirms to domain regexp so we explicitly check for ip)
- options[:domain] = if (request.host !~ /^[\d.]+$/) && (request.host =~ domain_regexp)
+ options[:domain] = if !request.host.match?(/^[\d.]+$/) && (request.host =~ domain_regexp)
".#{$&}"
end
elsif options[:domain].is_a? Array
diff --git a/actionpack/lib/action_dispatch/middleware/ssl.rb b/actionpack/lib/action_dispatch/middleware/ssl.rb
index 00902ede21..237eccf45f 100644
--- a/actionpack/lib/action_dispatch/middleware/ssl.rb
+++ b/actionpack/lib/action_dispatch/middleware/ssl.rb
@@ -13,7 +13,7 @@ module ActionDispatch
#
# Requests can opt-out of redirection with +exclude+:
#
- # config.ssl_options = { redirect: { exclude: -> request { request.path =~ /healthcheck/ } } }
+ # config.ssl_options = { redirect: { exclude: -> request { /healthcheck/.match?(request.path) } } }
#
# Cookies will not be flagged as secure for excluded requests.
#
@@ -126,7 +126,7 @@ module ActionDispatch
[ @redirect.fetch(:status, redirection_status(request)),
{ "Content-Type" => "text/html",
"Location" => https_location_for(request) },
- @redirect.fetch(:body, []) ]
+ (@redirect[:body] || []) ]
end
def redirection_status(request)
diff --git a/actionpack/lib/action_dispatch/middleware/static.rb b/actionpack/lib/action_dispatch/middleware/static.rb
index 1f2f7757a3..eddcdbaeac 100644
--- a/actionpack/lib/action_dispatch/middleware/static.rb
+++ b/actionpack/lib/action_dispatch/middleware/static.rb
@@ -32,18 +32,13 @@ module ActionDispatch
return false unless ::Rack::Utils.valid_path? path
path = ::Rack::Utils.clean_path_info path
- paths = [path, "#{path}#{ext}", "#{path}/#{@index}#{ext}"]
+ return ::Rack::Utils.escape_path(path).b if file_readable?(path)
- if match = paths.detect { |p|
- path = File.join(@root, p.b)
- begin
- File.file?(path) && File.readable?(path)
- rescue SystemCallError
- false
- end
- }
- return ::Rack::Utils.escape_path(match).b
- end
+ path_with_ext = path + ext
+ return ::Rack::Utils.escape_path(path_with_ext).b if file_readable?(path_with_ext)
+
+ path << "/" << @index << ext
+ return ::Rack::Utils.escape_path(path).b if file_readable?(path)
end
def call(env)
@@ -83,11 +78,11 @@ module ActionDispatch
end
def gzip_encoding_accepted?(request)
- request.accept_encoding.any? { |enc, quality| enc =~ /\bgzip\b/i }
+ request.accept_encoding.any? { |enc, quality| /\bgzip\b/i.match?(enc) }
end
def gzip_file_path(path)
- can_gzip_mime = content_type(path) =~ /\A(?:text\/|application\/javascript)/
+ can_gzip_mime = /\A(?:text\/|application\/javascript)/.match?(content_type(path))
gzip_path = "#{path}.gz"
if can_gzip_mime && File.exist?(File.join(@root, ::Rack::Utils.unescape_path(gzip_path)))
gzip_path
@@ -95,6 +90,12 @@ module ActionDispatch
false
end
end
+
+ def file_readable?(path)
+ file_path = File.join(@root, path.b)
+ File.file?(file_path) && File.readable?(file_path)
+ rescue SystemCallError
+ end
end
# This middleware will attempt to return the contents of a file's body from
diff --git a/actionpack/lib/action_dispatch/routing/inspector.rb b/actionpack/lib/action_dispatch/routing/inspector.rb
index 6e40a18009..bf286c299d 100644
--- a/actionpack/lib/action_dispatch/routing/inspector.rb
+++ b/actionpack/lib/action_dispatch/routing/inspector.rb
@@ -94,7 +94,7 @@ module ActionDispatch
if filter
@routes.select do |route|
route_wrapper = RouteWrapper.new(route)
- filter.any? { |default, value| route_wrapper.send(default) =~ value }
+ filter.any? { |default, value| value.match?(route_wrapper.send(default)) }
end
else
@routes
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index d1100089b1..da95e14cbb 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -112,7 +112,7 @@ module ActionDispatch
end
def self.optional_format?(path, format)
- format != false && path !~ OPTIONAL_FORMAT_REGEX
+ format != false && !path.match?(OPTIONAL_FORMAT_REGEX)
end
def initialize(set:, ast:, controller:, default_action:, to:, formatted:, via:, options_constraints:, anchor:, scope_params:, options:)
@@ -367,7 +367,7 @@ module ActionDispatch
def translate_controller(controller)
return controller if Regexp === controller
- return controller.to_s if controller =~ /\A[a-z_0-9][a-z_0-9\/]*\z/
+ return controller.to_s if /\A[a-z_0-9][a-z_0-9\/]*\z/.match?(controller)
yield
end
@@ -403,7 +403,7 @@ module ActionDispatch
# for root cases, where the latter is the correct one.
def self.normalize_path(path)
path = Journey::Router::Utils.normalize_path(path)
- path.gsub!(%r{/(\(+)/?}, '\1/') unless path =~ %r{^/(\(+[^)]+\)){1,}$}
+ path.gsub!(%r{/(\(+)/?}, '\1/') unless %r{^/(\(+[^)]+\)){1,}$}.match?(path)
path
end
@@ -996,7 +996,7 @@ module ActionDispatch
#
# Requests to routes can be constrained based on specific criteria:
#
- # constraints(-> (req) { req.env["HTTP_USER_AGENT"] =~ /iPhone/ }) do
+ # constraints(-> (req) { /iPhone/.match?(req.env["HTTP_USER_AGENT"]) }) do
# resources :iphones
# end
#
@@ -1006,7 +1006,7 @@ module ActionDispatch
#
# class Iphone
# def self.matches?(request)
- # request.env["HTTP_USER_AGENT"] =~ /iPhone/
+ # /iPhone/.match?(request.env["HTTP_USER_AGENT"])
# end
# end
#
@@ -1833,7 +1833,7 @@ module ActionDispatch
# and return nil in case it isn't. Otherwise, we pass the invalid name
# forward so the underlying router engine treats it and raises an exception.
if as.nil?
- candidate unless candidate !~ /\A[_a-z]/i || has_named_route?(candidate)
+ candidate unless !candidate.match?(/\A[_a-z]/i) || has_named_route?(candidate)
else
candidate
end
@@ -1887,7 +1887,7 @@ module ActionDispatch
options_constraints = options.delete(:constraints) || {}
path_types = paths.group_by(&:class)
- path_types.fetch(String, []).each do |_path|
+ (path_types[String] || []).each do |_path|
route_options = options.dup
if _path && option_path
raise ArgumentError, "Ambiguous route definition. Both :path and the route path were specified as strings."
@@ -1896,7 +1896,7 @@ module ActionDispatch
decomposed_match(_path, controller, route_options, _path, to, via, formatted, anchor, options_constraints)
end
- path_types.fetch(Symbol, []).each do |action|
+ (path_types[Symbol] || []).each do |action|
route_options = options.dup
decomposed_match(action, controller, route_options, option_path, to, via, formatted, anchor, options_constraints)
end
@@ -1916,7 +1916,7 @@ module ActionDispatch
end
def using_match_shorthand?(path)
- path =~ %r{^/?[-\w]+/[-\w/]+$}
+ %r{^/?[-\w]+/[-\w/]+$}.match?(path)
end
def decomposed_match(path, controller, options, _path, to, via, formatted, anchor, options_constraints)
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 5b35b68c44..db8c54ba84 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -836,7 +836,7 @@ module ActionDispatch
def recognize_path(path, environment = {})
method = (environment[:method] || "GET").to_s.upcase
- path = Journey::Router::Utils.normalize_path(path) unless path =~ %r{://}
+ path = Journey::Router::Utils.normalize_path(path) unless %r{://}.match?(path)
extras = environment[:extras] || {}
begin
diff --git a/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb b/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb
index 056ce51a61..cba053ee4c 100644
--- a/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb
+++ b/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb
@@ -9,10 +9,16 @@ module ActionDispatch
#
# +take_screenshot+ can be used at any point in your system tests to take
# a screenshot of the current state. This can be useful for debugging or
- # automating visual testing.
+ # automating visual testing. You can take multiple screenshots per test
+ # to investigate changes at different points during your test. These will be
+ # named with a sequential prefix (or 'failed' for failing tests)
#
# The screenshot will be displayed in your console, if supported.
#
+ # You can set the +RAILS_SYSTEM_TESTING_SCREENSHOT_HTML+ environment variable to
+ # save the HTML from the page that is being screenhoted so you can investigate the
+ # elements on the page at the time of the screenshot
+ #
# You can set the +RAILS_SYSTEM_TESTING_SCREENSHOT+ environment variable to
# control the output. Possible values are:
# * [+simple+ (default)] Only displays the screenshot path.
@@ -22,6 +28,8 @@ module ActionDispatch
# * [+artifact+] Display the screenshot in the terminal, using the terminal
# artifact format (https://buildkite.github.io/terminal-to-html/inline-images/).
def take_screenshot
+ increment_unique
+ save_html if save_html?
save_image
puts display_image
end
@@ -38,17 +46,48 @@ module ActionDispatch
end
private
+ attr_accessor :_screenshot_counter
+
+ def save_html?
+ ENV["RAILS_SYSTEM_TESTING_SCREENSHOT_HTML"] == "1"
+ end
+
+ def increment_unique
+ @_screenshot_counter ||= 0
+ @_screenshot_counter += 1
+ end
+
+ def unique
+ failed? ? "failures" : (_screenshot_counter || 0).to_s
+ end
+
def image_name
- name = method_name[0...225]
- failed? ? "failures_#{name}" : name
+ name = "#{unique}_#{method_name}"
+ name[0...225]
end
def image_path
- @image_path ||= absolute_image_path.to_s
+ absolute_image_path.to_s
+ end
+
+ def html_path
+ absolute_html_path.to_s
+ end
+
+ def absolute_path
+ Rails.root.join("tmp/screenshots/#{image_name}")
end
def absolute_image_path
- Rails.root.join("tmp/screenshots/#{image_name}.png")
+ "#{absolute_path}.png"
+ end
+
+ def absolute_html_path
+ "#{absolute_path}.html"
+ end
+
+ def save_html
+ page.save_page(absolute_html_path)
end
def save_image
@@ -66,7 +105,8 @@ module ActionDispatch
end
def display_image
- message = +"[Screenshot]: #{image_path}\n"
+ message = +"[Screenshot Image]: #{image_path}\n"
+ message << +"[Screenshot HTML]: #{html_path}\n" if save_html?
case output_type
when "artifact"
diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb
index cb7c2467ac..4f5f5b71ae 100644
--- a/actionpack/test/controller/integration_test.rb
+++ b/actionpack/test/controller/integration_test.rb
@@ -606,7 +606,7 @@ class MetalIntegrationTest < ActionDispatch::IntegrationTest
class Poller
def self.call(env)
- if env["PATH_INFO"] =~ /^\/success/
+ if /^\/success/.match?(env["PATH_INFO"])
[200, { "Content-Type" => "text/plain", "Content-Length" => "12" }, ["Hello World!"]]
else
[404, { "Content-Type" => "text/plain", "Content-Length" => "0" }, []]
diff --git a/actionpack/test/controller/log_subscriber_test.rb b/actionpack/test/controller/log_subscriber_test.rb
index 1a7e7f6cbb..46ab7b4f74 100644
--- a/actionpack/test/controller/log_subscriber_test.rb
+++ b/actionpack/test/controller/log_subscriber_test.rb
@@ -139,7 +139,7 @@ class ACLogSubscriberTest < ActionController::TestCase
def test_process_action_without_parameters
get :show
wait
- assert_nil logs.detect { |l| l =~ /Parameters/ }
+ assert_nil logs.detect { |l| /Parameters/.match?(l) }
end
def test_process_action_with_parameters
diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb
index fa629bc761..5d12b62fd4 100644
--- a/actionpack/test/dispatch/debug_exceptions_test.rb
+++ b/actionpack/test/dispatch/debug_exceptions_test.rb
@@ -544,8 +544,8 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
@app = DevelopmentApp
Rails.stub :root, Pathname.new(".") do
cleaner = ActiveSupport::BacktraceCleaner.new.tap do |bc|
- bc.add_silencer { |line| line =~ /method_that_raises/ }
- bc.add_silencer { |line| line !~ %r{test/dispatch/debug_exceptions_test.rb} }
+ bc.add_silencer { |line| line.match?(/method_that_raises/) }
+ bc.add_silencer { |line| !line.match?(%r{test/dispatch/debug_exceptions_test.rb}) }
end
get "/framework_raises", headers: { "action_dispatch.backtrace_cleaner" => cleaner }
@@ -596,7 +596,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
@app = DevelopmentApp
Rails.stub :root, Pathname.new(".") do
cleaner = ActiveSupport::BacktraceCleaner.new.tap do |bc|
- bc.add_silencer { |line| line !~ %r{test/dispatch/debug_exceptions_test.rb} }
+ bc.add_silencer { |line| !line.match?(%r{test/dispatch/debug_exceptions_test.rb}) }
end
get "/nested_exceptions", headers: { "action_dispatch.backtrace_cleaner" => cleaner }
@@ -631,7 +631,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
@app = DevelopmentApp
Rails.stub :root, Pathname.new(".") do
cleaner = ActiveSupport::BacktraceCleaner.new.tap do |bc|
- bc.add_silencer { |line| line !~ %r{test/dispatch/debug_exceptions_test.rb} }
+ bc.add_silencer { |line| !line.match?(%r{test/dispatch/debug_exceptions_test.rb}) }
end
get "/actionable_error", headers: { "action_dispatch.backtrace_cleaner" => cleaner }
diff --git a/actionpack/test/dispatch/exception_wrapper_test.rb b/actionpack/test/dispatch/exception_wrapper_test.rb
index 668469a01d..3c395ca5ee 100644
--- a/actionpack/test/dispatch/exception_wrapper_test.rb
+++ b/actionpack/test/dispatch/exception_wrapper_test.rb
@@ -21,7 +21,7 @@ module ActionDispatch
setup do
@cleaner = ActiveSupport::BacktraceCleaner.new
@cleaner.remove_filters!
- @cleaner.add_silencer { |line| line !~ /^lib/ }
+ @cleaner.add_silencer { |line| !line.match?(/^lib/) }
end
test "#source_extracts fetches source fragments for every backtrace entry" do
diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb
index 50f6c06fee..b0b2aa0cc1 100644
--- a/actionpack/test/dispatch/mime_type_test.rb
+++ b/actionpack/test/dispatch/mime_type_test.rb
@@ -175,6 +175,12 @@ class MimeTypeTest < ActiveSupport::TestCase
assert Mime[:html] =~ "application/xhtml+xml"
end
+ test "match?" do
+ assert Mime[:js].match?("text/javascript")
+ assert Mime[:js].match?("application/javascript")
+ assert_not Mime[:js].match?("text/html")
+ end
+
test "can be initialized with wildcards" do
assert_equal "*/*", Mime::Type.new("*/*").to_s
assert_equal "text/*", Mime::Type.new("text/*").to_s
diff --git a/actionpack/test/dispatch/request/json_params_parsing_test.rb b/actionpack/test/dispatch/request/json_params_parsing_test.rb
index 2a48a12497..bbf98912f3 100644
--- a/actionpack/test/dispatch/request/json_params_parsing_test.rb
+++ b/actionpack/test/dispatch/request/json_params_parsing_test.rb
@@ -68,7 +68,7 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest
post "/parse", params: json, headers: { "CONTENT_TYPE" => "application/json", "action_dispatch.show_exceptions" => true, "action_dispatch.logger" => ActiveSupport::Logger.new(output) }
assert_response :bad_request
output.rewind && err = output.read
- assert err =~ /Error occurred while parsing request parameters/
+ assert err.match?(/Error occurred while parsing request parameters/)
end
end
diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb
index c4cb27429d..806b7d0559 100644
--- a/actionpack/test/dispatch/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -884,7 +884,7 @@ class RequestFormat < BaseRequestTest
assert request.format.html?
output.rewind && (err = output.read)
- assert_match /Error occurred while parsing request parameters/, err
+ assert_match(/Error occurred while parsing request parameters/, err)
end
test "formats with xhr request" do
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index b67b1dd347..d4a667a13a 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -12,7 +12,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
class IpRestrictor
def self.matches?(request)
- request.ip =~ /192\.168\.1\.1\d\d/
+ /192\.168\.1\.1\d\d/.match?(request.ip)
end
end
@@ -3823,7 +3823,7 @@ private
end
def method_missing(method, *args, &block)
- if method.to_s =~ /_(path|url)$/
+ if method.to_s.match?(/_(path|url)$/)
@app.routes.url_helpers.send(method, *args, &block)
else
super
@@ -5137,7 +5137,7 @@ class TestRecognizePath < ActionDispatch::IntegrationTest
end
def matches?(request)
- request.path_parameters[key] =~ pattern
+ pattern.match?(request.path_parameters[key])
end
end
@@ -5147,8 +5147,8 @@ class TestRecognizePath < ActionDispatch::IntegrationTest
get "/hash/:foo", to: "pages#show", constraints: { foo: /foo/ }
get "/hash/:bar", to: "pages#show", constraints: { bar: /bar/ }
- get "/proc/:foo", to: "pages#show", constraints: proc { |r| r.path_parameters[:foo] =~ /foo/ }
- get "/proc/:bar", to: "pages#show", constraints: proc { |r| r.path_parameters[:bar] =~ /bar/ }
+ get "/proc/:foo", to: "pages#show", constraints: proc { |r| /foo/.match?(r.path_parameters[:foo]) }
+ get "/proc/:bar", to: "pages#show", constraints: proc { |r| /bar/.match?(r.path_parameters[:bar]) }
get "/class/:foo", to: "pages#show", constraints: PageConstraint.new(:foo, /foo/)
get "/class/:bar", to: "pages#show", constraints: PageConstraint.new(:bar, /bar/)
diff --git a/actionpack/test/dispatch/ssl_test.rb b/actionpack/test/dispatch/ssl_test.rb
index baf46e7c7e..44fe433c5f 100644
--- a/actionpack/test/dispatch/ssl_test.rb
+++ b/actionpack/test/dispatch/ssl_test.rb
@@ -42,7 +42,7 @@ class RedirectSSLTest < SSLTest
end
test "exclude can avoid redirect" do
- excluding = { exclude: -> request { request.path =~ /healthcheck/ } }
+ excluding = { exclude: -> request { request.path.match?(/healthcheck/) } }
assert_not_redirected "http://example.org/healthcheck", redirect: excluding
assert_redirected from: "http://example.org/", redirect: excluding
@@ -209,7 +209,7 @@ class SecureCookiesTest < SSLTest
end
def test_cookies_as_not_secure_with_exclude
- excluding = { exclude: -> request { request.domain =~ /example/ } }
+ excluding = { exclude: -> request { /example/.match?(request.domain) } }
get headers: { "Set-Cookie" => DEFAULT }, ssl_options: { redirect: excluding }
assert_cookies(*DEFAULT.split("\n"))
diff --git a/actionpack/test/dispatch/system_testing/screenshot_helper_test.rb b/actionpack/test/dispatch/system_testing/screenshot_helper_test.rb
index b0b36f9d74..5d69a887ef 100644
--- a/actionpack/test/dispatch/system_testing/screenshot_helper_test.rb
+++ b/actionpack/test/dispatch/system_testing/screenshot_helper_test.rb
@@ -6,60 +6,93 @@ require "capybara/dsl"
require "selenium/webdriver"
class ScreenshotHelperTest < ActiveSupport::TestCase
+ def setup
+ @new_test = DrivenBySeleniumWithChrome.new("x")
+ @new_test.send("_screenshot_counter=", nil)
+ end
+
test "image path is saved in tmp directory" do
- new_test = DrivenBySeleniumWithChrome.new("x")
+ Rails.stub :root, Pathname.getwd do
+ assert_equal Rails.root.join("tmp/screenshots/0_x.png").to_s, @new_test.send(:image_path)
+ end
+ end
+
+ test "image path unique counter is changed when incremented" do
+ @new_test.send(:increment_unique)
Rails.stub :root, Pathname.getwd do
- assert_equal Rails.root.join("tmp/screenshots/x.png").to_s, new_test.send(:image_path)
+ assert_equal Rails.root.join("tmp/screenshots/1_x.png").to_s, @new_test.send(:image_path)
end
end
- test "image path includes failures text if test did not pass" do
- new_test = DrivenBySeleniumWithChrome.new("x")
+ # To allow multiple screenshots in same test
+ test "image path unique counter generates different path in same test" do
+ Rails.stub :root, Pathname.getwd do
+ @new_test.send(:increment_unique)
+ assert_equal Rails.root.join("tmp/screenshots/1_x.png").to_s, @new_test.send(:image_path)
+
+ @new_test.send(:increment_unique)
+ assert_equal Rails.root.join("tmp/screenshots/2_x.png").to_s, @new_test.send(:image_path)
+ end
+ end
+ test "image path includes failures text if test did not pass" do
Rails.stub :root, Pathname.getwd do
- new_test.stub :passed?, false do
- assert_equal Rails.root.join("tmp/screenshots/failures_x.png").to_s, new_test.send(:image_path)
+ @new_test.stub :passed?, false do
+ assert_equal Rails.root.join("tmp/screenshots/failures_x.png").to_s, @new_test.send(:image_path)
+ assert_equal Rails.root.join("tmp/screenshots/failures_x.html").to_s, @new_test.send(:html_path)
end
end
end
test "image path does not include failures text if test skipped" do
- new_test = DrivenBySeleniumWithChrome.new("x")
-
Rails.stub :root, Pathname.getwd do
- new_test.stub :passed?, false do
- new_test.stub :skipped?, true do
- assert_equal Rails.root.join("tmp/screenshots/x.png").to_s, new_test.send(:image_path)
+ @new_test.stub :passed?, false do
+ @new_test.stub :skipped?, true do
+ assert_equal Rails.root.join("tmp/screenshots/0_x.png").to_s, @new_test.send(:image_path)
+ assert_equal Rails.root.join("tmp/screenshots/0_x.html").to_s, @new_test.send(:html_path)
end
end
end
end
- test "image name truncates names over 225 characters" do
- new_test = DrivenBySeleniumWithChrome.new("x" * 400)
+ test "image name truncates names over 225 characters including counter" do
+ long_test = DrivenBySeleniumWithChrome.new("x" * 400)
Rails.stub :root, Pathname.getwd do
- assert_equal Rails.root.join("tmp/screenshots/#{"x" * 225}.png").to_s, new_test.send(:image_path)
+ assert_equal Rails.root.join("tmp/screenshots/0_#{"x" * 223}.png").to_s, long_test.send(:image_path)
+ assert_equal Rails.root.join("tmp/screenshots/0_#{"x" * 223}.html").to_s, long_test.send(:html_path)
end
end
test "defaults to simple output for the screenshot" do
- new_test = DrivenBySeleniumWithChrome.new("x")
- assert_equal "simple", new_test.send(:output_type)
+ assert_equal "simple", @new_test.send(:output_type)
+ end
+
+ test "display_image return html path when RAILS_SYSTEM_TESTING_SCREENSHOT_HTML environment" do
+ original_html_setting = ENV["RAILS_SYSTEM_TESTING_SCREENSHOT_HTML"]
+ ENV["RAILS_SYSTEM_TESTING_SCREENSHOT_HTML"] = "1"
+
+ assert @new_test.send(:save_html?)
+
+ Rails.stub :root, Pathname.getwd do
+ @new_test.stub :passed?, false do
+ assert_match %r|\[Screenshot HTML\].+?tmp/screenshots/failures_x\.html|, @new_test.send(:display_image)
+ end
+ end
+ ensure
+ ENV["RAILS_SYSTEM_TESTING_SCREENSHOT_HTML"] = original_html_setting
end
test "display_image return artifact format when specify RAILS_SYSTEM_TESTING_SCREENSHOT environment" do
original_output_type = ENV["RAILS_SYSTEM_TESTING_SCREENSHOT"]
ENV["RAILS_SYSTEM_TESTING_SCREENSHOT"] = "artifact"
- new_test = DrivenBySeleniumWithChrome.new("x")
-
- assert_equal "artifact", new_test.send(:output_type)
+ assert_equal "artifact", @new_test.send(:output_type)
Rails.stub :root, Pathname.getwd do
- new_test.stub :passed?, false do
- assert_match %r|url=artifact://.+?tmp/screenshots/failures_x\.png|, new_test.send(:display_image)
+ @new_test.stub :passed?, false do
+ assert_match %r|url=artifact://.+?tmp/screenshots/failures_x\.png|, @new_test.send(:display_image)
end
end
ensure
@@ -67,10 +100,8 @@ class ScreenshotHelperTest < ActiveSupport::TestCase
end
test "image path returns the absolute path from root" do
- new_test = DrivenBySeleniumWithChrome.new("x")
-
Rails.stub :root, Pathname.getwd.join("..") do
- assert_equal Rails.root.join("tmp/screenshots/x.png").to_s, new_test.send(:image_path)
+ assert_equal Rails.root.join("tmp/screenshots/0_x.png").to_s, @new_test.send(:image_path)
end
end
end
diff --git a/actiontext/lib/action_text/attachables/remote_image.rb b/actiontext/lib/action_text/attachables/remote_image.rb
index 650b11862b..c5819ef1f5 100644
--- a/actiontext/lib/action_text/attachables/remote_image.rb
+++ b/actiontext/lib/action_text/attachables/remote_image.rb
@@ -14,7 +14,7 @@ module ActionText
private
def content_type_is_image?(content_type)
- content_type.to_s =~ /^image(\/.+|$)/
+ content_type.to_s.match?(/^image(\/.+|$)/)
end
def attributes_from_node(node)
diff --git a/actiontext/lib/action_text/attachment_gallery.rb b/actiontext/lib/action_text/attachment_gallery.rb
index 45afbff058..48ba9f830c 100644
--- a/actiontext/lib/action_text/attachment_gallery.rb
+++ b/actiontext/lib/action_text/attachment_gallery.rb
@@ -23,7 +23,7 @@ module ActionText
Fragment.wrap(content).find_all(SELECTOR).select do |node|
node.children.all? do |child|
if child.text?
- child.text =~ /\A(\n|\ )*\z/
+ /\A(\n|\ )*\z/.match?(child.text)
else
child.matches? ATTACHMENT_SELECTOR
end
diff --git a/actiontext/package.json b/actiontext/package.json
index 594cfe16eb..ee44b75d2c 100644
--- a/actiontext/package.json
+++ b/actiontext/package.json
@@ -24,6 +24,6 @@
"@rails/activestorage": "^6.0.0-alpha"
},
"peerDependencies": {
- "trix": "^1.0.0"
+ "trix": "^1.2.0"
}
}
diff --git a/actiontext/test/dummy/config/initializers/backtrace_silencers.rb b/actiontext/test/dummy/config/initializers/backtrace_silencers.rb
index 59385cdf37..3c56b21b3c 100644
--- a/actiontext/test/dummy/config/initializers/backtrace_silencers.rb
+++ b/actiontext/test/dummy/config/initializers/backtrace_silencers.rb
@@ -1,7 +1,7 @@
# Be sure to restart your server when you modify this file.
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
-# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
+# Rails.backtrace_cleaner.add_silencer { |line| /my_noisy_library/.match?(line) }
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
# Rails.backtrace_cleaner.remove_silencers!
diff --git a/actionview/lib/action_view/helpers/form_options_helper.rb b/actionview/lib/action_view/helpers/form_options_helper.rb
index ad19426fff..cf8f7de931 100644
--- a/actionview/lib/action_view/helpers/form_options_helper.rb
+++ b/actionview/lib/action_view/helpers/form_options_helper.rb
@@ -569,7 +569,7 @@ module ActionView
# be obtained in Active Record as a value object). The +model+ parameter
# must respond to +all+ and return an array of objects that represent time
# zones; each object must respond to +name+. If a Regexp is given it will
- # attempt to match the zones using the <code>=~<code> operator.
+ # attempt to match the zones using <code>match?</code> method.
#
# NOTE: Only the option tags are returned, you have to wrap this call in
# a regular HTML select tag.
@@ -581,7 +581,7 @@ module ActionView
if priority_zones
if priority_zones.is_a?(Regexp)
- priority_zones = zones.select { |z| z =~ priority_zones }
+ priority_zones = zones.select { |z| z.match?(priority_zones) }
end
zone_options.safe_concat options_for_select(convert_zones[priority_zones], selected)
diff --git a/actionview/lib/action_view/helpers/text_helper.rb b/actionview/lib/action_view/helpers/text_helper.rb
index 8203a43239..980a89a7b6 100644
--- a/actionview/lib/action_view/helpers/text_helper.rb
+++ b/actionview/lib/action_view/helpers/text_helper.rb
@@ -228,7 +228,7 @@ module ActionView
# pluralize(2, 'Person', locale: :de)
# # => 2 Personen
def pluralize(count, singular, plural_arg = nil, plural: plural_arg, locale: I18n.locale)
- word = if count == 1 || count.to_s =~ /^1(\.0+)?$/
+ word = if count == 1 || count.to_s.match?(/^1(\.0+)?$/)
singular
else
plural || singular.pluralize(locale)
diff --git a/actionview/lib/action_view/helpers/url_helper.rb b/actionview/lib/action_view/helpers/url_helper.rb
index 9b4116834e..1b05d4aa71 100644
--- a/actionview/lib/action_view/helpers/url_helper.rb
+++ b/actionview/lib/action_view/helpers/url_helper.rb
@@ -627,7 +627,7 @@ module ActionView
# is prepopulated with the passed phone number and optional
# +country_code+ value.
#
- # +phone_to+ has a optional +country_code+ option which automatically adds the country
+ # +phone_to+ has an optional +country_code+ option which automatically adds the country
# code as well as the + sign in the phone numer that gets prepopulated,
# for example if +country_code: "01"+ +\+01+ will be prepended to the
# phone numer, by passing special keys to +html_options+.
@@ -689,7 +689,7 @@ module ActionView
end
def add_method_to_attributes!(html_options, method)
- if method_not_get_method?(method) && html_options["rel"] !~ /nofollow/
+ if method_not_get_method?(method) && !html_options["rel"]&.match?(/nofollow/)
if html_options["rel"].blank?
html_options["rel"] = "nofollow"
else
diff --git a/actionview/lib/action_view/layouts.rb b/actionview/lib/action_view/layouts.rb
index be21ff0e5d..74e8e80e07 100644
--- a/actionview/lib/action_view/layouts.rb
+++ b/actionview/lib/action_view/layouts.rb
@@ -395,7 +395,7 @@ module ActionView
end
def _normalize_layout(value)
- value.is_a?(String) && value !~ /\blayouts/ ? "layouts/#{value}" : value
+ value.is_a?(String) && !value.match?(/\blayouts/) ? "layouts/#{value}" : value
end
# Returns the default layout for this controller.
diff --git a/actionview/lib/action_view/lookup_context.rb b/actionview/lib/action_view/lookup_context.rb
index 211fbc8e6c..f050d54e27 100644
--- a/actionview/lib/action_view/lookup_context.rb
+++ b/actionview/lib/action_view/lookup_context.rb
@@ -29,7 +29,7 @@ module ActionView
Accessors.define_method(:"default_#{name}", &block)
Accessors.module_eval <<-METHOD, __FILE__, __LINE__ + 1
def #{name}
- @details.fetch(:#{name}, [])
+ @details[:#{name}] || []
end
def #{name}=(value)
diff --git a/actionview/test/activerecord/relation_cache_test.rb b/actionview/test/activerecord/relation_cache_test.rb
index 6fe83dcb9a..26f3bfbcbc 100644
--- a/actionview/test/activerecord/relation_cache_test.rb
+++ b/actionview/test/activerecord/relation_cache_test.rb
@@ -17,9 +17,24 @@ class RelationCacheTest < ActionView::TestCase
end
def test_cache_relation_other
- cache(Project.all) { concat("Hello World") }
+ assert_queries(1) do
+ cache(Project.all) { concat("Hello World") }
+ end
assert_equal "Hello World", controller.cache_store.read("views/test/hello_world:fa9482a68ce25bf7589b8eddad72f736/projects-#{Project.count}")
end
def view_cache_dependencies; []; end
+
+ def assert_queries(num)
+ ActiveRecord::Base.connection.materialize_transactions
+ count = 0
+
+ ActiveSupport::Notifications.subscribe("sql.active_record") do |_name, _start, _finish, _id, payload|
+ count += 1 unless ["SCHEMA", "TRANSACTION"].include? payload[:name]
+ end
+
+ result = yield
+ assert_equal num, count, "#{count} instead of #{num} queries were executed."
+ result
+ end
end
diff --git a/actionview/test/template/form_options_helper_test.rb b/actionview/test/template/form_options_helper_test.rb
index d7a7b95ab3..273646b077 100644
--- a/actionview/test/template/form_options_helper_test.rb
+++ b/actionview/test/template/form_options_helper_test.rb
@@ -47,6 +47,7 @@ class FormOptionsHelperTest < ActionView::TestCase
FakeZone = Struct.new(:name) do
def to_s; name; end
def =~(_re); end
+ def match?(_re); end
end
module ClassMethods
@@ -1266,6 +1267,7 @@ class FormOptionsHelperTest < ActionView::TestCase
@fake_timezones.each do |tz|
def tz.=~(re); %(A D).include?(name) end
+ def tz.match?(re); %(A D).include?(name) end
end
html = time_zone_select("firm", "time_zone", /A|D/)
diff --git a/actionview/test/template/output_safety_helper_test.rb b/actionview/test/template/output_safety_helper_test.rb
index faeeded1c8..b2c6ae99ed 100644
--- a/actionview/test/template/output_safety_helper_test.rb
+++ b/actionview/test/template/output_safety_helper_test.rb
@@ -43,7 +43,9 @@ class OutputSafetyHelperTest < ActionView::TestCase
joined = safe_join(["a", "b"])
assert_equal "ab", joined
- $, = "|"
+ silence_warnings do
+ $, = "|"
+ end
joined = safe_join(["a", "b"])
assert_equal "a|b", joined
ensure
@@ -108,7 +110,9 @@ class OutputSafetyHelperTest < ActionView::TestCase
test "to_sentence is not affected by $," do
separator_was = $,
- $, = "|"
+ silence_warnings do
+ $, = "|"
+ end
begin
assert_equal "one and two", to_sentence(["one", "two"])
assert_equal "one, two, and three", to_sentence(["one", "two", "three"])
diff --git a/actionview/test/template/url_helper_test.rb b/actionview/test/template/url_helper_test.rb
index 08413a65c8..ba5ae837f1 100644
--- a/actionview/test/template/url_helper_test.rb
+++ b/actionview/test/template/url_helper_test.rb
@@ -657,7 +657,7 @@ class UrlHelperTest < ActiveSupport::TestCase
)
end
- def test_mail_with_options
+ def test_mail_to_with_options
assert_dom_equal(
%{<a href="mailto:me@example.com?cc=ccaddress%40example.com&amp;bcc=bccaddress%40example.com&amp;body=This%20is%20the%20body%20of%20the%20message.&amp;subject=This%20is%20an%20example%20email&amp;reply-to=foo%40bar.com">My email</a>},
mail_to("me@example.com", "My email", cc: "ccaddress@example.com", bcc: "bccaddress@example.com", subject: "This is an example email", body: "This is the body of the message.", reply_to: "foo@bar.com")
@@ -795,40 +795,40 @@ class UrlHelperTest < ActiveSupport::TestCase
)
end
- def test_phone_with_img
+ def test_phone_to_with_img
assert_dom_equal %{<a href="tel:1234567890"><img src="/feedback.png" /></a>},
phone_to("1234567890", raw('<img src="/feedback.png" />'))
end
- def test_phone_with_html_safe_string
+ def test_phone_to_with_html_safe_string
assert_dom_equal(
%{<a href="tel:1%2B234567890">1+234567890</a>},
phone_to(raw("1+234567890"))
)
end
- def test_phone_with_nil
+ def test_phone_to_with_nil
assert_dom_equal(
%{<a href="tel:"></a>},
phone_to(nil)
)
end
- def test_phone_returns_html_safe_string
+ def test_phone_to_returns_html_safe_string
assert_predicate phone_to("1234567890"), :html_safe?
end
- def test_phone_with_block
+ def test_phone_to_with_block
assert_dom_equal %{<a href="tel:1234567890"><span>Phone</span></a>},
phone_to("1234567890") { content_tag(:span, "Phone") }
end
- def test_phone_with_block_and_options
+ def test_phone_to_with_block_and_options
assert_dom_equal %{<a class="special" href="tel:+011234567890"><span>Phone</span></a>},
phone_to("1234567890", country_code: "01", class: "special") { content_tag(:span, "Phone") }
end
- def test_phone_does_not_modify_html_options_hash
+ def test_phone_to_does_not_modify_html_options_hash
options = { class: "special" }
phone_to "1234567890", "ME!", options
assert_equal({ class: "special" }, options)
diff --git a/actionview/test/ujs/public/test/data-remote.js b/actionview/test/ujs/public/test/data-remote.js
index dbbb383995..f95a57f795 100644
--- a/actionview/test/ujs/public/test/data-remote.js
+++ b/actionview/test/ujs/public/test/data-remote.js
@@ -490,7 +490,7 @@ asyncTest('changing a select option without "data-url" attribute still fires aja
setTimeout(function() { start() }, 20)
})
-asyncTest('inputs inside disabled fieldset are not submited on remote forms', 3, function() {
+asyncTest('inputs inside disabled fieldset are not submitted on remote forms', 3, function() {
$('form')
.append('<fieldset>\
<input name="description" value="A wise man" />\
diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index 42c004ce31..c91ac69603 100644
--- a/activemodel/lib/active_model/errors.rb
+++ b/activemodel/lib/active_model/errors.rb
@@ -100,7 +100,7 @@ module ActiveModel
def copy!(other) # :nodoc:
@errors = other.errors.deep_dup
@errors.each { |error|
- error.instance_variable_set("@base", @base)
+ error.instance_variable_set(:@base, @base)
}
end
diff --git a/activemodel/lib/active_model/type/helpers/timezone.rb b/activemodel/lib/active_model/type/helpers/timezone.rb
index cf87b9715b..b0477aec32 100644
--- a/activemodel/lib/active_model/type/helpers/timezone.rb
+++ b/activemodel/lib/active_model/type/helpers/timezone.rb
@@ -7,7 +7,7 @@ module ActiveModel
module Helpers # :nodoc: all
module Timezone
def is_utc?
- ::Time.zone_default.nil? || ::Time.zone_default =~ "UTC"
+ ::Time.zone_default.nil? || ::Time.zone_default.match?("UTC")
end
def default_timezone
diff --git a/activemodel/lib/active_model/validations/format.rb b/activemodel/lib/active_model/validations/format.rb
index bea57415b0..a473440b4e 100644
--- a/activemodel/lib/active_model/validations/format.rb
+++ b/activemodel/lib/active_model/validations/format.rb
@@ -6,7 +6,7 @@ module ActiveModel
def validate_each(record, attribute, value)
if options[:with]
regexp = option_call(record, :with)
- record_error(record, attribute, :with, value) if value.to_s !~ regexp
+ record_error(record, attribute, :with, value) unless regexp.match?(value.to_s)
elsif options[:without]
regexp = option_call(record, :without)
record_error(record, attribute, :without, value) if regexp.match?(value.to_s)
diff --git a/activemodel/lib/active_model/validations/validates.rb b/activemodel/lib/active_model/validations/validates.rb
index 97612d474d..8906837aa8 100644
--- a/activemodel/lib/active_model/validations/validates.rb
+++ b/activemodel/lib/active_model/validations/validates.rb
@@ -27,7 +27,7 @@ module ActiveModel
# class EmailValidator < ActiveModel::EachValidator
# def validate_each(record, attribute, value)
# record.errors.add attribute, (options[:message] || "is not an email") unless
- # value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
+ # /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i.match?(value)
# end
# end
#
@@ -47,7 +47,7 @@ module ActiveModel
#
# class TitleValidator < ActiveModel::EachValidator
# def validate_each(record, attribute, value)
- # record.errors.add attribute, "must start with 'the'" unless value =~ /\Athe/i
+ # record.errors.add attribute, "must start with 'the'" unless /\Athe/i.match?(value)
# end
# end
#
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 2af48f99db..56a8796318 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,21 @@
+* Preserve user supplied joins order as much as possible.
+
+ Fixes #36761, #34328, #24281, #12953.
+
+ *Ryuta Kamizono*
+
+* Allow `matches_regex` and `does_not_match_regexp` on the MySQL Arel visitor.
+
+ *James Pearson*
+
+* Allow specifying fixtures to be ignored by setting `ignore` in YAML file's '_fixture' section.
+
+ *Tongfei Gao*
+
+* Make the DATABASE_URL env variable only affect the primary connection. Add new env variables for multiple databases.
+
+ *John Crepezzi*, *Eileen Uchitelle*
+
* Add a warning for enum elements with 'not_' prefix.
class Foo
@@ -56,5 +74,4 @@
*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/associations/association.rb b/activerecord/lib/active_record/associations/association.rb
index cf22b850b9..705a5571ee 100644
--- a/activerecord/lib/active_record/associations/association.rb
+++ b/activerecord/lib/active_record/associations/association.rb
@@ -56,6 +56,10 @@ module ActiveRecord
@inversed = false
end
+ def reset_negative_cache # :nodoc:
+ reset if loaded? && target.nil?
+ end
+
# Reloads the \target and returns +self+ on success.
# The QueryCache is cleared if +force+ is true.
def reload(force = false)
diff --git a/activerecord/lib/active_record/associations/builder/has_one.rb b/activerecord/lib/active_record/associations/builder/has_one.rb
index 27ebe8cb71..db8393930e 100644
--- a/activerecord/lib/active_record/associations/builder/has_one.rb
+++ b/activerecord/lib/active_record/associations/builder/has_one.rb
@@ -32,15 +32,12 @@ module ActiveRecord::Associations::Builder # :nodoc:
end
end
- def self.touch_record(o, name, touch)
- record = o.send name
+ def self.touch_record(record, name, touch)
+ instance = record.send(name)
- return unless record && record.persisted?
-
- if touch != true
- record.touch(touch)
- else
- record.touch
+ if instance&.persisted?
+ touch != true ?
+ instance.touch(touch) : instance.touch
end
end
@@ -48,11 +45,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
name = reflection.name
touch = reflection.options[:touch]
- callback = lambda { |record|
- HasOne.touch_record(record, name, touch)
- }
-
+ callback = -> (record) { HasOne.touch_record(record, name, touch) }
model.after_create callback, if: :saved_changes?
+ model.after_create_commit { association(name).reset_negative_cache }
model.after_update callback, if: :saved_changes?
model.after_destroy callback
model.after_touch callback
diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb
index 0db0ad8595..404a7c02ba 100644
--- a/activerecord/lib/active_record/associations/collection_proxy.rb
+++ b/activerecord/lib/active_record/associations/collection_proxy.rb
@@ -100,7 +100,7 @@ module ActiveRecord
# converting them into an array and iterating through them using
# Array#select.
#
- # person.pets.select { |pet| pet.name =~ /oo/ }
+ # person.pets.select { |pet| /oo/.match?(pet.name) }
# # => [
# # #<Pet id: 2, name: "Spook", person_id: 1>,
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
diff --git a/activerecord/lib/active_record/attribute_methods/query.rb b/activerecord/lib/active_record/attribute_methods/query.rb
index 0cf67644af..5a21e36cc7 100644
--- a/activerecord/lib/active_record/attribute_methods/query.rb
+++ b/activerecord/lib/active_record/attribute_methods/query.rb
@@ -17,7 +17,7 @@ module ActiveRecord
when false, nil then false
else
if !type_for_attribute(attr_name) { false }
- if Numeric === value || value !~ /[^0-9]/
+ if Numeric === value || !value.match?(/[^0-9]/)
!value.to_i.zero?
else
return false if ActiveModel::Type::Boolean::FALSE_VALUES.include?(value)
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 ef1eef6b69..0fe16270ed 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -572,7 +572,8 @@ module ActiveRecord
end
end
- # See https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html
+ # See https://dev.mysql.com/doc/refman/5.7/en/server-error-reference.html
+ ER_DB_CREATE_EXISTS = 1007
ER_DUP_ENTRY = 1062
ER_NOT_NULL_VIOLATION = 1048
ER_NO_REFERENCED_ROW = 1216
@@ -592,6 +593,8 @@ module ActiveRecord
def translate_exception(exception, message:, sql:, binds:)
case error_number(exception)
+ when ER_DB_CREATE_EXISTS
+ DatabaseAlreadyExists.new(message, sql: sql, binds: binds)
when ER_DUP_ENTRY
RecordNotUnique.new(message, sql: sql, binds: binds)
when ER_NO_REFERENCED_ROW, ER_ROW_IS_REFERENCED, ER_ROW_IS_REFERENCED_2, ER_NO_REFERENCED_ROW_2
diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb
index 0732b69f81..20041f0c85 100644
--- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb
+++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb
@@ -275,7 +275,7 @@ module ActiveRecord
# hash and merges with the rest of the hash.
# Connection details inside of the "url" key win any merge conflicts
def resolve_hash_connection(spec)
- if spec["url"] && spec["url"] !~ /^jdbc:/
+ if spec["url"] && !spec["url"].match?(/^jdbc:/)
connection_hash = resolve_url_connection(spec.delete("url"))
spec.merge!(connection_hash)
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 0a7c6d8ac4..f33ba87435 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -467,6 +467,7 @@ module ActiveRecord
UNIQUE_VIOLATION = "23505"
SERIALIZATION_FAILURE = "40001"
DEADLOCK_DETECTED = "40P01"
+ DUPLICATE_DATABASE = "42P04"
LOCK_NOT_AVAILABLE = "55P03"
QUERY_CANCELED = "57014"
@@ -488,6 +489,8 @@ module ActiveRecord
SerializationFailure.new(message, sql: sql, binds: binds)
when DEADLOCK_DETECTED
Deadlocked.new(message, sql: sql, binds: binds)
+ when DUPLICATE_DATABASE
+ DatabaseAlreadyExists.new(message, sql: sql, binds: binds)
when LOCK_NOT_AVAILABLE
LockWaitTimeout.new(message, sql: sql, binds: binds)
when QUERY_CANCELED
diff --git a/activerecord/lib/active_record/database_configurations.rb b/activerecord/lib/active_record/database_configurations.rb
index 3e387782f6..fcf13a910c 100644
--- a/activerecord/lib/active_record/database_configurations.rb
+++ b/activerecord/lib/active_record/database_configurations.rb
@@ -181,12 +181,19 @@ module ActiveRecord
end
def environment_url_config(env, spec_name, config)
- url = ENV["DATABASE_URL"]
+ url = environment_value_for(spec_name)
return unless url
ActiveRecord::DatabaseConfigurations::UrlConfig.new(env, spec_name, url, config)
end
+ def environment_value_for(spec_name)
+ spec_env_key = "#{spec_name.upcase}_DATABASE_URL"
+ url = ENV[spec_env_key]
+ url ||= ENV["DATABASE_URL"] if spec_name == "primary"
+ url
+ end
+
def method_missing(method, *args, &blk)
case method
when :fetch
diff --git a/activerecord/lib/active_record/errors.rb b/activerecord/lib/active_record/errors.rb
index 20cc987d6e..509f21c9a5 100644
--- a/activerecord/lib/active_record/errors.rb
+++ b/activerecord/lib/active_record/errors.rb
@@ -187,6 +187,10 @@ module ActiveRecord
class NoDatabaseError < StatementInvalid
end
+ # Raised when creating a database if it exists.
+ class DatabaseAlreadyExists < StatementInvalid
+ end
+
# Raised when PostgreSQL returns 'cached plan must not change result type' and
# we cannot retry gracefully (e.g. inside a transaction)
class PreparedStatementCacheExpired < StatementInvalid
@@ -334,7 +338,7 @@ module ActiveRecord
# See the following:
#
# * https://www.postgresql.org/docs/current/static/transaction-iso.html
- # * https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html#error_er_lock_deadlock
+ # * https://dev.mysql.com/doc/refman/5.7/en/server-error-reference.html#error_er_lock_deadlock
class TransactionRollbackError < StatementInvalid
end
diff --git a/activerecord/lib/active_record/explain_subscriber.rb b/activerecord/lib/active_record/explain_subscriber.rb
index a86217abc0..ce209092f5 100644
--- a/activerecord/lib/active_record/explain_subscriber.rb
+++ b/activerecord/lib/active_record/explain_subscriber.rb
@@ -26,7 +26,7 @@ module ActiveRecord
payload[:exception] ||
payload[:cached] ||
IGNORED_PAYLOADS.include?(payload[:name]) ||
- payload[:sql] !~ EXPLAINED_SQLS
+ !payload[:sql].match?(EXPLAINED_SQLS)
end
ActiveSupport::Notifications.subscribe("sql.active_record", new)
diff --git a/activerecord/lib/active_record/fixture_set/file.rb b/activerecord/lib/active_record/fixture_set/file.rb
index f1ea0e022f..b2030a5bb9 100644
--- a/activerecord/lib/active_record/fixture_set/file.rb
+++ b/activerecord/lib/active_record/fixture_set/file.rb
@@ -29,6 +29,10 @@ module ActiveRecord
config_row["model_class"]
end
+ def ignored_fixtures
+ config_row["ignore"]
+ end
+
private
def rows
@rows ||= raw_rows.reject { |fixture_name, _| fixture_name == "_fixture" }
@@ -40,7 +44,7 @@ module ActiveRecord
if row
row.last
else
- { 'model_class': nil }
+ { 'model_class': nil, 'ignore': nil }
end
end
end
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 046ed0e95c..3df4b3c87f 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -420,6 +420,29 @@ module ActiveRecord
#
# Any fixture labeled "DEFAULTS" is safely ignored.
#
+ # Besides using "DEFAULTS", you can also specify what fixtures will
+ # be ignored by setting "ignore" in "_fixture" section.
+ #
+ # # users.yml
+ # _fixture:
+ # ignore:
+ # - base
+ # # or use "ignore: base" when there is only one fixture needs to be ignored.
+ #
+ # base: &base
+ # admin: false
+ # introduction: "This is a default description"
+ #
+ # admin:
+ # <<: *base
+ # admin: true
+ #
+ # visitor:
+ # <<: *base
+ #
+ # In the above example, 'base' will be ignored when creating fixtures.
+ # This can be used for common attributes inheriting.
+ #
# == Configure the fixture model class
#
# It's possible to set the fixture's model class directly in the YAML file.
@@ -614,7 +637,7 @@ module ActiveRecord
end
end
- attr_reader :table_name, :name, :fixtures, :model_class, :config
+ attr_reader :table_name, :name, :fixtures, :model_class, :ignored_fixtures, :config
def initialize(_, name, class_name, path, config = ActiveRecord::Base)
@name = name
@@ -647,8 +670,8 @@ module ActiveRecord
# Returns a hash of rows to be inserted. The key is the table, the value is
# a list of rows to insert to that table.
def table_rows
- # allow a standard key to be used for doing defaults in YAML
- fixtures.delete("DEFAULTS")
+ # allow specifying fixtures to be ignored by setting `ignore` in `_fixture` section
+ fixtures.except!(*ignored_fixtures)
TableRows.new(
table_name,
@@ -667,6 +690,21 @@ module ActiveRecord
end
end
+ def ignored_fixtures=(base)
+ @ignored_fixtures =
+ case base
+ when Array
+ base
+ when String
+ [base]
+ else
+ []
+ end
+
+ @ignored_fixtures << "DEFAULTS" unless @ignored_fixtures.include?("DEFAULTS")
+ @ignored_fixtures.compact
+ end
+
# Loads the fixtures from the YAML file at +path+.
# If the file sets the +model_class+ and current instance value is not set,
# it uses the file value.
@@ -678,6 +716,7 @@ module ActiveRecord
yaml_files.each_with_object({}) do |file, fixtures|
FixtureSet::File.open(file) do |fh|
self.model_class ||= fh.model_class if fh.model_class
+ self.ignored_fixtures ||= fh.ignored_fixtures
fh.each do |fixture_name, row|
fixtures[fixture_name] = ActiveRecord::Fixture.new(row, model_class)
end
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index 323b01ab2d..4dfe8655fe 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -566,10 +566,10 @@ module ActiveRecord
def becomes(klass)
became = klass.allocate
became.send(:initialize)
- became.instance_variable_set("@attributes", @attributes)
- became.instance_variable_set("@mutations_from_database", @mutations_from_database ||= nil)
- became.instance_variable_set("@new_record", new_record?)
- became.instance_variable_set("@destroyed", destroyed?)
+ became.instance_variable_set(:@attributes, @attributes)
+ became.instance_variable_set(:@mutations_from_database, @mutations_from_database ||= nil)
+ became.instance_variable_set(:@new_record, new_record?)
+ became.instance_variable_set(:@destroyed, destroyed?)
became.errors.copy!(errors)
became
end
@@ -809,7 +809,7 @@ module ActiveRecord
self.class.unscoped { self.class.find(id) }
end
- @attributes = fresh_object.instance_variable_get("@attributes")
+ @attributes = fresh_object.instance_variable_get(:@attributes)
@new_record = false
self
end
diff --git a/activerecord/lib/active_record/query_cache.rb b/activerecord/lib/active_record/query_cache.rb
index 43a21e629e..881ba623b8 100644
--- a/activerecord/lib/active_record/query_cache.rb
+++ b/activerecord/lib/active_record/query_cache.rb
@@ -29,10 +29,10 @@ module ActiveRecord
pools = []
ActiveRecord::Base.connection_handlers.each do |key, handler|
- pools << handler.connection_pool_list.reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! }
+ pools.concat(handler.connection_pool_list.reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! })
end
- pools.flatten
+ pools
end
def self.complete(pools)
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index 4d9acc911b..d699e2e21b 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -265,6 +265,8 @@ db_namespace = namespace :db do
end
abort %{Run `rails db:migrate` to update your database then try again.}
end
+ ensure
+ ActiveRecord::Base.establish_connection(ActiveRecord::Tasks::DatabaseTasks.env.to_sym)
end
namespace :abort_if_pending_migrations do
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 6957ba052b..29e2e2cedc 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -1095,26 +1095,44 @@ module ActiveRecord
end
def build_left_outer_joins(manager, outer_joins, aliases)
- buckets = { association_join: valid_association_list(outer_joins) }
+ buckets = Hash.new { |h, k| h[k] = [] }
+ buckets[:association_join] = valid_association_list(outer_joins)
build_join_query(manager, buckets, Arel::Nodes::OuterJoin, aliases)
end
def build_joins(manager, joins, aliases)
+ buckets = Hash.new { |h, k| h[k] = [] }
+
unless left_outer_joins_values.empty?
left_joins = valid_association_list(left_outer_joins_values.flatten)
- joins.unshift construct_join_dependency(left_joins, Arel::Nodes::OuterJoin)
+ buckets[:stashed_join] << construct_join_dependency(left_joins, Arel::Nodes::OuterJoin)
end
- buckets = joins.group_by do |join|
+ joins.map! do |join|
+ if join.is_a?(String)
+ table.create_string_join(Arel.sql(join.strip)) unless join.blank?
+ else
+ join
+ end
+ end.compact_blank!
+
+ while joins.first.is_a?(Arel::Nodes::Join)
+ join_node = joins.shift
+ if join_node.is_a?(Arel::Nodes::StringJoin) && !buckets[:stashed_join].empty?
+ buckets[:join_node] << join_node
+ else
+ buckets[:leading_join] << join_node
+ end
+ end
+
+ joins.each do |join|
case join
- when String
- :string_join
when Hash, Symbol, Array
- :association_join
+ buckets[:association_join] << join
when ActiveRecord::Associations::JoinDependency
- :stashed_join
+ buckets[:stashed_join] << join
when Arel::Nodes::Join
- :join_node
+ buckets[:join_node] << join
else
raise "unknown class: %s" % join.class.name
end
@@ -1124,25 +1142,21 @@ module ActiveRecord
end
def build_join_query(manager, buckets, join_type, aliases)
- buckets.default = []
-
association_joins = buckets[:association_join]
stashed_joins = buckets[:stashed_join]
+ leading_joins = buckets[:leading_join].tap(&:uniq!)
join_nodes = buckets[:join_node].tap(&:uniq!)
- string_joins = buckets[:string_join].compact_blank!.map!(&:strip).tap(&:uniq!)
-
- string_joins.map! { |join| table.create_string_join(Arel.sql(join)) }
join_sources = manager.join_sources
- join_sources.concat(join_nodes) unless join_nodes.empty?
+ join_sources.concat(leading_joins) unless leading_joins.empty?
unless association_joins.empty? && stashed_joins.empty?
- alias_tracker = alias_tracker(join_nodes + string_joins, aliases)
+ alias_tracker = alias_tracker(leading_joins + join_nodes, aliases)
join_dependency = construct_join_dependency(association_joins, join_type)
join_sources.concat(join_dependency.join_constraints(stashed_joins, alias_tracker))
end
- join_sources.concat(string_joins) unless string_joins.empty?
+ join_sources.concat(join_nodes) unless join_nodes.empty?
end
def build_select(arel)
diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb
index 5d1ce19829..300e67b0aa 100644
--- a/activerecord/lib/active_record/tasks/database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/database_tasks.rb
@@ -4,7 +4,6 @@ require "active_record/database_configurations"
module ActiveRecord
module Tasks # :nodoc:
- class DatabaseAlreadyExists < StandardError; end # :nodoc:
class DatabaseNotSupported < StandardError; end # :nodoc:
# ActiveRecord::Tasks::DatabaseTasks is a utility class, which encapsulates
diff --git a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
index e3efeb75b5..b9a8ccb22c 100644
--- a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
@@ -15,12 +15,6 @@ module ActiveRecord
establish_connection configuration_without_database
connection.create_database configuration["database"], creation_options
establish_connection configuration
- rescue ActiveRecord::StatementInvalid => error
- if connection.error_number(error.cause) == ER_DB_CREATE_EXISTS
- raise DatabaseAlreadyExists
- else
- raise
- end
end
def drop
diff --git a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
index 626ffdfdf9..fc37db216d 100644
--- a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
@@ -21,12 +21,6 @@ module ActiveRecord
connection.create_database configuration["database"],
configuration.merge("encoding" => encoding)
establish_connection configuration
- rescue ActiveRecord::StatementInvalid => error
- if error.cause.is_a?(PG::DuplicateDatabase)
- raise DatabaseAlreadyExists
- else
- raise
- end
end
def drop
diff --git a/activerecord/lib/arel/visitors/mysql.rb b/activerecord/lib/arel/visitors/mysql.rb
index dd77cfdf66..6cb866715f 100644
--- a/activerecord/lib/arel/visitors/mysql.rb
+++ b/activerecord/lib/arel/visitors/mysql.rb
@@ -48,6 +48,14 @@ module Arel # :nodoc: all
visit_Arel_Nodes_IsNotDistinctFrom o, collector
end
+ def visit_Arel_Nodes_Regexp(o, collector)
+ infix_value o, collector, " REGEXP "
+ end
+
+ def visit_Arel_Nodes_NotRegexp(o, collector)
+ infix_value o, collector, " NOT REGEXP "
+ end
+
# In the simple case, MySQL allows us to place JOINs directly into the UPDATE
# query. However, this does not allow for LIMIT, OFFSET and ORDER. To support
# these, we must use a subquery.
diff --git a/activerecord/lib/arel/visitors/oracle.rb b/activerecord/lib/arel/visitors/oracle.rb
index aab66301ef..a0a74d365c 100644
--- a/activerecord/lib/arel/visitors/oracle.rb
+++ b/activerecord/lib/arel/visitors/oracle.rb
@@ -9,7 +9,7 @@ module Arel # :nodoc: all
# if need to select first records without ORDER BY and GROUP BY and without DISTINCT
# then can use simple ROWNUM in WHERE clause
- if o.limit && o.orders.empty? && o.cores.first.groups.empty? && !o.offset && o.cores.first.set_quantifier.class.to_s !~ /Distinct/
+ if o.limit && o.orders.empty? && o.cores.first.groups.empty? && !o.offset && !o.cores.first.set_quantifier.class.to_s.match?(/Distinct/)
o.cores.last.wheres.push Nodes::LessThanOrEqual.new(
Nodes::SqlLiteral.new("ROWNUM"), o.limit.expr
)
@@ -122,7 +122,7 @@ module Arel # :nodoc: all
o.orders = []
orders.each_with_index do |order, i|
o.orders <<
- Nodes::SqlLiteral.new("alias_#{i}__#{' DESC' if /\bdesc$/i === order}")
+ Nodes::SqlLiteral.new("alias_#{i}__#{' DESC' if /\bdesc$/i.match?(order)}")
end
o
end
diff --git a/activerecord/test/cases/arel/nodes/node_test.rb b/activerecord/test/cases/arel/nodes/node_test.rb
index f1e0ce1ea9..8a9ecd84ca 100644
--- a/activerecord/test/cases/arel/nodes/node_test.rb
+++ b/activerecord/test/cases/arel/nodes/node_test.rb
@@ -14,7 +14,7 @@ module Arel
}.grep(Class).each do |klass|
next if Nodes::SqlLiteral == klass
next if Nodes::BindParam == klass
- next if klass.name =~ /^Arel::Nodes::(?:Test|.*Test$)/
+ next if /^Arel::Nodes::(?:Test|.*Test$)/.match?(klass.name)
assert klass.ancestors.include?(Nodes::Node), klass.name
end
end
diff --git a/activerecord/test/cases/arel/select_manager_test.rb b/activerecord/test/cases/arel/select_manager_test.rb
index 526fe6787a..4512d8e8a6 100644
--- a/activerecord/test/cases/arel/select_manager_test.rb
+++ b/activerecord/test/cases/arel/select_manager_test.rb
@@ -514,7 +514,7 @@ module Arel
assert_equal "bar", join.right
end
- it "should create join nodes with a outer join klass" do
+ it "should create join nodes with an outer join klass" do
relation = Arel::SelectManager.new
join = relation.create_join "foo", "bar", Arel::Nodes::OuterJoin
assert_kind_of Arel::Nodes::OuterJoin, join
diff --git a/activerecord/test/cases/arel/visitors/mysql_test.rb b/activerecord/test/cases/arel/visitors/mysql_test.rb
index 5f37587957..05dccd126e 100644
--- a/activerecord/test/cases/arel/visitors/mysql_test.rb
+++ b/activerecord/test/cases/arel/visitors/mysql_test.rb
@@ -104,6 +104,52 @@ module Arel
sql.must_be_like %{ NOT "users"."name" <=> NULL }
end
end
+
+ describe "Nodes::Regexp" do
+ before do
+ @table = Table.new(:users)
+ @attr = @table[:id]
+ end
+
+ it "should know how to visit" do
+ node = @table[:name].matches_regexp("foo.*")
+ node.must_be_kind_of Nodes::Regexp
+ compile(node).must_be_like %{
+ "users"."name" REGEXP 'foo.*'
+ }
+ end
+
+ it "can handle subqueries" do
+ subquery = @table.project(:id).where(@table[:name].matches_regexp("foo.*"))
+ node = @attr.in subquery
+ compile(node).must_be_like %{
+ "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" REGEXP 'foo.*')
+ }
+ end
+ end
+
+ describe "Nodes::NotRegexp" do
+ before do
+ @table = Table.new(:users)
+ @attr = @table[:id]
+ end
+
+ it "should know how to visit" do
+ node = @table[:name].does_not_match_regexp("foo.*")
+ node.must_be_kind_of Nodes::NotRegexp
+ compile(node).must_be_like %{
+ "users"."name" NOT REGEXP 'foo.*'
+ }
+ end
+
+ it "can handle subqueries" do
+ subquery = @table.project(:id).where(@table[:name].does_not_match_regexp("foo.*"))
+ node = @attr.in subquery
+ compile(node).must_be_like %{
+ "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" NOT REGEXP 'foo.*')
+ }
+ end
+ end
end
end
end
diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb
index 3525fa2ab8..6bd305306f 100644
--- a/activerecord/test/cases/associations/belongs_to_associations_test.rb
+++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb
@@ -60,11 +60,8 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
end
def test_belongs_to_does_not_use_order_by
- ActiveRecord::SQLCounter.clear_log
- Client.find(3).firm
- ensure
- sql_log = ActiveRecord::SQLCounter.log
- assert sql_log.all? { |sql| /order by/i !~ sql }, "ORDER BY was used in the query: #{sql_log}"
+ sql_log = capture_sql { Client.find(3).firm }
+ assert sql_log.all? { |sql| !/order by/i.match?(sql) }, "ORDER BY was used in the query: #{sql_log}"
end
def test_belongs_to_with_primary_key
diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb
index 3ef25c7027..6c2a09c296 100644
--- a/activerecord/test/cases/associations/has_one_associations_test.rb
+++ b/activerecord/test/cases/associations/has_one_associations_test.rb
@@ -37,11 +37,8 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
end
def test_has_one_does_not_use_order_by
- ActiveRecord::SQLCounter.clear_log
- companies(:first_firm).account
- ensure
- sql_log = ActiveRecord::SQLCounter.log
- assert sql_log.all? { |sql| /order by/i !~ sql }, "ORDER BY was used in the query: #{sql_log}"
+ sql_log = capture_sql { companies(:first_firm).account }
+ assert sql_log.all? { |sql| !/order by/i.match?(sql) }, "ORDER BY was used in the query: #{sql_log}"
end
def test_has_one_cache_nils
@@ -712,6 +709,24 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
}
end
+ def test_polymorphic_has_one_with_touch_option_on_create_wont_cache_association_so_fetching_after_transaction_commit_works
+ assert_queries(4) {
+ chef = Chef.create(employable: DrinkDesignerWithPolymorphicTouchChef.new)
+ employable = chef.employable
+
+ assert_equal chef, employable.chef
+ }
+ end
+
+ def test_polymorphic_has_one_with_touch_option_on_update_will_touch_record_by_fetching_from_database_if_needed
+ DrinkDesignerWithPolymorphicTouchChef.create(chef: Chef.new)
+ designer = DrinkDesignerWithPolymorphicTouchChef.last
+
+ assert_queries(3) {
+ designer.update(name: "foo")
+ }
+ end
+
def test_has_one_with_touch_option_on_update
new_club = Club.create(name: "1000 Oaks")
new_club.create_membership
diff --git a/activerecord/test/cases/associations/inner_join_association_test.rb b/activerecord/test/cases/associations/inner_join_association_test.rb
index e0dac01f4a..b65af4b819 100644
--- a/activerecord/test/cases/associations/inner_join_association_test.rb
+++ b/activerecord/test/cases/associations/inner_join_association_test.rb
@@ -13,7 +13,7 @@ require "models/tag"
class InnerJoinAssociationTest < ActiveRecord::TestCase
fixtures :authors, :author_addresses, :essays, :posts, :comments, :categories, :categories_posts, :categorizations,
- :taggings, :tags
+ :taggings, :tags, :people
def test_construct_finder_sql_applies_aliases_tables_on_association_conditions
result = Author.joins(:thinking_posts, :welcome_posts).to_a
@@ -36,16 +36,37 @@ class InnerJoinAssociationTest < ActiveRecord::TestCase
end
def test_construct_finder_sql_does_not_table_name_collide_with_string_joins
- sql = Person.joins(:agents).joins("JOIN people agents_people ON agents_people.primary_contact_id = people.id").to_sql
- assert_match(/agents_people_2/i, sql)
+ string_join = <<~SQL
+ JOIN people agents_people ON agents_people.primary_contact_id = agents_people_2.id AND agents_people.id > agents_people_2.id
+ SQL
+
+ expected = people(:susan)
+ assert_sql(/agents_people_2/i) do
+ assert_equal [expected], Person.joins(:agents).joins(string_join)
+ end
end
def test_construct_finder_sql_does_not_table_name_collide_with_aliased_joins
- people = Person.arel_table
- agents = people.alias("agents_people")
- constraint = agents[:primary_contact_id].eq(people[:id])
- sql = Person.joins(:agents).joins(agents.create_join(agents, agents.create_on(constraint))).to_sql
- assert_match(/agents_people_2/i, sql)
+ agents = Person.arel_table.alias("agents_people")
+ agents_2 = Person.arel_table.alias("agents_people_2")
+ constraint = agents[:primary_contact_id].eq(agents_2[:id]).and(agents[:id].gt(agents_2[:id]))
+
+ expected = people(:susan)
+ assert_sql(/agents_people_2/i) do
+ assert_equal [expected], Person.joins(:agents).joins(agents.create_join(agents, agents.create_on(constraint)))
+ end
+ end
+
+ def test_user_supplied_joins_order_should_be_preserved
+ string_join = <<~SQL
+ JOIN people agents_people_2 ON agents_people_2.primary_contact_id = people.id
+ SQL
+ agents = Person.arel_table.alias("agents_people")
+ agents_2 = Person.arel_table.alias("agents_people_2")
+ constraint = agents[:primary_contact_id].eq(agents_2[:id]).and(agents[:id].gt(agents_2[:id]))
+
+ expected = people(:susan)
+ assert_equal [expected], Person.joins(string_join).joins(agents.create_join(agents, agents.create_on(constraint)))
end
def test_construct_finder_sql_ignores_empty_joins_hash
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 95e57f42e3..ee2972101f 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
@@ -334,6 +334,8 @@ module ActiveRecord
}
}
+ configs = ActiveRecord::DatabaseConfigurations.new(config)
+ actual = configs.configs_for(env_name: "default_env", spec_name: "primary").config
expected = {
"adapter" => "postgresql",
"database" => "foo",
@@ -341,11 +343,37 @@ module ActiveRecord
"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
+ assert_equal expected, actual
+
+ configs = ActiveRecord::DatabaseConfigurations.new(config)
+ actual = configs.configs_for(env_name: "default_env", spec_name: "animals").config
+ expected = { "pool" => 5 }
+
+ assert_equal expected, actual
+ end
+
+ def test_separate_database_env_vars
+ ENV["DATABASE_URL"] = "postgres://localhost/foo"
+ ENV["PRIMARY_DATABASE_URL"] = "postgres://localhost/primary"
+ ENV["ANIMALS_DATABASE_URL"] = "postgres://localhost/animals"
+
+ config = {
+ "default_env" => {
+ "primary" => { "pool" => 5 },
+ "animals" => { "pool" => 5 }
+ }
+ }
+
+ configs = ActiveRecord::DatabaseConfigurations.new(config)
+ actual = configs.configs_for(env_name: "default_env", spec_name: "primary").config
+ assert_equal "primary", actual["database"]
+
+ configs = ActiveRecord::DatabaseConfigurations.new(config)
+ actual = configs.configs_for(env_name: "default_env", spec_name: "animals").config
+ assert_equal "animals", actual["database"]
+ ensure
+ ENV.delete("PRIMARY_DATABASE_URL")
+ ENV.delete("ANIMALS_DATABASE_URL")
end
def test_does_not_change_other_environments
diff --git a/activerecord/test/cases/database_configurations_test.rb b/activerecord/test/cases/database_configurations_test.rb
index 725d1b5d1b..714b9d75c5 100644
--- a/activerecord/test/cases/database_configurations_test.rb
+++ b/activerecord/test/cases/database_configurations_test.rb
@@ -89,7 +89,7 @@ class LegacyDatabaseConfigurationsTest < ActiveRecord::TestCase
end
def test_first_is_deprecated
- first_config = ActiveRecord::Base.configurations.values.first
+ first_config = ActiveRecord::Base.configurations.configurations.map(&:config).first
assert_deprecated do
env_name, config = ActiveRecord::Base.configurations.first
assert_equal "arunit", env_name
diff --git a/activerecord/test/cases/enum_test.rb b/activerecord/test/cases/enum_test.rb
index 8673a99c45..0ae156320a 100644
--- a/activerecord/test/cases/enum_test.rb
+++ b/activerecord/test/cases/enum_test.rb
@@ -580,7 +580,9 @@ class EnumTest < ActiveRecord::TestCase
def self.name
"Book"
end
- enum status: [:sent, :not_sent]
+ silence_warnings do
+ enum status: [:sent, :not_sent]
+ end
end
assert_match(expected_message, logger.logged(:warn).first)
diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb
index a7f01e898e..0861d938c5 100644
--- a/activerecord/test/cases/fixtures_test.rb
+++ b/activerecord/test/cases/fixtures_test.rb
@@ -67,7 +67,7 @@ class FixturesTest < ActiveRecord::TestCase
end
def call(_, _, _, _, values)
- @events << values[:sql] if values[:sql] =~ /INSERT/
+ @events << values[:sql] if /INSERT/.match?(values[:sql])
end
end
@@ -1279,6 +1279,33 @@ class CustomNameForFixtureOrModelTest < ActiveRecord::TestCase
end
end
+class IgnoreFixturesTest < ActiveRecord::TestCase
+ fixtures :other_books, :parrots
+
+ test "ignores books fixtures" do
+ assert_raise(StandardError) { other_books(:published) }
+ assert_raise(StandardError) { other_books(:published_paperback) }
+ assert_raise(StandardError) { other_books(:published_ebook) }
+
+ assert_equal 2, Book.count
+ assert_equal "Agile Web Development with Rails", other_books(:awdr).name
+ assert_equal "published", other_books(:awdr).status
+ assert_equal "paperback", other_books(:awdr).format
+ assert_equal "english", other_books(:awdr).language
+
+ assert_equal "Ruby for Rails", other_books(:rfr).name
+ assert_equal "ebook", other_books(:rfr).format
+ assert_equal "published", other_books(:rfr).status
+ end
+
+ test "ignores parrots fixtures" do
+ assert_raise(StandardError) { parrots(:DEFAULT) }
+ assert_raise(StandardError) { parrots(:DEAD_PARROT) }
+
+ assert_equal "DeadParrot", parrots(:polly).parrot_sti_class
+ end
+end
+
class FixturesWithDefaultScopeTest < ActiveRecord::TestCase
fixtures :bulbs
diff --git a/activerecord/test/cases/tasks/mysql_rake_test.rb b/activerecord/test/cases/tasks/mysql_rake_test.rb
index ac3c5bc26e..4b039395e8 100644
--- a/activerecord/test/cases/tasks/mysql_rake_test.rb
+++ b/activerecord/test/cases/tasks/mysql_rake_test.rb
@@ -93,11 +93,9 @@ if current_adapter?(:Mysql2Adapter)
with_stubbed_connection_establish_connection do
ActiveRecord::Base.connection.stub(
:create_database,
- proc { raise ActiveRecord::StatementInvalid }
+ proc { raise ActiveRecord::DatabaseAlreadyExists }
) do
- ActiveRecord::Base.connection.stub(:error_number, 1007) do
- ActiveRecord::Tasks::DatabaseTasks.create @configuration
- end
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
assert_equal "Database 'my-app-db' already exists\n", $stderr.string
end
diff --git a/activerecord/test/cases/tasks/postgresql_rake_test.rb b/activerecord/test/cases/tasks/postgresql_rake_test.rb
index f9df650687..d74ba0580d 100644
--- a/activerecord/test/cases/tasks/postgresql_rake_test.rb
+++ b/activerecord/test/cases/tasks/postgresql_rake_test.rb
@@ -129,7 +129,7 @@ if current_adapter?(:PostgreSQLAdapter)
with_stubbed_connection_establish_connection do
ActiveRecord::Base.connection.stub(
:create_database,
- proc { raise ActiveRecord::Tasks::DatabaseAlreadyExists }
+ proc { raise ActiveRecord::DatabaseAlreadyExists }
) do
ActiveRecord::Tasks::DatabaseTasks.create @configuration
diff --git a/activerecord/test/fixtures/other_books.yml b/activerecord/test/fixtures/other_books.yml
new file mode 100644
index 0000000000..62806c03d7
--- /dev/null
+++ b/activerecord/test/fixtures/other_books.yml
@@ -0,0 +1,26 @@
+_fixture:
+ model_class: Book
+ ignore:
+ - PUBLISHED
+ - PUBLISHED_PAPERBACK
+ - PUBLISHED_EBOOK
+
+PUBLISHED: &PUBLISHED
+ status: :published
+
+PUBLISHED_PAPERBACK: &PUBLISHED_PAPERBACK
+ <<: *PUBLISHED
+ format: "paperback"
+ language: :english
+
+PUBLISHED_EBOOK: &PUBLISHED_EBOOK
+ <<: *PUBLISHED
+ format: "ebook"
+
+awdr:
+ <<: *PUBLISHED_PAPERBACK
+ name: "Agile Web Development with Rails"
+
+rfr:
+ <<: *PUBLISHED_EBOOK
+ name: "Ruby for Rails"
diff --git a/activerecord/test/fixtures/parrots.yml b/activerecord/test/fixtures/parrots.yml
index 8425ef98e0..4f0a090e03 100644
--- a/activerecord/test/fixtures/parrots.yml
+++ b/activerecord/test/fixtures/parrots.yml
@@ -1,3 +1,9 @@
+_fixture:
+ ignore: DEAD_PARROT
+
+DEAD_PARROT: &DEAD_PARROT
+ parrot_sti_class: DeadParrot
+
george:
name: "Curious George"
treasures: diamond, sapphire
@@ -17,7 +23,7 @@ polly:
name: $LABEL
killer: blackbeard
treasures: sapphire, ruby
- parrot_sti_class: DeadParrot
+ <<: *DEAD_PARROT
DEFAULTS: &DEFAULTS
treasures: sapphire, ruby
diff --git a/activerecord/test/models/drink_designer.rb b/activerecord/test/models/drink_designer.rb
index 8258408f35..fe7f5c9e03 100644
--- a/activerecord/test/models/drink_designer.rb
+++ b/activerecord/test/models/drink_designer.rb
@@ -10,5 +10,11 @@ class DrinkDesignerWithPolymorphicDependentNullifyChef < ActiveRecord::Base
has_one :chef, as: :employable, dependent: :nullify
end
+class DrinkDesignerWithPolymorphicTouchChef < ActiveRecord::Base
+ self.table_name = "drink_designers"
+
+ has_one :chef, as: :employable, touch: true
+end
+
class MocktailDesigner < DrinkDesigner
end
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index dd0ff759b6..cae2890c9e 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -1070,6 +1070,7 @@ ActiveRecord::Schema.define do
create_table :cake_designers, force: true do |t|
end
create_table :drink_designers, force: true do |t|
+ t.string :name
end
create_table :chefs, force: true do |t|
t.integer :employable_id
@@ -1077,6 +1078,7 @@ ActiveRecord::Schema.define do
t.integer :department_id
t.string :employable_list_type
t.integer :employable_list_id
+ t.timestamps
end
create_table :recipes, force: true do |t|
t.integer :chef_id
diff --git a/activestorage/lib/active_storage/service/s3_service.rb b/activestorage/lib/active_storage/service/s3_service.rb
index e4bd57048a..a73f6ab526 100644
--- a/activestorage/lib/active_storage/service/s3_service.rb
+++ b/activestorage/lib/active_storage/service/s3_service.rb
@@ -20,12 +20,14 @@ module ActiveStorage
@upload_options = upload
end
- def upload(key, io, checksum: nil, content_type: nil, **)
+ def upload(key, io, checksum: nil, filename: nil, content_type: nil, disposition: nil, **)
instrument :upload, key: key, checksum: checksum do
+ content_disposition = content_disposition_with(filename: filename, type: disposition) if disposition && filename
+
if io.size < multipart_upload_threshold
- upload_with_single_part key, io, checksum: checksum, content_type: content_type
+ upload_with_single_part key, io, checksum: checksum, content_type: content_type, content_disposition: content_disposition
else
- upload_with_multipart key, io, content_type: content_type
+ upload_with_multipart key, io, content_type: content_type, content_disposition: content_disposition
end
end
end
@@ -103,16 +105,16 @@ module ActiveStorage
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)
+ def upload_with_single_part(key, io, checksum: nil, content_type: nil, content_disposition: nil)
+ object_for(key).put(body: io, content_md5: checksum, content_type: content_type, content_disposition: content_disposition, **upload_options)
rescue Aws::S3::Errors::BadDigest
raise ActiveStorage::IntegrityError
end
- def upload_with_multipart(key, io, content_type: nil)
+ def upload_with_multipart(key, io, content_type: nil, content_disposition: 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|
+ object_for(key).upload_stream(content_type: content_type, content_disposition: content_disposition, part_size: part_size, **upload_options) do |out|
IO.copy_stream(io, out)
end
end
diff --git a/activestorage/test/dummy/config/initializers/backtrace_silencers.rb b/activestorage/test/dummy/config/initializers/backtrace_silencers.rb
index d0f0d3b5df..8452ef9236 100644
--- a/activestorage/test/dummy/config/initializers/backtrace_silencers.rb
+++ b/activestorage/test/dummy/config/initializers/backtrace_silencers.rb
@@ -2,7 +2,7 @@
# Be sure to restart your server when you modify this file.
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
-# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
+# Rails.backtrace_cleaner.add_silencer { |line| /my_noisy_library/.match?(line) }
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
# Rails.backtrace_cleaner.remove_silencers!
diff --git a/activestorage/test/fixtures/files/racecar.tif b/activestorage/test/fixtures/files/racecar.tif
index 0a11b22896..97430741e2 100644
--- a/activestorage/test/fixtures/files/racecar.tif
+++ b/activestorage/test/fixtures/files/racecar.tif
Binary files differ
diff --git a/activestorage/test/service/s3_service_test.rb b/activestorage/test/service/s3_service_test.rb
index b9120770e6..3dd1b59681 100644
--- a/activestorage/test/service/s3_service_test.rb
+++ b/activestorage/test/service/s3_service_test.rb
@@ -77,6 +77,23 @@ if SERVICE_CONFIGURATIONS[:s3]
@service.delete key
end
+ test "upload with content disposition" do
+ key = SecureRandom.base58(24)
+ data = "Something else entirely!"
+
+ @service.upload(
+ key,
+ StringIO.new(data),
+ checksum: Digest::MD5.base64digest(data),
+ filename: ActiveStorage::Filename.new("cool_data.txt"),
+ disposition: :attachment
+ )
+
+ assert_equal("attachment; filename=\"cool_data.txt\"; filename*=UTF-8''cool_data.txt", @service.bucket.object(key).content_disposition)
+ ensure
+ @service.delete key
+ end
+
test "uploading a large object in multiple parts" do
service = build_service(upload: { multipart_threshold: 5.megabytes })
diff --git a/activesupport/lib/active_support/backtrace_cleaner.rb b/activesupport/lib/active_support/backtrace_cleaner.rb
index f55e821e10..6273012808 100644
--- a/activesupport/lib/active_support/backtrace_cleaner.rb
+++ b/activesupport/lib/active_support/backtrace_cleaner.rb
@@ -16,7 +16,7 @@ module ActiveSupport
#
# bc = ActiveSupport::BacktraceCleaner.new
# bc.add_filter { |line| line.gsub(Rails.root.to_s, '') } # strip the Rails.root prefix
- # bc.add_silencer { |line| line =~ /puma|rubygems/ } # skip any lines from puma or rubygems
+ # bc.add_silencer { |line| /puma|rubygems/.match?(line) } # skip any lines from puma or rubygems
# bc.clean(exception.backtrace) # perform the cleanup
#
# To reconfigure an existing BacktraceCleaner (like the default one in Rails)
@@ -65,7 +65,7 @@ module ActiveSupport
# for a given line, it will be excluded from the clean backtrace.
#
# # Will reject all lines that include the word "puma", like "/gems/puma/server.rb" or "/app/my_puma_server/rb"
- # backtrace_cleaner.add_silencer { |line| line =~ /puma/ }
+ # backtrace_cleaner.add_silencer { |line| /puma/.match?(line) }
def add_silencer(&block)
@silencers << block
end
diff --git a/activesupport/lib/active_support/core_ext/name_error.rb b/activesupport/lib/active_support/core_ext/name_error.rb
index 6d37cd9dfd..c51aec0e03 100644
--- a/activesupport/lib/active_support/core_ext/name_error.rb
+++ b/activesupport/lib/active_support/core_ext/name_error.rb
@@ -15,7 +15,7 @@ class NameError
# We should use original_message message instead.
message = respond_to?(:original_message) ? original_message : self.message
- if /undefined local variable or method/ !~ message
+ unless /undefined local variable or method/.match?(message)
$1 if /((::)?([A-Z]\w*)(::[A-Z]\w*)*)$/ =~ message
end
end
diff --git a/activesupport/lib/active_support/core_ext/string/access.rb b/activesupport/lib/active_support/core_ext/string/access.rb
index 4f70e7f5fc..f6a14c08bc 100644
--- a/activesupport/lib/active_support/core_ext/string/access.rb
+++ b/activesupport/lib/active_support/core_ext/string/access.rb
@@ -62,7 +62,7 @@ class String
# str.from(1).to(-2) # => "ell"
def to(position)
position += size if position < 0
- self[0, position + 1].to_s
+ self[0, position + 1] || +""
end
# Returns the first character. If a limit is supplied, returns a substring
@@ -76,17 +76,7 @@ class String
# str.first(0) # => ""
# str.first(6) # => "hello"
def first(limit = 1)
- ActiveSupport::Deprecation.warn(
- "Calling String#first with a negative integer limit " \
- "will raise an ArgumentError in Rails 6.1."
- ) if limit < 0
- if limit == 0
- ""
- elsif limit >= size
- dup
- else
- to(limit - 1)
- end
+ self[0, limit] || raise(ArgumentError, "negative limit")
end
# Returns the last character of the string. If a limit is supplied, returns a substring
@@ -100,16 +90,6 @@ class String
# str.last(0) # => ""
# str.last(6) # => "hello"
def last(limit = 1)
- ActiveSupport::Deprecation.warn(
- "Calling String#last with a negative integer limit " \
- "will raise an ArgumentError in Rails 6.1."
- ) if limit < 0
- if limit == 0
- ""
- elsif limit >= size
- dup
- else
- from(-limit)
- end
+ self[[length - limit, 0].max, limit] || raise(ArgumentError, "negative limit")
end
end
diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb
index 923d6ad228..6d71a67a46 100644
--- a/activesupport/lib/active_support/dependencies.rb
+++ b/activesupport/lib/active_support/dependencies.rb
@@ -793,7 +793,6 @@ module ActiveSupport #:nodoc:
end
private
-
# Returns the original name of a class or module even if `name` has been
# overridden.
def real_mod_name(mod)
diff --git a/activesupport/lib/active_support/dependencies/zeitwerk_integration.rb b/activesupport/lib/active_support/dependencies/zeitwerk_integration.rb
index f75083a05a..2cf55713bd 100644
--- a/activesupport/lib/active_support/dependencies/zeitwerk_integration.rb
+++ b/activesupport/lib/active_support/dependencies/zeitwerk_integration.rb
@@ -42,6 +42,17 @@ module ActiveSupport
end
end
+ module RequireDependency
+ def require_dependency(filename)
+ filename = filename.to_path if filename.respond_to?(:to_path)
+ if abspath = ActiveSupport::Dependencies.search_for_file(filename)
+ require abspath
+ else
+ require filename
+ end
+ end
+ end
+
module Inflector
def self.camelize(basename, _abspath)
basename.camelize
@@ -90,7 +101,7 @@ module ActiveSupport
def decorate_dependencies
Dependencies.unhook!
Dependencies.singleton_class.prepend(Decorations)
- Object.class_eval { alias_method :require_dependency, :require }
+ Object.prepend(RequireDependency)
end
end
end
diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb
index 18f3f53879..94d1115ccf 100644
--- a/activesupport/lib/active_support/inflector/methods.rb
+++ b/activesupport/lib/active_support/inflector/methods.rb
@@ -269,32 +269,36 @@ module ActiveSupport
# NameError is raised when the name is not in CamelCase or the constant is
# unknown.
def constantize(camel_cased_word)
- names = camel_cased_word.split("::")
-
- # Trigger a built-in NameError exception including the ill-formed constant in the message.
- Object.const_get(camel_cased_word) if names.empty?
-
- # Remove the first blank element in case of '::ClassName' notation.
- names.shift if names.size > 1 && names.first.empty?
-
- names.inject(Object) do |constant, name|
- if constant == Object
- constant.const_get(name)
- else
- candidate = constant.const_get(name)
- next candidate if constant.const_defined?(name, false)
- next candidate unless Object.const_defined?(name)
-
- # Go down the ancestors to check if it is owned directly. The check
- # stops when we reach Object or the end of ancestors tree.
- constant = constant.ancestors.inject(constant) do |const, ancestor|
- break const if ancestor == Object
- break ancestor if ancestor.const_defined?(name, false)
- const
+ if camel_cased_word.blank? || !camel_cased_word.include?("::")
+ Object.const_get(camel_cased_word)
+ else
+ names = camel_cased_word.split("::")
+
+ # Trigger a built-in NameError exception including the ill-formed constant in the message.
+ Object.const_get(camel_cased_word) if names.empty?
+
+ # Remove the first blank element in case of '::ClassName' notation.
+ names.shift if names.size > 1 && names.first.empty?
+
+ names.inject(Object) do |constant, name|
+ if constant == Object
+ constant.const_get(name)
+ else
+ candidate = constant.const_get(name)
+ next candidate if constant.const_defined?(name, false)
+ next candidate unless Object.const_defined?(name)
+
+ # Go down the ancestors to check if it is owned directly. The check
+ # stops when we reach Object or the end of ancestors tree.
+ constant = constant.ancestors.inject(constant) do |const, ancestor|
+ break const if ancestor == Object
+ break ancestor if ancestor.const_defined?(name, false)
+ const
+ end
+
+ # owner is in Object, so raise
+ constant.const_get(name, false)
end
-
- # owner is in Object, so raise
- constant.const_get(name, false)
end
end
end
@@ -371,7 +375,7 @@ module ActiveSupport
last = parts.pop
- parts.reverse.inject(last) do |acc, part|
+ parts.reverse!.inject(last) do |acc, part|
part.empty? ? acc : "#{part}(::#{acc})?"
end
end
diff --git a/activesupport/lib/active_support/inflector/transliterate.rb b/activesupport/lib/active_support/inflector/transliterate.rb
index 0751f8a3ad..1899a1212d 100644
--- a/activesupport/lib/active_support/inflector/transliterate.rb
+++ b/activesupport/lib/active_support/inflector/transliterate.rb
@@ -60,6 +60,7 @@ module ActiveSupport
# Transliteration is restricted to UTF-8, US-ASCII and GB18030 strings
# Other encodings will raise an ArgumentError.
def transliterate(string, replacement = "?", locale: nil)
+ string = string.dup if string.frozen?
raise ArgumentError, "Can only transliterate strings. Received #{string.class.name}" unless string.is_a?(String)
allowed_encodings = [Encoding::UTF_8, Encoding::US_ASCII, Encoding::GB18030]
@@ -116,7 +117,7 @@ module ActiveSupport
# If the optional parameter +locale+ is specified,
# the word will be parameterized as a word of that language.
# By default, this parameter is set to <tt>nil</tt> and it will use
- # the configured <tt>I18n.locale<tt>.
+ # the configured <tt>I18n.locale</tt>.
def parameterize(string, separator: "-", preserve_case: false, locale: nil)
# Replace accented chars with their ASCII equivalents.
parameterized_string = transliterate(string, locale: locale)
diff --git a/activesupport/lib/active_support/logger.rb b/activesupport/lib/active_support/logger.rb
index b8555c887b..2576bee4ff 100644
--- a/activesupport/lib/active_support/logger.rb
+++ b/activesupport/lib/active_support/logger.rb
@@ -14,7 +14,7 @@ module ActiveSupport
# ActiveSupport::Logger.logger_outputs_to?(logger, STDOUT)
# # => true
def self.logger_outputs_to?(logger, *sources)
- logdev = logger.instance_variable_get("@logdev")
+ logdev = logger.instance_variable_get(:@logdev)
logger_source = logdev.dev if logdev.respond_to?(:dev)
sources.any? { |source| source == logger_source }
end
diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb
index 2ba3936cae..868cb70423 100644
--- a/activesupport/lib/active_support/multibyte/chars.rb
+++ b/activesupport/lib/active_support/multibyte/chars.rb
@@ -48,7 +48,7 @@ module ActiveSupport #:nodoc:
alias to_s wrapped_string
alias to_str wrapped_string
- delegate :<=>, :=~, :acts_like_string?, to: :wrapped_string
+ delegate :<=>, :=~, :match?, :acts_like_string?, to: :wrapped_string
# Creates a new Chars instance by wrapping _string_.
def initialize(string)
diff --git a/activesupport/lib/active_support/option_merger.rb b/activesupport/lib/active_support/option_merger.rb
index ab9ca727f6..8e54b11be6 100644
--- a/activesupport/lib/active_support/option_merger.rb
+++ b/activesupport/lib/active_support/option_merger.rb
@@ -5,7 +5,7 @@ require "active_support/core_ext/hash/deep_merge"
module ActiveSupport
class OptionMerger #:nodoc:
instance_methods.each do |method|
- undef_method(method) if method !~ /^(__|instance_eval|class|object_id)/
+ undef_method(method) unless method.match?(/^(__|instance_eval|class|object_id)/)
end
def initialize(context, options)
diff --git a/activesupport/lib/active_support/parameter_filter.rb b/activesupport/lib/active_support/parameter_filter.rb
index e1cd7c46c1..f4c4f2d2fb 100644
--- a/activesupport/lib/active_support/parameter_filter.rb
+++ b/activesupport/lib/active_support/parameter_filter.rb
@@ -22,7 +22,7 @@ module ActiveSupport
# change { file: { code: "xxxx"} }
#
# ActiveSupport::ParameterFilter.new([-> (k, v) do
- # v.reverse! if k =~ /secret/i
+ # v.reverse! if /secret/i.match?(k)
# end])
# => reverses the value to all keys matching /secret/i
class ParameterFilter
diff --git a/activesupport/lib/active_support/per_thread_registry.rb b/activesupport/lib/active_support/per_thread_registry.rb
index eb92fb4371..bf5a3b97ae 100644
--- a/activesupport/lib/active_support/per_thread_registry.rb
+++ b/activesupport/lib/active_support/per_thread_registry.rb
@@ -40,7 +40,7 @@ module ActiveSupport
# If the class has an initializer, it must accept no arguments.
module PerThreadRegistry
def self.extended(object)
- object.instance_variable_set "@per_thread_registry_key", object.name.freeze
+ object.instance_variable_set :@per_thread_registry_key, object.name.freeze
end
def instance
diff --git a/activesupport/lib/active_support/secure_compare_rotator.rb b/activesupport/lib/active_support/secure_compare_rotator.rb
index 97110d41f7..269703c34a 100644
--- a/activesupport/lib/active_support/secure_compare_rotator.rb
+++ b/activesupport/lib/active_support/secure_compare_rotator.rb
@@ -44,7 +44,6 @@ module ActiveSupport
end
private
-
def build_rotation(previous_value, _options)
self.class.new(previous_value)
end
diff --git a/activesupport/lib/active_support/tagged_logging.rb b/activesupport/lib/active_support/tagged_logging.rb
index d8a86d997e..75a7ca24c2 100644
--- a/activesupport/lib/active_support/tagged_logging.rb
+++ b/activesupport/lib/active_support/tagged_logging.rb
@@ -32,15 +32,18 @@ module ActiveSupport
def push_tags(*tags)
tags.flatten.reject(&:blank?).tap do |new_tags|
+ @tags_text = nil
current_tags.concat new_tags
end
end
def pop_tags(size = 1)
+ @tags_text = nil
current_tags.pop size
end
def clear_tags!
+ @tags_text = nil
current_tags.clear
end
@@ -51,11 +54,13 @@ module ActiveSupport
end
def tags_text
- tags = current_tags
- if tags.one?
- "[#{tags[0]}] "
- elsif tags.any?
- tags.collect { |tag| "[#{tag}] " }.join
+ @tags_text ||= begin
+ tags = current_tags
+ if tags.one?
+ "[#{tags[0]}] "
+ elsif tags.any?
+ tags.collect { |tag| "[#{tag}] " }.join
+ end
end
end
end
diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb
index d9e033e23b..90830b89bd 100644
--- a/activesupport/lib/active_support/values/time_zone.rb
+++ b/activesupport/lib/active_support/values/time_zone.rb
@@ -334,6 +334,13 @@ module ActiveSupport
re === name || re === MAPPING[name]
end
+ # Compare #name and TZInfo identifier to a supplied regexp, returning +true+
+ # if a match is found.
+ def match?(re)
+ (re == name) || (re == MAPPING[name]) ||
+ ((Regexp === re) && (re.match?(name) || re.match?(MAPPING[name])))
+ end
+
# Returns a textual representation of this time zone.
def to_s
"(GMT#{formatted_offset}) #{name}"
diff --git a/activesupport/test/cache/stores/mem_cache_store_test.rb b/activesupport/test/cache/stores/mem_cache_store_test.rb
index 3917d14d1c..0a5e20ed46 100644
--- a/activesupport/test/cache/stores/mem_cache_store_test.rb
+++ b/activesupport/test/cache/stores/mem_cache_store_test.rb
@@ -9,7 +9,7 @@ require "dalli"
# connection pool testing.
class SlowDalliClient < Dalli::Client
def get(key, options = {})
- if key =~ /latency/
+ if /latency/.match?(key)
sleep 3
else
super
diff --git a/activesupport/test/cache/stores/redis_cache_store_test.rb b/activesupport/test/cache/stores/redis_cache_store_test.rb
index a2177e0476..0ea37b15d5 100644
--- a/activesupport/test/cache/stores/redis_cache_store_test.rb
+++ b/activesupport/test/cache/stores/redis_cache_store_test.rb
@@ -15,7 +15,7 @@ Redis::Connection.drivers.append(driver)
# connection pool testing.
class SlowRedis < Redis
def get(key, options = {})
- if key =~ /latency/
+ if /latency/.match?(key)
sleep 3
else
super
diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb
index cc37c4fa99..221a8a5731 100644
--- a/activesupport/test/callbacks_test.rb
+++ b/activesupport/test/callbacks_test.rb
@@ -256,7 +256,7 @@ module CallbacksTest
end
def respond_to_missing?(sym)
- sym =~ /^(log|wrap)_/ || super
+ sym.match?(/^(log|wrap)_/) || super
end
end
diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb
index b1ab9533e7..af8f9c9b09 100644
--- a/activesupport/test/core_ext/string_ext_test.rb
+++ b/activesupport/test/core_ext/string_ext_test.rb
@@ -482,12 +482,16 @@ class StringAccessTest < ActiveSupport::TestCase
assert_not_same different_string, string
end
- test "#first with negative Integer is deprecated" do
- string = "hello"
- message = "Calling String#first with a negative integer limit " \
- "will raise an ArgumentError in Rails 6.1."
- assert_deprecated(message) do
- string.first(-1)
+ test "#first with Integer returns a non-frozen string" do
+ string = "he"
+ (0..string.length + 1).each do |limit|
+ assert_not string.first(limit).frozen?
+ end
+ end
+
+ test "#first with negative Integer raises ArgumentError" do
+ assert_raise ArgumentError do
+ "hello".first(-1)
end
end
@@ -509,12 +513,16 @@ class StringAccessTest < ActiveSupport::TestCase
assert_not_same different_string, string
end
- test "#last with negative Integer is deprecated" do
- string = "hello"
- message = "Calling String#last with a negative integer limit " \
- "will raise an ArgumentError in Rails 6.1."
- assert_deprecated(message) do
- string.last(-1)
+ test "#last with Integer returns a non-frozen string" do
+ string = "he"
+ (0..string.length + 1).each do |limit|
+ assert_not string.last(limit).frozen?
+ end
+ end
+
+ test "#last with negative Integer raises ArgumentError" do
+ assert_raise ArgumentError do
+ "hello".last(-1)
end
end
diff --git a/activesupport/test/message_encryptor_test.rb b/activesupport/test/message_encryptor_test.rb
index 097aa8b5f8..f807497709 100644
--- a/activesupport/test/message_encryptor_test.rb
+++ b/activesupport/test/message_encryptor_test.rb
@@ -174,7 +174,7 @@ class MessageEncryptorTest < ActiveSupport::TestCase
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
+ rotated = rotated = false # double assigning to suppress "assigned but unused variable" warning
encryptor = ActiveSupport::MessageEncryptor.new(@secret, on_rotation: proc { rotated = true })
encryptor.rotate secrets[:older], "older sign"
@@ -188,7 +188,7 @@ class MessageEncryptorTest < ActiveSupport::TestCase
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
+ rotated = rotated = false # double assigning to suppress "assigned but unused variable" warning
encryptor = ActiveSupport::MessageEncryptor.new(@secret, on_rotation: proc { rotated = true })
encryptor.rotate secrets[:older], "older sign"
diff --git a/activesupport/test/multibyte_chars_test.rb b/activesupport/test/multibyte_chars_test.rb
index e0e0d9afc0..b0027047df 100644
--- a/activesupport/test/multibyte_chars_test.rb
+++ b/activesupport/test/multibyte_chars_test.rb
@@ -204,6 +204,12 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase
assert_equal 3, (@chars =~ /わ/u)
end
+ def test_match_should_return_boolean_for_regexp_match
+ assert_not @chars.match?(/wrong/u)
+ assert @chars.match?(/こに/u)
+ assert @chars.match?(/ち/u)
+ end
+
def test_should_use_character_offsets_for_insert_offsets
assert_equal "", (+"").mb_chars.insert(0, "")
assert_equal "こわにちわ", @chars.insert(1, "わ")
diff --git a/activesupport/test/parameter_filter_test.rb b/activesupport/test/parameter_filter_test.rb
index e680a22479..510921cf95 100644
--- a/activesupport/test/parameter_filter_test.rb
+++ b/activesupport/test/parameter_filter_test.rb
@@ -22,7 +22,7 @@ class ParameterFilterTest < ActiveSupport::TestCase
filter_words << "blah"
filter_words << lambda { |key, value|
- value.reverse! if key =~ /bargain/
+ value.reverse! if /bargain/.match?(key)
}
filter_words << lambda { |key, value, original_params|
value.replace("world!") if original_params["barg"]["blah"] == "bar" && key == "hello"
@@ -61,7 +61,7 @@ class ParameterFilterTest < ActiveSupport::TestCase
filter_words << "blah"
filter_words << lambda { |key, value|
- value.reverse! if key =~ /bargain/
+ value.reverse! if /bargain/.match?(key)
}
filter_words << lambda { |key, value, original_params|
value.replace("world!") if original_params["barg"]["blah"] == "bar" && key == "hello"
diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb
index f948c363df..6ca3afd561 100644
--- a/activesupport/test/time_zone_test.rb
+++ b/activesupport/test/time_zone_test.rb
@@ -717,6 +717,13 @@ class TimeZoneTest < ActiveSupport::TestCase
assert zone !~ /Nonexistent_Place/
end
+ def test_zone_match?
+ zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
+ assert zone.match?(/Eastern/)
+ assert zone.match?(/New_York/)
+ assert_not zone.match?(/Nonexistent_Place/)
+ end
+
def test_to_s
assert_equal "(GMT+05:30) New Delhi", ActiveSupport::TimeZone["New Delhi"].to_s
end
diff --git a/activesupport/test/transliterate_test.rb b/activesupport/test/transliterate_test.rb
index 2e02b5e938..f13c5efa47 100644
--- a/activesupport/test/transliterate_test.rb
+++ b/activesupport/test/transliterate_test.rb
@@ -59,19 +59,19 @@ class TransliterateTest < ActiveSupport::TestCase
end
def test_transliterate_handles_strings_with_valid_utf8_encodings
- string = String.new("A", encoding: Encoding::UTF_8)
+ string = String.new("A", encoding: Encoding::UTF_8).freeze
assert_equal "A", ActiveSupport::Inflector.transliterate(string)
end
def test_transliterate_handles_strings_with_valid_us_ascii_encodings
- string = String.new("A", encoding: Encoding::US_ASCII)
+ string = String.new("A", encoding: Encoding::US_ASCII).freeze
transcoded = ActiveSupport::Inflector.transliterate(string)
assert_equal "A", transcoded
assert_equal Encoding::US_ASCII, transcoded.encoding
end
def test_transliterate_handles_strings_with_valid_gb18030_encodings
- string = String.new("A", encoding: Encoding::GB18030)
+ string = String.new("A", encoding: Encoding::GB18030).freeze
transcoded = ActiveSupport::Inflector.transliterate(string)
assert_equal "A", transcoded
assert_equal Encoding::GB18030, transcoded.encoding
@@ -84,7 +84,7 @@ class TransliterateTest < ActiveSupport::TestCase
Encoding::GB18030
]
incompatible_encodings.each do |encoding|
- string = String.new("", encoding: encoding)
+ string = String.new("", encoding: encoding).freeze
exception = assert_raises ArgumentError do
ActiveSupport::Inflector.transliterate(string)
end
@@ -93,17 +93,17 @@ class TransliterateTest < ActiveSupport::TestCase
end
def test_transliterate_handles_strings_with_invalid_utf8_bytes
- string = String.new("\255", encoding: Encoding::UTF_8)
+ string = String.new("\255", encoding: Encoding::UTF_8).freeze
assert_equal "?", ActiveSupport::Inflector.transliterate(string)
end
def test_transliterate_handles_strings_with_invalid_us_ascii_bytes
- string = String.new("\255", encoding: Encoding::US_ASCII)
+ string = String.new("\255", encoding: Encoding::US_ASCII).freeze
assert_equal "?", ActiveSupport::Inflector.transliterate(string)
end
def test_transliterate_handles_strings_with_invalid_gb18030_bytes
- string = String.new("\255", encoding: Encoding::GB18030)
+ string = String.new("\255", encoding: Encoding::GB18030).freeze
assert_equal "?", ActiveSupport::Inflector.transliterate(string)
end
end
diff --git a/guides/rails_guides/kindle.rb b/guides/rails_guides/kindle.rb
index 8a0361ff4c..fc8e6b97e6 100644
--- a/guides/rails_guides/kindle.rb
+++ b/guides/rails_guides/kindle.rb
@@ -36,7 +36,7 @@ module Kindle
frontmatter = []
html_pages.delete_if { |x|
if /(toc|welcome|copyright).html/.match?(x)
- frontmatter << x unless x =~ /toc/
+ frontmatter << x unless /toc/.match?(x)
true
end
}
diff --git a/guides/source/action_mailer_basics.md b/guides/source/action_mailer_basics.md
index f600cf29ce..9f4a567f96 100644
--- a/guides/source/action_mailer_basics.md
+++ b/guides/source/action_mailer_basics.md
@@ -743,7 +743,7 @@ files (environment.rb, production.rb, etc...)
| Configuration | Description |
|---------------|-------------|
|`logger`|Generates information on the mailing run if available. Can be set to `nil` for no logging. Compatible with both Ruby's own `Logger` and `Log4r` loggers.|
-|`smtp_settings`|Allows detailed configuration for `:smtp` delivery method:<ul><li>`:address` - Allows you to use a remote mail server. Just change it from its default `"localhost"` setting.</li><li>`:port` - On the off chance that your mail server doesn't run on port 25, you can change it.</li><li>`:domain` - If you need to specify a HELO domain, you can do it here.</li><li>`:user_name` - If your mail server requires authentication, set the username in this setting.</li><li>`:password` - If your mail server requires authentication, set the password in this setting.</li><li>`:authentication` - If your mail server requires authentication, you need to specify the authentication type here. This is a symbol and one of `:plain` (will send the password in the clear), `:login` (will send password Base64 encoded) or `:cram_md5` (combines a Challenge/Response mechanism to exchange information and a cryptographic Message Digest 5 algorithm to hash important information)</li><li>`:enable_starttls_auto` - Detects if STARTTLS is enabled in your SMTP server and starts to use it. Defaults to `true`.</li><li>`:openssl_verify_mode` - When using TLS, you can set how OpenSSL checks the certificate. This is really useful if you need to validate a self-signed and/or a wildcard certificate. You can use the name of an OpenSSL verify constant ('none' or 'peer') or directly the constant (`OpenSSL::SSL::VERIFY_NONE` or `OpenSSL::SSL::VERIFY_PEER`).</li></ul>|
+|`smtp_settings`|Allows detailed configuration for `:smtp` delivery method:<ul><li>`:address` - Allows you to use a remote mail server. Just change it from its default `"localhost"` setting.</li><li>`:port` - On the off chance that your mail server doesn't run on port 25, you can change it.</li><li>`:domain` - If you need to specify a HELO domain, you can do it here.</li><li>`:user_name` - If your mail server requires authentication, set the username in this setting.</li><li>`:password` - If your mail server requires authentication, set the password in this setting.</li><li>`:authentication` - If your mail server requires authentication, you need to specify the authentication type here. This is a symbol and one of `:plain` (will send the password in the clear), `:login` (will send password Base64 encoded) or `:cram_md5` (combines a Challenge/Response mechanism to exchange information and a cryptographic Message Digest 5 algorithm to hash important information)</li><li>`:enable_starttls_auto` - Detects if STARTTLS is enabled in your SMTP server and starts to use it. Defaults to `true`.</li><li>`:openssl_verify_mode` - When using TLS, you can set how OpenSSL checks the certificate. This is really useful if you need to validate a self-signed and/or a wildcard certificate. You can use the name of an OpenSSL verify constant ('none' or 'peer') or directly the constant (`OpenSSL::SSL::VERIFY_NONE` or `OpenSSL::SSL::VERIFY_PEER`).</li><li>`:ssl/:tls` - Enables the SMTP connection to use SMTP/TLS (SMTPS: SMTP over direct TLS connection)</li></ul>|
|`sendmail_settings`|Allows you to override options for the `:sendmail` delivery method.<ul><li>`:location` - The location of the sendmail executable. Defaults to `/usr/sbin/sendmail`.</li><li>`:arguments` - The command line arguments to be passed to sendmail. Defaults to `-i`.</li></ul>|
|`raise_delivery_errors`|Whether or not errors should be raised if the email fails to be delivered. This only works if the external email server is configured for immediate delivery.|
|`delivery_method`|Defines a delivery method. Possible values are:<ul><li>`:smtp` (default), can be configured by using `config.action_mailer.smtp_settings`.</li><li>`:sendmail`, can be configured by using `config.action_mailer.sendmail_settings`.</li><li>`:file`: save emails to files; can be configured by using `config.action_mailer.file_settings`.</li><li>`:test`: save emails to `ActionMailer::Base.deliveries` array.</li></ul>See [API docs](https://api.rubyonrails.org/classes/ActionMailer/Base.html) for more info.|
diff --git a/guides/source/autoloading_and_reloading_constants.md b/guides/source/autoloading_and_reloading_constants.md
index 8cd2d353de..212cbfaf43 100644
--- a/guides/source/autoloading_and_reloading_constants.md
+++ b/guides/source/autoloading_and_reloading_constants.md
@@ -90,7 +90,7 @@ INFO. Autoload paths are called _root directories_ in Zeitwerk documentation, bu
Within an autoload path, file names must match the constants they define as documented [here](https://github.com/fxn/zeitwerk#file-structure).
-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.
+By default, the autoload paths of an application consist of all the subdirectories of `app` that exist when the application boots ---except for `assets`, `javascripts`, `views`,--- plus the autoload paths of engines it might depend on.
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:
diff --git a/guides/source/working_with_javascript_in_rails.md b/guides/source/working_with_javascript_in_rails.md
index b740e933ba..28af1cd88d 100644
--- a/guides/source/working_with_javascript_in_rails.md
+++ b/guides/source/working_with_javascript_in_rails.md
@@ -536,9 +536,9 @@ the token:
var token = document.getElementsByName('csrf-token')[0].content
```
-You can then submit this token as a X-CSRF-Token in your header for your
-Ajax requst. You do not need to add a CSRF for GET requests, only non-GET
-requests.
+You can then submit this token as a `X-CSRF-Token` header for your
+Ajax request. You do not need to add a CSRF token for GET requests,
+only non-GET ones.
You can read more about about Cross-Site Request Forgery in [Security](https://guides.rubyonrails.org/security.html#cross-site-request-forgery-csrf)
diff --git a/railties/lib/rails/code_statistics.rb b/railties/lib/rails/code_statistics.rb
index 09082282f3..aa5c0d0b5b 100644
--- a/railties/lib/rails/code_statistics.rb
+++ b/railties/lib/rails/code_statistics.rb
@@ -44,7 +44,7 @@ class CodeStatistics #:nodoc:
Dir.foreach(directory) do |file_name|
path = "#{directory}/#{file_name}"
- if File.directory?(path) && (/^\./ !~ file_name)
+ if File.directory?(path) && !(/^\./.match?(file_name))
stats.add(calculate_directory_statistics(path, pattern))
elsif file_name&.match?(pattern)
stats.add_by_file_path(path)
diff --git a/railties/lib/rails/code_statistics_calculator.rb b/railties/lib/rails/code_statistics_calculator.rb
index 85f86bdbd0..8dd415d9d1 100644
--- a/railties/lib/rails/code_statistics_calculator.rb
+++ b/railties/lib/rails/code_statistics_calculator.rb
@@ -58,20 +58,20 @@ class CodeStatisticsCalculator #:nodoc:
@lines += 1
if comment_started
- if patterns[:end_block_comment] && line =~ patterns[:end_block_comment]
+ if patterns[:end_block_comment] && patterns[:end_block_comment].match?(line)
comment_started = false
end
next
else
- if patterns[:begin_block_comment] && line =~ patterns[:begin_block_comment]
+ if patterns[:begin_block_comment] && patterns[:begin_block_comment].match?(line)
comment_started = true
next
end
end
- @classes += 1 if patterns[:class] && line =~ patterns[:class]
- @methods += 1 if patterns[:method] && line =~ patterns[:method]
- if line !~ /^\s*$/ && (patterns[:line_comment].nil? || line !~ patterns[:line_comment])
+ @classes += 1 if patterns[:class] && patterns[:class].match?(line)
+ @methods += 1 if patterns[:method] && patterns[:method].match?(line)
+ if !line.match?(/^\s*$/) && (patterns[:line_comment].nil? || !line.match?(patterns[:line_comment]))
@code_lines += 1
end
end
diff --git a/railties/lib/rails/command/base.rb b/railties/lib/rails/command/base.rb
index a22b198c66..415bab199f 100644
--- a/railties/lib/rails/command/base.rb
+++ b/railties/lib/rails/command/base.rb
@@ -52,7 +52,7 @@ module Rails
def inherited(base) #:nodoc:
super
- if base.name && base.name !~ /Base$/
+ if base.name && !base.name.match?(/Base$/)
Rails::Command.subclasses << base
end
end
diff --git a/railties/lib/rails/command/behavior.rb b/railties/lib/rails/command/behavior.rb
index 7fb2a99e67..90650059f4 100644
--- a/railties/lib/rails/command/behavior.rb
+++ b/railties/lib/rails/command/behavior.rb
@@ -44,7 +44,7 @@ module Rails
require path
return
rescue LoadError => e
- raise unless e.message =~ /#{Regexp.escape(path)}$/
+ raise unless /#{Regexp.escape(path)}$/.match?(e.message)
rescue Exception => e
warn "[WARNING] Could not load #{command_type} #{path.inspect}. Error: #{e.message}.\n#{e.backtrace.join("\n")}"
end
diff --git a/railties/lib/rails/command/environment_argument.rb b/railties/lib/rails/command/environment_argument.rb
index 9945fd1430..df3cc1b2bb 100644
--- a/railties/lib/rails/command/environment_argument.rb
+++ b/railties/lib/rails/command/environment_argument.rb
@@ -28,7 +28,7 @@ module Rails
if available_environments.include? env
env
else
- %w( production development test ).detect { |e| e =~ /^#{env}/ } || env
+ %w( production development test ).detect { |e| /^#{env}/.match?(e) } || env
end
end
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 46f1d38b96..b4c0028b1f 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -362,7 +362,7 @@ module Rails
base.called_from = begin
call_stack = caller_locations.map { |l| l.absolute_path || l.path }
- File.dirname(call_stack.detect { |p| p !~ %r[railties[\w.-]*/lib/rails|rack[\w.-]*/lib/rack] })
+ File.dirname(call_stack.detect { |p| !p.match?(%r[railties[\w.-]*/lib/rails|rack[\w.-]*/lib/rack]) })
end
end
diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index dbfb7337f0..ed0215bda9 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -400,7 +400,7 @@ module Rails
end
def os_supports_listen_out_of_the_box?
- RbConfig::CONFIG["host_os"] =~ /darwin|linux/
+ /darwin|linux/.match?(RbConfig::CONFIG["host_os"])
end
def run_bundle
diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb
index a153923ce3..1d3c947cb0 100644
--- a/railties/lib/rails/generators/base.rb
+++ b/railties/lib/rails/generators/base.rb
@@ -233,7 +233,7 @@ module Rails
# Invoke source_root so the default_source_root is set.
base.source_root
- if base.name && base.name !~ /Base$/
+ if base.name && !base.name.match?(/Base$/)
Rails::Generators.subclasses << base
Rails::Generators.templates_path.each do |path|
diff --git a/railties/lib/rails/generators/generated_attribute.rb b/railties/lib/rails/generators/generated_attribute.rb
index 4e348be9be..377a5dfc65 100644
--- a/railties/lib/rails/generators/generated_attribute.rb
+++ b/railties/lib/rails/generators/generated_attribute.rb
@@ -131,7 +131,7 @@ module Rails
end
def foreign_key?
- !!(name =~ /_id$/)
+ /_id$/.match?(name)
end
def reference?
diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile.tt b/railties/lib/rails/generators/rails/app/templates/Gemfile.tt
index cf5462f7dc..f13dab59b1 100644
--- a/railties/lib/rails/generators/rails/app/templates/Gemfile.tt
+++ b/railties/lib/rails/generators/rails/app/templates/Gemfile.tt
@@ -72,7 +72,7 @@ group :test do
# Easy installation and use of web drivers to run system tests with browsers
gem 'webdrivers'
end
-<%- end -%>
+<%- end -%>
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
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 b8c1f21c0b..437bf84ce3 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
@@ -2,6 +2,7 @@
<html>
<head>
<title><%= camelized %></title>
+ <meta name="viewport" content="width=device-width,initial-scale=1">
<%%= csrf_meta_tags %>
<%%= csp_meta_tag %>
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/backtrace_silencers.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/backtrace_silencers.rb.tt
index 59385cdf37..3c56b21b3c 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/initializers/backtrace_silencers.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/backtrace_silencers.rb.tt
@@ -1,7 +1,7 @@
# Be sure to restart your server when you modify this file.
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
-# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
+# Rails.backtrace_cleaner.add_silencer { |line| /my_noisy_library/.match?(line) }
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
# Rails.backtrace_cleaner.remove_silencers!
diff --git a/railties/lib/rails/tasks/framework.rake b/railties/lib/rails/tasks/framework.rake
index 2886986865..c0f19fcfe5 100644
--- a/railties/lib/rails/tasks/framework.rake
+++ b/railties/lib/rails/tasks/framework.rake
@@ -8,7 +8,7 @@ namespace :app do
task template: :environment do
template = ENV["LOCATION"]
raise "No LOCATION value given. Please set LOCATION either as path to a file or a URL" if template.blank?
- template = File.expand_path(template) if template !~ %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://}
+ template = File.expand_path(template) unless %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://}.match?(template)
require "rails/generators"
require "rails/generators/rails/app/app_generator"
generator = Rails::Generators::AppGenerator.new [Rails.root], {}, { destination_root: Rails.root }
diff --git a/railties/lib/rails/test_unit/runner.rb b/railties/lib/rails/test_unit/runner.rb
index 7b294751fc..b8bce8c772 100644
--- a/railties/lib/rails/test_unit/runner.rb
+++ b/railties/lib/rails/test_unit/runner.rb
@@ -61,7 +61,7 @@ module Rails
private
def extract_filters(argv)
# Extract absolute and relative paths but skip -n /.*/ regexp filters.
- argv.select { |arg| arg =~ %r%^/?\w+/% && !arg.end_with?("/") }.map do |path|
+ argv.select { |arg| %r%^/?\w+/%.match?(arg) && !arg.end_with?("/") }.map do |path|
case
when /(:\d+)+$/.match?(path)
file, *lines = path.split(":")
diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb
index a7dd233f3d..651897d8f3 100644
--- a/railties/test/application/assets_test.rb
+++ b/railties/test/application/assets_test.rb
@@ -311,7 +311,7 @@ module ApplicationTests
manifest = Dir["#{app_path}/public/assets/.sprockets-manifest-*.json"].first
assets = ActiveSupport::JSON.decode(File.read(manifest))
- assert asset_path = assets["assets"].find { |(k, _)| k && k =~ /.png/ }[1]
+ assert asset_path = assets["assets"].find { |(k, _)| /.png/.match?(k) }[1]
# Load app env
app "development"
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index 38dda20bec..b44edbc7d3 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -456,7 +456,7 @@ module ApplicationTests
test "filter_parameters should be able to set via config.filter_parameters" do
add_to_config <<-RUBY
config.filter_parameters += [ :foo, 'bar', lambda { |key, value|
- value = value.reverse if key =~ /baz/
+ value = value.reverse if /baz/.match?(key)
}]
RUBY
@@ -790,7 +790,7 @@ module ApplicationTests
end
get "/"
- assert last_response.body =~ /csrf\-param/
+ assert_match(/csrf\-param/, last_response.body)
end
test "default form builder specified as a string" do
diff --git a/railties/test/application/rake/multi_dbs_test.rb b/railties/test/application/rake/multi_dbs_test.rb
index 2606e64424..c5f8904f4e 100644
--- a/railties/test/application/rake/multi_dbs_test.rb
+++ b/railties/test/application/rake/multi_dbs_test.rb
@@ -349,6 +349,25 @@ module ApplicationTests
rails "db:drop" rescue nil
end
end
+
+ test "db:seed uses primary database connection" do
+ @old_rails_env = ENV["RAILS_ENV"]
+ @old_rack_env = ENV["RACK_ENV"]
+ ENV.delete "RAILS_ENV"
+ ENV.delete "RACK_ENV"
+
+ db_migrate_and_schema_dump_and_load "schema"
+
+ app_file "db/seeds.rb", <<-RUBY
+ print Book.connection.pool.spec.config[:database]
+ RUBY
+
+ output = rails("db:seed")
+ assert_equal output, "db/development.sqlite3"
+ ensure
+ ENV["RAILS_ENV"] = @old_rails_env
+ ENV["RACK_ENV"] = @old_rack_env
+ end
end
end
end
diff --git a/railties/test/application/zeitwerk_integration_test.rb b/railties/test/application/zeitwerk_integration_test.rb
index ff8c06b479..d03fa3d0c6 100644
--- a/railties/test/application/zeitwerk_integration_test.rb
+++ b/railties/test/application/zeitwerk_integration_test.rb
@@ -150,6 +150,35 @@ class ZeitwerkIntegrationTest < ActiveSupport::TestCase
assert_empty deps.autoloaded_constants
end
+ [true, false].each do |add_aps_to_lp|
+ test "require_dependency looks autoload paths up (#{add_aps_to_lp})" do
+ add_to_config "config.add_autoload_paths_to_load_path = #{add_aps_to_lp}"
+ app_file "app/models/user.rb", "class User; end"
+ boot
+
+ assert require_dependency("user")
+ end
+
+ test "require_dependency handles absolute paths correctly (#{add_aps_to_lp})" do
+ add_to_config "config.add_autoload_paths_to_load_path = #{add_aps_to_lp}"
+ app_file "app/models/user.rb", "class User; end"
+ boot
+
+ assert require_dependency("#{app_path}/app/models/user.rb")
+ end
+
+ test "require_dependency supports arguments that repond to to_path (#{add_aps_to_lp})" do
+ add_to_config "config.add_autoload_paths_to_load_path = #{add_aps_to_lp}"
+ app_file "app/models/user.rb", "class User; end"
+ boot
+
+ user = Object.new
+ def user.to_path; "user"; end
+
+ assert require_dependency(user)
+ end
+ end
+
test "eager loading loads the application code" do
$zeitwerk_integration_test_user = false
$zeitwerk_integration_test_post = false
diff --git a/railties/test/commands/credentials_test.rb b/railties/test/commands/credentials_test.rb
index 562e2ec382..3dec6fbe10 100644
--- a/railties/test/commands/credentials_test.rb
+++ b/railties/test/commands/credentials_test.rb
@@ -5,6 +5,7 @@ require "env_helpers"
require "rails/command"
require "rails/commands/credentials/credentials_command"
require "fileutils"
+require "tempfile"
class Rails::Command::CredentialsCommandTest < ActiveSupport::TestCase
include ActiveSupport::Testing::Isolation, EnvHelpers
@@ -110,7 +111,7 @@ class Rails::Command::CredentialsCommandTest < ActiveSupport::TestCase
end
test "edit ask the user to opt in to pretty credentials, user accepts" do
- file = File.open("foo", "w")
+ file = Tempfile.open("credentials_test")
file.write("y")
file.rewind
@@ -127,11 +128,11 @@ class Rails::Command::CredentialsCommandTest < ActiveSupport::TestCase
assert_equal("bin/rails credentials:show\n", `git config --get 'diff.rails_credentials.textconv'`)
end
ensure
- File.delete(file)
+ file.close!
end
test "edit ask the user to opt in to pretty credentials, user refuses" do
- file = File.open("foo", "w")
+ file = Tempfile.open("credentials_test")
file.write("n")
file.rewind
@@ -140,7 +141,7 @@ class Rails::Command::CredentialsCommandTest < ActiveSupport::TestCase
git_attributes = app_path(".gitattributes")
assert_not(File.exist?(git_attributes))
ensure
- File.delete(file)
+ file.close!
end
test "show credentials" do
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index 5b439fdcba..43461036f3 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -678,7 +678,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
def test_inclusion_of_listen_related_configuration_by_default
run_generator
- if RbConfig::CONFIG["host_os"] =~ /darwin|linux/
+ if /darwin|linux/.match?(RbConfig::CONFIG["host_os"])
assert_listen_related_configuration
else
assert_no_listen_related_configuration
@@ -690,7 +690,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
Object.const_set(:RUBY_ENGINE, "MyRuby")
run_generator
- if RbConfig::CONFIG["host_os"] =~ /darwin|linux/
+ if /darwin|linux/.match?(RbConfig::CONFIG["host_os"])
assert_listen_related_configuration
else
assert_no_listen_related_configuration
@@ -708,7 +708,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
def test_evented_file_update_checker_config
run_generator
assert_file "config/environments/development.rb" do |content|
- if RbConfig::CONFIG["host_os"] =~ /darwin|linux/
+ if /darwin|linux/.match?(RbConfig::CONFIG["host_os"])
assert_match(/^\s*config\.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content)
else
assert_match(/^\s*# config\.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content)
diff --git a/railties/test/generators/namespaced_generators_test.rb b/railties/test/generators/namespaced_generators_test.rb
index 4b75a31f17..12ccbe6ff1 100644
--- a/railties/test/generators/namespaced_generators_test.rb
+++ b/railties/test/generators/namespaced_generators_test.rb
@@ -308,7 +308,7 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase
run_generator [ "admin/role" ], behavior: :revoke
# Model
- assert_file "app/models/test_app/admin.rb" # ( should not be remove )
+ assert_file "app/models/test_app/admin.rb" # ( should not be remove )
assert_no_file "app/models/test_app/admin/role.rb"
assert_no_file "test/models/test_app/admin/role_test.rb"
assert_no_file "test/fixtures/test_app/admin/roles.yml"
@@ -375,7 +375,7 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase
run_generator [ "admin/user/special/role" ], behavior: :revoke
# Model
- assert_file "app/models/test_app/admin/user/special.rb" # ( should not be remove )
+ assert_file "app/models/test_app/admin/user/special.rb" # ( should not be remove )
assert_no_file "app/models/test_app/admin/user/special/role.rb"
assert_no_file "test/models/test_app/admin/user/special/role_test.rb"
assert_no_file "test/fixtures/test_app/admin/user/special/roles.yml"
diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb
index 7f05b9d9cf..06836844f0 100644
--- a/railties/test/railties/engine_test.rb
+++ b/railties/test/railties/engine_test.rb
@@ -110,7 +110,7 @@ module RailtiesTest
assert_no_match(/\d+_create_users/, output.join("\n"))
- bukkits_migration_order = output.index(output.detect { |o| /NOTE: Migration \d+_create_sessions\.rb from bukkits has been skipped/ =~ o })
+ bukkits_migration_order = output.index(output.detect { |o| /NOTE: Migration \d+_create_sessions\.rb from bukkits has been skipped/.match?(o) })
assert_not_nil bukkits_migration_order, "Expected migration to be skipped"
end
end