aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionmailer/lib/action_mailer/message_delivery.rb2
-rw-r--r--actionpack/lib/action_controller/railties/helpers.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb2
-rw-r--r--actionview/lib/action_view/template.rb8
-rw-r--r--activemodel/lib/active_model/naming.rb2
-rw-r--r--activemodel/test/cases/attribute_set_test.rb2
-rw-r--r--activerecord/lib/active_record/associations/builder/collection_association.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb17
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb26
-rw-r--r--activerecord/lib/active_record/fixture_set/render_context.rb17
-rw-r--r--activerecord/lib/active_record/fixtures.rb216
-rw-r--r--activerecord/lib/active_record/model_schema.rb10
-rw-r--r--activerecord/lib/active_record/railtie.rb16
-rw-r--r--activerecord/lib/active_record/relation.rb38
-rw-r--r--activerecord/lib/active_record/test_fixtures.rb201
-rw-r--r--activerecord/lib/arel/visitors/mysql.rb48
-rw-r--r--activerecord/lib/arel/visitors/to_sql.rb69
-rw-r--r--activerecord/test/cases/relation_test.rb2
-rw-r--r--activesupport/CHANGELOG.md13
-rw-r--r--activesupport/lib/active_support/cache.rb8
-rw-r--r--activesupport/lib/active_support/configurable.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/module/introspection.rb50
-rw-r--r--activesupport/lib/active_support/core_ext/string/access.rb8
-rw-r--r--activesupport/lib/active_support/dependencies.rb4
-rw-r--r--activesupport/lib/active_support/logger.rb15
-rw-r--r--activesupport/lib/active_support/logger_silence.rb39
-rw-r--r--activesupport/lib/active_support/logger_thread_safe_level.rb29
-rw-r--r--activesupport/test/broadcast_logger_test.rb11
-rw-r--r--activesupport/test/core_ext/module/introspection_test.rb40
-rw-r--r--activesupport/test/core_ext/string_ext_test.rb18
-rw-r--r--activesupport/test/core_ext/time_ext_test.rb38
-rw-r--r--activesupport/test/silence_logger_test.rb35
-rw-r--r--guides/source/3_0_release_notes.md2
-rw-r--r--guides/source/3_1_release_notes.md2
-rw-r--r--guides/source/4_2_release_notes.md2
-rw-r--r--guides/source/active_support_core_extensions.md32
-rw-r--r--guides/source/asset_pipeline.md5
-rw-r--r--guides/source/command_line.md5
-rw-r--r--guides/source/configuring.md5
-rw-r--r--guides/source/generators.md5
-rw-r--r--guides/source/getting_started.md3
-rw-r--r--guides/source/upgrading_ruby_on_rails.md2
-rw-r--r--guides/source/working_with_javascript_in_rails.md4
-rw-r--r--railties/lib/rails/railtie.rb2
44 files changed, 588 insertions, 471 deletions
diff --git a/actionmailer/lib/action_mailer/message_delivery.rb b/actionmailer/lib/action_mailer/message_delivery.rb
index 2377aeb9a5..a57980c322 100644
--- a/actionmailer/lib/action_mailer/message_delivery.rb
+++ b/actionmailer/lib/action_mailer/message_delivery.rb
@@ -29,7 +29,7 @@ module ActionMailer
@mail_message ||= processed_mailer.message
end
- # Unused except for delegator internals (dup, marshaling).
+ # Unused except for delegator internals (dup, marshalling).
def __setobj__(mail_message) #:nodoc:
@mail_message = mail_message
end
diff --git a/actionpack/lib/action_controller/railties/helpers.rb b/actionpack/lib/action_controller/railties/helpers.rb
index fa746fa9e8..75938108d6 100644
--- a/actionpack/lib/action_controller/railties/helpers.rb
+++ b/actionpack/lib/action_controller/railties/helpers.rb
@@ -7,7 +7,7 @@ module ActionController
super
return unless klass.respond_to?(:helpers_path=)
- if namespace = klass.parents.detect { |m| m.respond_to?(:railtie_helpers_paths) }
+ if namespace = klass.module_parents.detect { |m| m.respond_to?(:railtie_helpers_paths) }
paths = namespace.railtie_helpers_paths
else
paths = ActionController::Helpers.helpers_path
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 3b7611acc0..2c811b5e55 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -444,7 +444,7 @@ module ActionDispatch
end
def include_helpers_now(klass, include_path_helpers)
- namespace = klass.parents.detect { |m| m.respond_to?(:railtie_include_helpers) }
+ namespace = klass.module_parents.detect { |m| m.respond_to?(:railtie_include_helpers) }
if namespace && namespace.railtie_namespace.routes != self
namespace.railtie_include_helpers(klass, include_path_helpers)
diff --git a/actionview/lib/action_view/template.rb b/actionview/lib/action_view/template.rb
index 69a64948cc..070d82cf17 100644
--- a/actionview/lib/action_view/template.rb
+++ b/actionview/lib/action_view/template.rb
@@ -235,10 +235,10 @@ module ActionView
end
end
-
- # Exceptions are marshaled when using the parallel test runner with DRb, so we need
- # to ensure that references to the template object can be marshaled as well. This means forgoing
- # the marshalling of the compiler mutex and instantiating that again on unmarshaling.
+
+ # Exceptions are marshalled when using the parallel test runner with DRb, so we need
+ # to ensure that references to the template object can be marshalled as well. This means forgoing
+ # the marshalling of the compiler mutex and instantiating that again on unmarshalling.
def marshal_dump # :nodoc:
[ @source, @identifier, @handler, @compiled, @original_encoding, @locals, @virtual_path, @updated_at, @formats, @variants ]
end
diff --git a/activemodel/lib/active_model/naming.rb b/activemodel/lib/active_model/naming.rb
index 5f3d674c4e..bf23fa3c05 100644
--- a/activemodel/lib/active_model/naming.rb
+++ b/activemodel/lib/active_model/naming.rb
@@ -252,7 +252,7 @@ module ActiveModel
# Person.model_name.plural # => "people"
def model_name
@_model_name ||= begin
- namespace = parents.detect do |n|
+ namespace = module_parents.detect do |n|
n.respond_to?(:use_relative_model_naming?) && n.use_relative_model_naming?
end
ActiveModel::Name.new(self, namespace)
diff --git a/activemodel/test/cases/attribute_set_test.rb b/activemodel/test/cases/attribute_set_test.rb
index b868dba743..62feb9074e 100644
--- a/activemodel/test/cases/attribute_set_test.rb
+++ b/activemodel/test/cases/attribute_set_test.rb
@@ -217,7 +217,7 @@ module ActiveModel
assert_equal({ foo: "1" }, attributes.to_hash)
end
- test "marshaling dump/load legacy materialized attribute hash" do
+ test "marshalling dump/load legacy materialized attribute hash" do
builder = AttributeSet::Builder.new(foo: Type::String.new)
attributes = builder.build_from_database(foo: "1")
diff --git a/activerecord/lib/active_record/associations/builder/collection_association.rb b/activerecord/lib/active_record/associations/builder/collection_association.rb
index 35a72c3850..ff57c40121 100644
--- a/activerecord/lib/active_record/associations/builder/collection_association.rb
+++ b/activerecord/lib/active_record/associations/builder/collection_association.rb
@@ -24,7 +24,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
if block_given?
extension_module_name = "#{model.name.demodulize}#{name.to_s.camelize}AssociationExtension"
extension = Module.new(&Proc.new)
- model.parent.const_set(extension_module_name, extension)
+ model.module_parent.const_set(extension_module_name, extension)
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
index feacdf6931..0059f0b773 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -410,16 +410,6 @@ module ActiveRecord
end
end
- # The default strategy for an UPDATE with joins is to use a subquery. This doesn't work
- # on MySQL (even when aliasing the tables), but MySQL allows using JOIN directly in
- # an UPDATE statement, so in the MySQL adapters we redefine this to do that.
- def join_to_update(update, select, key) # :nodoc:
- subselect = subquery_for(key, select)
-
- update.where key.in(subselect)
- end
- alias join_to_delete join_to_update
-
private
def default_insert_value(column)
Arel.sql("DEFAULT")
@@ -460,13 +450,6 @@ module ActiveRecord
total_sql.join(";\n")
end
- # Returns a subquery for the given key using the join information.
- def subquery_for(key, select)
- subselect = select.clone
- subselect.projections = [key]
- subselect
- end
-
# Returns an ActiveRecord::Result instance.
def select(sql, name = nil, binds = [])
exec_query(sql, name, binds, prepare: false)
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 09242a0f14..d40f38fb77 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -223,18 +223,6 @@ module ActiveRecord
execute "ROLLBACK"
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.
- def join_to_update(update, select, key) # :nodoc:
- if select.limit || select.offset || select.orders.any?
- super
- else
- update.table select.source
- update.wheres = select.constraints
- end
- end
-
def empty_insert_statement_value(primary_key = nil)
"VALUES ()"
end
@@ -733,20 +721,6 @@ module ActiveRecord
[remove_column_for_alter(table_name, :updated_at), remove_column_for_alter(table_name, :created_at)]
end
- # MySQL is too stupid to create a temporary table for use subquery, so we have
- # to give it some prompting in the form of a subsubquery. Ugh!
- def subquery_for(key, select)
- subselect = select.clone
- subselect.projections = [key]
-
- # Materialize subquery by adding distinct
- # to work with MySQL 5.7.6 which sets optimizer_switch='derived_merge=on'
- subselect.distinct unless select.limit || select.offset || select.orders.any?
-
- key_name = quote_column_name(key.name)
- Arel::SelectManager.new(subselect.as("__active_record_temp")).project(Arel.sql(key_name))
- end
-
def supports_rename_index?
mariadb? ? false : version >= "5.7.6"
end
diff --git a/activerecord/lib/active_record/fixture_set/render_context.rb b/activerecord/lib/active_record/fixture_set/render_context.rb
new file mode 100644
index 0000000000..c90b5343dc
--- /dev/null
+++ b/activerecord/lib/active_record/fixture_set/render_context.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+# NOTE: This class has to be defined in compact style in
+# order for rendering context subclassing to work correctly.
+class ActiveRecord::FixtureSet::RenderContext # :nodoc:
+ def self.create_subclass
+ Class.new(ActiveRecord::FixtureSet.context_class) do
+ def get_binding
+ binding()
+ end
+
+ def binary(path)
+ %(!!binary "#{Base64.strict_encode64(File.read(path))}")
+ end
+ end
+ end
+end
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 0d1fdcfb28..e697c30bb6 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -7,6 +7,8 @@ require "set"
require "active_support/dependencies"
require "active_support/core_ext/digest/uuid"
require "active_record/fixture_set/file"
+require "active_record/fixture_set/render_context"
+require "active_record/test_fixtures"
require "active_record/errors"
module ActiveRecord
@@ -851,217 +853,3 @@ module ActiveRecord
end
end
end
-
-module ActiveRecord
- module TestFixtures
- extend ActiveSupport::Concern
-
- def before_setup # :nodoc:
- setup_fixtures
- super
- end
-
- def after_teardown # :nodoc:
- super
- teardown_fixtures
- end
-
- included do
- class_attribute :fixture_path, instance_writer: false
- class_attribute :fixture_table_names, default: []
- class_attribute :fixture_class_names, default: {}
- class_attribute :use_transactional_tests, default: true
- class_attribute :use_instantiated_fixtures, default: false # true, false, or :no_instances
- class_attribute :pre_loaded_fixtures, default: false
- class_attribute :config, default: ActiveRecord::Base
- class_attribute :lock_threads, default: true
- end
-
- module ClassMethods
- # Sets the model class for a fixture when the class name cannot be inferred from the fixture name.
- #
- # Examples:
- #
- # set_fixture_class some_fixture: SomeModel,
- # 'namespaced/fixture' => Another::Model
- #
- # The keys must be the fixture names, that coincide with the short paths to the fixture files.
- def set_fixture_class(class_names = {})
- self.fixture_class_names = fixture_class_names.merge(class_names.stringify_keys)
- end
-
- def fixtures(*fixture_set_names)
- if fixture_set_names.first == :all
- raise StandardError, "No fixture path found. Please set `#{self}.fixture_path`." if fixture_path.blank?
- fixture_set_names = Dir["#{fixture_path}/{**,*}/*.{yml}"].uniq
- fixture_set_names.map! { |f| f[(fixture_path.to_s.size + 1)..-5] }
- else
- fixture_set_names = fixture_set_names.flatten.map(&:to_s)
- end
-
- self.fixture_table_names |= fixture_set_names
- setup_fixture_accessors(fixture_set_names)
- end
-
- def setup_fixture_accessors(fixture_set_names = nil)
- fixture_set_names = Array(fixture_set_names || fixture_table_names)
- methods = Module.new do
- fixture_set_names.each do |fs_name|
- fs_name = fs_name.to_s
- accessor_name = fs_name.tr("/", "_").to_sym
-
- define_method(accessor_name) do |*fixture_names|
- force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
- return_single_record = fixture_names.size == 1
- fixture_names = @loaded_fixtures[fs_name].fixtures.keys if fixture_names.empty?
-
- @fixture_cache[fs_name] ||= {}
-
- instances = fixture_names.map do |f_name|
- f_name = f_name.to_s if f_name.is_a?(Symbol)
- @fixture_cache[fs_name].delete(f_name) if force_reload
-
- if @loaded_fixtures[fs_name][f_name]
- @fixture_cache[fs_name][f_name] ||= @loaded_fixtures[fs_name][f_name].find
- else
- raise StandardError, "No fixture named '#{f_name}' found for fixture set '#{fs_name}'"
- end
- end
-
- return_single_record ? instances.first : instances
- end
- private accessor_name
- end
- end
- include methods
- end
-
- def uses_transaction(*methods)
- @uses_transaction = [] unless defined?(@uses_transaction)
- @uses_transaction.concat methods.map(&:to_s)
- end
-
- def uses_transaction?(method)
- @uses_transaction = [] unless defined?(@uses_transaction)
- @uses_transaction.include?(method.to_s)
- end
- end
-
- def run_in_transaction?
- use_transactional_tests &&
- !self.class.uses_transaction?(method_name)
- end
-
- def setup_fixtures(config = ActiveRecord::Base)
- if pre_loaded_fixtures && !use_transactional_tests
- raise RuntimeError, "pre_loaded_fixtures requires use_transactional_tests"
- end
-
- @fixture_cache = {}
- @fixture_connections = []
- @@already_loaded_fixtures ||= {}
- @connection_subscriber = nil
-
- # Load fixtures once and begin transaction.
- if run_in_transaction?
- if @@already_loaded_fixtures[self.class]
- @loaded_fixtures = @@already_loaded_fixtures[self.class]
- else
- @loaded_fixtures = load_fixtures(config)
- @@already_loaded_fixtures[self.class] = @loaded_fixtures
- end
-
- # Begin transactions for connections already established
- @fixture_connections = enlist_fixture_connections
- @fixture_connections.each do |connection|
- connection.begin_transaction joinable: false
- connection.pool.lock_thread = true if lock_threads
- end
-
- # When connections are established in the future, begin a transaction too
- @connection_subscriber = ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload|
- spec_name = payload[:spec_name] if payload.key?(:spec_name)
-
- if spec_name
- begin
- connection = ActiveRecord::Base.connection_handler.retrieve_connection(spec_name)
- rescue ConnectionNotEstablished
- connection = nil
- end
-
- if connection && !@fixture_connections.include?(connection)
- connection.begin_transaction joinable: false
- connection.pool.lock_thread = true if lock_threads
- @fixture_connections << connection
- end
- end
- end
-
- # Load fixtures for every test.
- else
- ActiveRecord::FixtureSet.reset_cache
- @@already_loaded_fixtures[self.class] = nil
- @loaded_fixtures = load_fixtures(config)
- end
-
- # Instantiate fixtures for every test if requested.
- instantiate_fixtures if use_instantiated_fixtures
- end
-
- def teardown_fixtures
- # Rollback changes if a transaction is active.
- if run_in_transaction?
- ActiveSupport::Notifications.unsubscribe(@connection_subscriber) if @connection_subscriber
- @fixture_connections.each do |connection|
- connection.rollback_transaction if connection.transaction_open?
- connection.pool.lock_thread = false
- end
- @fixture_connections.clear
- else
- ActiveRecord::FixtureSet.reset_cache
- end
-
- ActiveRecord::Base.clear_active_connections!
- end
-
- def enlist_fixture_connections
- ActiveRecord::Base.connection_handler.connection_pool_list.map(&:connection)
- end
-
- private
- def load_fixtures(config)
- fixtures = ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names, config)
- Hash[fixtures.map { |f| [f.name, f] }]
- end
-
- def instantiate_fixtures
- if pre_loaded_fixtures
- raise RuntimeError, "Load fixtures before instantiating them." if ActiveRecord::FixtureSet.all_loaded_fixtures.empty?
- ActiveRecord::FixtureSet.instantiate_all_loaded_fixtures(self, load_instances?)
- else
- raise RuntimeError, "Load fixtures before instantiating them." if @loaded_fixtures.nil?
- @loaded_fixtures.each_value do |fixture_set|
- ActiveRecord::FixtureSet.instantiate_fixtures(self, fixture_set, load_instances?)
- end
- end
- end
-
- def load_instances?
- use_instantiated_fixtures != :no_instances
- end
- end
-end
-
-class ActiveRecord::FixtureSet::RenderContext # :nodoc:
- def self.create_subclass
- Class.new ActiveRecord::FixtureSet.context_class do
- def get_binding
- binding()
- end
-
- def binary(path)
- %(!!binary "#{Base64.strict_encode64(File.read(path))}")
- end
- end
- end
-end
diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb
index 9b985e049b..5a4a1fb969 100644
--- a/activerecord/lib/active_record/model_schema.rb
+++ b/activerecord/lib/active_record/model_schema.rb
@@ -218,11 +218,11 @@ module ActiveRecord
end
def full_table_name_prefix #:nodoc:
- (parents.detect { |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
+ (module_parents.detect { |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
end
def full_table_name_suffix #:nodoc:
- (parents.detect { |p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix
+ (module_parents.detect { |p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix
end
# The array of names of environments where destructive actions should be prohibited. By default,
@@ -503,9 +503,9 @@ module ActiveRecord
def compute_table_name
if base_class?
# Nested classes are prefixed with singular parent table name.
- if parent < Base && !parent.abstract_class?
- contained = parent.table_name
- contained = contained.singularize if parent.pluralize_table_names
+ if module_parent < Base && !module_parent.abstract_class?
+ contained = module_parent.table_name
+ contained = contained.singularize if module_parent.pluralize_table_names
contained += "_"
end
diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb
index 81ad9ef3a2..538659d6bd 100644
--- a/activerecord/lib/active_record/railtie.rb
+++ b/activerecord/lib/active_record/railtie.rb
@@ -168,21 +168,7 @@ end_error
initializer "active_record.initialize_database" do
ActiveSupport.on_load(:active_record) do
self.configurations = Rails.application.config.database_configuration
-
- begin
- establish_connection
- rescue ActiveRecord::NoDatabaseError
- warn <<-end_warning
-Oops - You have a database configured, but it doesn't exist yet!
-
-Here's how to get started:
-
- 1. Configure your database in config/database.yml.
- 2. Run `rails db:create` to create the database.
- 3. Run `rails db:setup` to load your database schema.
-end_warning
- raise
- end
+ establish_connection
end
end
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index d8cff30b88..d5b6082d13 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -348,7 +348,12 @@ module ActiveRecord
end
stmt = Arel::UpdateManager.new
- stmt.table(table)
+ stmt.table(arel.join_sources.empty? ? table : arel.source)
+ stmt.key = arel_attribute(primary_key)
+ stmt.take(arel.limit)
+ stmt.offset(arel.offset)
+ stmt.order(*arel.orders)
+ stmt.wheres = arel.constraints
if updates.is_a?(Hash)
stmt.set _substitute_values(updates)
@@ -356,16 +361,6 @@ module ActiveRecord
stmt.set Arel.sql(klass.sanitize_sql_for_assignment(updates, table.name))
end
- if has_join_values?
- @klass.connection.join_to_update(stmt, arel, arel_attribute(primary_key))
- else
- stmt.key = arel_attribute(primary_key)
- stmt.take(arel.limit)
- stmt.offset(arel.offset)
- stmt.order(*arel.orders)
- stmt.wheres = arel.constraints
- end
-
@klass.connection.update stmt, "#{@klass} Update All"
end
@@ -483,17 +478,12 @@ module ActiveRecord
end
stmt = Arel::DeleteManager.new
- stmt.from(table)
-
- if has_join_values?
- @klass.connection.join_to_delete(stmt, arel, arel_attribute(primary_key))
- else
- stmt.key = arel_attribute(primary_key)
- stmt.take(arel.limit)
- stmt.offset(arel.offset)
- stmt.order(*arel.orders)
- stmt.wheres = arel.constraints
- end
+ stmt.from(arel.join_sources.empty? ? table : arel.source)
+ stmt.key = arel_attribute(primary_key)
+ stmt.take(arel.limit)
+ stmt.offset(arel.offset)
+ stmt.order(*arel.orders)
+ stmt.wheres = arel.constraints
affected = @klass.connection.delete(stmt, "#{@klass} Destroy")
@@ -648,10 +638,6 @@ module ActiveRecord
end
end
- def has_join_values?
- joins_values.any? || left_outer_joins_values.any?
- end
-
def exec_queries(&block)
skip_query_cache_if_necessary do
@records =
diff --git a/activerecord/lib/active_record/test_fixtures.rb b/activerecord/lib/active_record/test_fixtures.rb
new file mode 100644
index 0000000000..7b7b3f7112
--- /dev/null
+++ b/activerecord/lib/active_record/test_fixtures.rb
@@ -0,0 +1,201 @@
+# frozen_string_literal: true
+
+module ActiveRecord
+ module TestFixtures
+ extend ActiveSupport::Concern
+
+ def before_setup # :nodoc:
+ setup_fixtures
+ super
+ end
+
+ def after_teardown # :nodoc:
+ super
+ teardown_fixtures
+ end
+
+ included do
+ class_attribute :fixture_path, instance_writer: false
+ class_attribute :fixture_table_names, default: []
+ class_attribute :fixture_class_names, default: {}
+ class_attribute :use_transactional_tests, default: true
+ class_attribute :use_instantiated_fixtures, default: false # true, false, or :no_instances
+ class_attribute :pre_loaded_fixtures, default: false
+ class_attribute :config, default: ActiveRecord::Base
+ class_attribute :lock_threads, default: true
+ end
+
+ module ClassMethods
+ # Sets the model class for a fixture when the class name cannot be inferred from the fixture name.
+ #
+ # Examples:
+ #
+ # set_fixture_class some_fixture: SomeModel,
+ # 'namespaced/fixture' => Another::Model
+ #
+ # The keys must be the fixture names, that coincide with the short paths to the fixture files.
+ def set_fixture_class(class_names = {})
+ self.fixture_class_names = fixture_class_names.merge(class_names.stringify_keys)
+ end
+
+ def fixtures(*fixture_set_names)
+ if fixture_set_names.first == :all
+ raise StandardError, "No fixture path found. Please set `#{self}.fixture_path`." if fixture_path.blank?
+ fixture_set_names = Dir["#{fixture_path}/{**,*}/*.{yml}"].uniq
+ fixture_set_names.map! { |f| f[(fixture_path.to_s.size + 1)..-5] }
+ else
+ fixture_set_names = fixture_set_names.flatten.map(&:to_s)
+ end
+
+ self.fixture_table_names |= fixture_set_names
+ setup_fixture_accessors(fixture_set_names)
+ end
+
+ def setup_fixture_accessors(fixture_set_names = nil)
+ fixture_set_names = Array(fixture_set_names || fixture_table_names)
+ methods = Module.new do
+ fixture_set_names.each do |fs_name|
+ fs_name = fs_name.to_s
+ accessor_name = fs_name.tr("/", "_").to_sym
+
+ define_method(accessor_name) do |*fixture_names|
+ force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
+ return_single_record = fixture_names.size == 1
+ fixture_names = @loaded_fixtures[fs_name].fixtures.keys if fixture_names.empty?
+
+ @fixture_cache[fs_name] ||= {}
+
+ instances = fixture_names.map do |f_name|
+ f_name = f_name.to_s if f_name.is_a?(Symbol)
+ @fixture_cache[fs_name].delete(f_name) if force_reload
+
+ if @loaded_fixtures[fs_name][f_name]
+ @fixture_cache[fs_name][f_name] ||= @loaded_fixtures[fs_name][f_name].find
+ else
+ raise StandardError, "No fixture named '#{f_name}' found for fixture set '#{fs_name}'"
+ end
+ end
+
+ return_single_record ? instances.first : instances
+ end
+ private accessor_name
+ end
+ end
+ include methods
+ end
+
+ def uses_transaction(*methods)
+ @uses_transaction = [] unless defined?(@uses_transaction)
+ @uses_transaction.concat methods.map(&:to_s)
+ end
+
+ def uses_transaction?(method)
+ @uses_transaction = [] unless defined?(@uses_transaction)
+ @uses_transaction.include?(method.to_s)
+ end
+ end
+
+ def run_in_transaction?
+ use_transactional_tests &&
+ !self.class.uses_transaction?(method_name)
+ end
+
+ def setup_fixtures(config = ActiveRecord::Base)
+ if pre_loaded_fixtures && !use_transactional_tests
+ raise RuntimeError, "pre_loaded_fixtures requires use_transactional_tests"
+ end
+
+ @fixture_cache = {}
+ @fixture_connections = []
+ @@already_loaded_fixtures ||= {}
+ @connection_subscriber = nil
+
+ # Load fixtures once and begin transaction.
+ if run_in_transaction?
+ if @@already_loaded_fixtures[self.class]
+ @loaded_fixtures = @@already_loaded_fixtures[self.class]
+ else
+ @loaded_fixtures = load_fixtures(config)
+ @@already_loaded_fixtures[self.class] = @loaded_fixtures
+ end
+
+ # Begin transactions for connections already established
+ @fixture_connections = enlist_fixture_connections
+ @fixture_connections.each do |connection|
+ connection.begin_transaction joinable: false
+ connection.pool.lock_thread = true if lock_threads
+ end
+
+ # When connections are established in the future, begin a transaction too
+ @connection_subscriber = ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload|
+ spec_name = payload[:spec_name] if payload.key?(:spec_name)
+
+ if spec_name
+ begin
+ connection = ActiveRecord::Base.connection_handler.retrieve_connection(spec_name)
+ rescue ConnectionNotEstablished
+ connection = nil
+ end
+
+ if connection && !@fixture_connections.include?(connection)
+ connection.begin_transaction joinable: false
+ connection.pool.lock_thread = true if lock_threads
+ @fixture_connections << connection
+ end
+ end
+ end
+
+ # Load fixtures for every test.
+ else
+ ActiveRecord::FixtureSet.reset_cache
+ @@already_loaded_fixtures[self.class] = nil
+ @loaded_fixtures = load_fixtures(config)
+ end
+
+ # Instantiate fixtures for every test if requested.
+ instantiate_fixtures if use_instantiated_fixtures
+ end
+
+ def teardown_fixtures
+ # Rollback changes if a transaction is active.
+ if run_in_transaction?
+ ActiveSupport::Notifications.unsubscribe(@connection_subscriber) if @connection_subscriber
+ @fixture_connections.each do |connection|
+ connection.rollback_transaction if connection.transaction_open?
+ connection.pool.lock_thread = false
+ end
+ @fixture_connections.clear
+ else
+ ActiveRecord::FixtureSet.reset_cache
+ end
+
+ ActiveRecord::Base.clear_active_connections!
+ end
+
+ def enlist_fixture_connections
+ ActiveRecord::Base.connection_handler.connection_pool_list.map(&:connection)
+ end
+
+ private
+ def load_fixtures(config)
+ fixtures = ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names, config)
+ Hash[fixtures.map { |f| [f.name, f] }]
+ end
+
+ def instantiate_fixtures
+ if pre_loaded_fixtures
+ raise RuntimeError, "Load fixtures before instantiating them." if ActiveRecord::FixtureSet.all_loaded_fixtures.empty?
+ ActiveRecord::FixtureSet.instantiate_all_loaded_fixtures(self, load_instances?)
+ else
+ raise RuntimeError, "Load fixtures before instantiating them." if @loaded_fixtures.nil?
+ @loaded_fixtures.each_value do |fixture_set|
+ ActiveRecord::FixtureSet.instantiate_fixtures(self, fixture_set, load_instances?)
+ end
+ end
+ end
+
+ def load_instances?
+ use_instantiated_fixtures != :no_instances
+ end
+ end
+end
diff --git a/activerecord/lib/arel/visitors/mysql.rb b/activerecord/lib/arel/visitors/mysql.rb
index eb8a449079..081452caeb 100644
--- a/activerecord/lib/arel/visitors/mysql.rb
+++ b/activerecord/lib/arel/visitors/mysql.rb
@@ -65,12 +65,42 @@ module Arel # :nodoc: all
collector
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.
+ def prepare_update_statement(o)
+ if has_join_sources?(o)
+ if has_limit_or_offset_or_orders?(o)
+ super
+ else
+ o
+ end
+ elsif o.offset
+ super
+ else
+ o
+ end
+ end
+
+ def prepare_delete_statement(o)
+ if has_join_sources?(o) || o.offset
+ super
+ else
+ o
+ end
+ end
+
+ # MySQL is too stupid to create a temporary table for use subquery, so we have
+ # to give it some prompting in the form of a subsubquery.
def build_subselect(key, o)
subselect = super
# Materialize subquery by adding distinct
# to work with MySQL 5.7.6 which sets optimizer_switch='derived_merge=on'
- subselect.distinct unless subselect.limit || subselect.offset || subselect.orders.any?
+ unless has_limit_or_offset_or_orders?(subselect)
+ core = subselect.cores.last
+ core.set_quantifier = Arel::Nodes::Distinct.new
+ end
Nodes::SelectStatement.new.tap do |stmt|
core = stmt.cores.last
@@ -78,22 +108,6 @@ module Arel # :nodoc: all
core.projections = [Arel.sql(quote_column_name(key.name))]
end
end
-
- def collect_where_for(o, collector)
- return super if o.offset
-
- unless o.wheres.empty?
- collector << " WHERE "
- collector = inject_join o.wheres, collector, " AND "
- end
-
- unless o.orders.empty?
- collector << " ORDER BY "
- collector = inject_join o.orders, collector, ", "
- end
-
- maybe_visit o.limit, collector
- end
end
end
end
diff --git a/activerecord/lib/arel/visitors/to_sql.rb b/activerecord/lib/arel/visitors/to_sql.rb
index 0172204fc8..7c0f6c2e97 100644
--- a/activerecord/lib/arel/visitors/to_sql.rb
+++ b/activerecord/lib/arel/visitors/to_sql.rb
@@ -74,26 +74,17 @@ module Arel # :nodoc: all
private
def visit_Arel_Nodes_DeleteStatement(o, collector)
+ o = prepare_delete_statement(o)
+
collector << "DELETE FROM "
collector = visit o.relation, collector
collect_where_for(o, collector)
end
- # FIXME: we should probably have a 2-pass visitor for this
- def build_subselect(key, o)
- stmt = Nodes::SelectStatement.new
- core = stmt.cores.first
- core.froms = o.relation
- core.wheres = o.wheres
- core.projections = [key]
- stmt.limit = o.limit
- stmt.offset = o.offset
- stmt.orders = o.orders
- stmt
- end
-
def visit_Arel_Nodes_UpdateStatement(o, collector)
+ o = prepare_update_statement(o)
+
collector << "UPDATE "
collector = visit o.relation, collector
unless o.values.empty?
@@ -800,19 +791,57 @@ module Arel # :nodoc: all
}
end
- def collect_where_for(o, collector)
- if o.orders.empty? && o.limit.nil? && o.offset.nil?
- wheres = o.wheres
+ def has_join_sources?(o)
+ o.relation.is_a?(Nodes::JoinSource) && !o.relation.right.empty?
+ end
+
+ def has_limit_or_offset_or_orders?(o)
+ o.limit || o.offset || !o.orders.empty?
+ end
+
+ # The default strategy for an UPDATE with joins is to use a subquery. This doesn't work
+ # on MySQL (even when aliasing the tables), but MySQL allows using JOIN directly in
+ # an UPDATE statement, so in the MySQL visitor we redefine this to do that.
+ def prepare_update_statement(o)
+ if o.key && (has_limit_or_offset_or_orders?(o) || has_join_sources?(o))
+ stmt = o.clone
+ stmt.limit = nil
+ stmt.offset = nil
+ stmt.orders = []
+ stmt.wheres = [Nodes::In.new(o.key, [build_subselect(o.key, o)])]
+ stmt.relation = o.relation.left if has_join_sources?(o)
+ stmt
else
- wheres = [Nodes::In.new(o.key, [build_subselect(o.key, o)])]
+ o
end
+ end
+ alias :prepare_delete_statement :prepare_update_statement
+
+ # FIXME: we should probably have a 2-pass visitor for this
+ def build_subselect(key, o)
+ stmt = Nodes::SelectStatement.new
+ core = stmt.cores.first
+ core.froms = o.relation
+ core.wheres = o.wheres
+ core.projections = [key]
+ stmt.limit = o.limit
+ stmt.offset = o.offset
+ stmt.orders = o.orders
+ stmt
+ end
- unless wheres.empty?
+ def collect_where_for(o, collector)
+ unless o.wheres.empty?
collector << " WHERE "
- collector = inject_join wheres, collector, " AND "
+ collector = inject_join o.wheres, collector, " AND "
end
- collector
+ unless o.orders.empty?
+ collector << " ORDER BY "
+ collector = inject_join o.orders, collector, ", "
+ end
+
+ maybe_visit o.limit, collector
end
def infix_value(o, collector, value)
diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb
index fbeb617b29..68161f6a84 100644
--- a/activerecord/test/cases/relation_test.rb
+++ b/activerecord/test/cases/relation_test.rb
@@ -232,7 +232,7 @@ module ActiveRecord
assert_equal 3, nb_inner_join, "Wrong amount of INNER JOIN in query"
# using `\W` as the column separator
- assert queries.any? { |sql| %r[INNER\s+JOIN\s+#{Author.quoted_table_name}\s+\Wauthors_categorizations\W]i.match?(sql) }, "Should be aliasing the child INNER JOINs in query"
+ assert queries.any? { |sql| %r[INNER\s+JOIN\s+#{Regexp.escape(Author.quoted_table_name)}\s+\Wauthors_categorizations\W]i.match?(sql) }, "Should be aliasing the child INNER JOINs in query"
end
def test_relation_with_merged_joins_aliased_works
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 3a348a26bf..586ed28693 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,3 +1,16 @@
+* Rename `Module#parent`, `Module#parents`, and `Module#parent_name` to
+ `module_parent`, `module_parents`, and `module_parent_name`.
+
+ *Gannon McGibbon*
+
+* Deprecate the use of `LoggerSilence` in favor of `ActiveSupport::LoggerSilence`
+
+ *Edouard Chin*
+
+* Deprecate using negative limits in `String#first` and `String#last`.
+
+ *Gannon McGibbon*, *Eric Turner*
+
* Fix bug where `#without` for `ActiveSupport::HashWithIndifferentAccess` would fail
with symbol arguments
diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb
index a5d0c52b13..222ef2b515 100644
--- a/activesupport/lib/active_support/cache.rb
+++ b/activesupport/lib/active_support/cache.rb
@@ -596,9 +596,13 @@ module ActiveSupport
# Merges the default options with ones specific to a method call.
def merged_options(call_options)
if call_options
- options.merge(call_options)
+ if options.empty?
+ call_options
+ else
+ options.merge(call_options)
+ end
else
- options.dup
+ options
end
end
diff --git a/activesupport/lib/active_support/configurable.rb b/activesupport/lib/active_support/configurable.rb
index 2610114d8f..6159e45230 100644
--- a/activesupport/lib/active_support/configurable.rb
+++ b/activesupport/lib/active_support/configurable.rb
@@ -105,7 +105,7 @@ module ActiveSupport
# end
#
# User.hair_colors # => [:brown, :black, :blonde, :red]
- def config_accessor(*names)
+ def config_accessor(*names) #:doc:
options = names.extract_options!
names.each do |name|
diff --git a/activesupport/lib/active_support/core_ext/module/introspection.rb b/activesupport/lib/active_support/core_ext/module/introspection.rb
index c5bb598bd1..9b6df40596 100644
--- a/activesupport/lib/active_support/core_ext/module/introspection.rb
+++ b/activesupport/lib/active_support/core_ext/module/introspection.rb
@@ -5,8 +5,8 @@ require "active_support/inflector"
class Module
# Returns the name of the module containing this one.
#
- # M::N.parent_name # => "M"
- def parent_name
+ # M::N.module_parent_name # => "M"
+ def module_parent_name
if defined?(@parent_name)
@parent_name
else
@@ -16,6 +16,14 @@ class Module
end
end
+ def parent_name
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ `Module#parent_name` has been renamed to `module_parent_name`.
+ `parent_name` is deprecated and will be removed in Rails 6.1.
+ MSG
+ module_parent_name
+ end
+
# Returns the module which contains this one according to its name.
#
# module M
@@ -24,15 +32,23 @@ class Module
# end
# X = M::N
#
- # M::N.parent # => M
- # X.parent # => M
+ # M::N.module_parent # => M
+ # X.module_parent # => M
#
# The parent of top-level and anonymous modules is Object.
#
- # M.parent # => Object
- # Module.new.parent # => Object
+ # M.module_parent # => Object
+ # Module.new.module_parent # => Object
+ def module_parent
+ module_parent_name ? ActiveSupport::Inflector.constantize(module_parent_name) : Object
+ end
+
def parent
- parent_name ? ActiveSupport::Inflector.constantize(parent_name) : Object
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ `Module#parent` has been renamed to `module_parent`.
+ `parent` is deprecated and will be removed in Rails 6.1.
+ MSG
+ module_parent
end
# Returns all the parents of this module according to its name, ordered from
@@ -44,13 +60,13 @@ class Module
# end
# X = M::N
#
- # M.parents # => [Object]
- # M::N.parents # => [M, Object]
- # X.parents # => [M, Object]
- def parents
+ # M.module_parents # => [Object]
+ # M::N.module_parents # => [M, Object]
+ # X.module_parents # => [M, Object]
+ def module_parents
parents = []
- if parent_name
- parts = parent_name.split("::")
+ if module_parent_name
+ parts = module_parent_name.split("::")
until parts.empty?
parents << ActiveSupport::Inflector.constantize(parts * "::")
parts.pop
@@ -59,4 +75,12 @@ class Module
parents << Object unless parents.include? Object
parents
end
+
+ def parents
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ `Module#parents` has been renamed to `module_parents`.
+ `parents` is deprecated and will be removed in Rails 6.1.
+ MSG
+ module_parents
+ 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 58591bbaaf..4ca24028b0 100644
--- a/activesupport/lib/active_support/core_ext/string/access.rb
+++ b/activesupport/lib/active_support/core_ext/string/access.rb
@@ -75,6 +75,10 @@ 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
@@ -95,6 +99,10 @@ 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
diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb
index 063d8d1587..66e0bea00e 100644
--- a/activesupport/lib/active_support/dependencies.rb
+++ b/activesupport/lib/active_support/dependencies.rb
@@ -521,8 +521,8 @@ module ActiveSupport #:nodoc:
end
elsif mod = autoload_module!(from_mod, const_name, qualified_name, path_suffix)
return mod
- elsif (parent = from_mod.parent) && parent != from_mod &&
- ! from_mod.parents.any? { |p| p.const_defined?(const_name, false) }
+ elsif (parent = from_mod.module_parent) && parent != from_mod &&
+ ! from_mod.module_parents.any? { |p| p.const_defined?(const_name, false) }
# If our parents do not have a constant named +const_name+ then we are free
# to attempt to load upwards. If they do have such a constant, then this
# const_missing must be due to from_mod::const_name, which should not
diff --git a/activesupport/lib/active_support/logger.rb b/activesupport/lib/active_support/logger.rb
index 8152a182b4..b8555c887b 100644
--- a/activesupport/lib/active_support/logger.rb
+++ b/activesupport/lib/active_support/logger.rb
@@ -6,7 +6,6 @@ require "logger"
module ActiveSupport
class Logger < ::Logger
- include ActiveSupport::LoggerThreadSafeLevel
include LoggerSilence
# Returns true if the logger destination matches one of the sources
@@ -81,20 +80,6 @@ module ActiveSupport
def initialize(*args)
super
@formatter = SimpleFormatter.new
- after_initialize if respond_to? :after_initialize
- end
-
- def add(severity, message = nil, progname = nil, &block)
- return true if @logdev.nil? || (severity || UNKNOWN) < level
- super
- end
-
- Logger::Severity.constants.each do |severity|
- class_eval(<<-EOT, __FILE__, __LINE__ + 1)
- def #{severity.downcase}? # def debug?
- Logger::#{severity} >= level # DEBUG >= level
- end # end
- EOT
end
# Simple formatter which only displays the message.
diff --git a/activesupport/lib/active_support/logger_silence.rb b/activesupport/lib/active_support/logger_silence.rb
index 4344ca0429..b2444c1e34 100644
--- a/activesupport/lib/active_support/logger_silence.rb
+++ b/activesupport/lib/active_support/logger_silence.rb
@@ -2,27 +2,44 @@
require "active_support/concern"
require "active_support/core_ext/module/attribute_accessors"
+require "active_support/logger_thread_safe_level"
module LoggerSilence
extend ActiveSupport::Concern
included do
- cattr_accessor :silencer, default: true
+ ActiveSupport::Deprecation.warn(
+ "Including LoggerSilence is deprecated and will be removed in Rails 6.1. " \
+ "Please use `ActiveSupport::LoggerSilence` instead"
+ )
+
+ include ActiveSupport::LoggerSilence
end
+end
+
+module ActiveSupport
+ module LoggerSilence
+ extend ActiveSupport::Concern
+
+ included do
+ cattr_accessor :silencer, default: true
+ include ActiveSupport::LoggerThreadSafeLevel
+ end
- # Silences the logger for the duration of the block.
- def silence(temporary_level = Logger::ERROR)
- if silencer
- begin
- old_local_level = local_level
- self.local_level = temporary_level
+ # Silences the logger for the duration of the block.
+ def silence(temporary_level = Logger::ERROR)
+ if silencer
+ begin
+ old_local_level = local_level
+ self.local_level = temporary_level
+ yield self
+ ensure
+ self.local_level = old_local_level
+ end
+ else
yield self
- ensure
- self.local_level = old_local_level
end
- else
- yield self
end
end
end
diff --git a/activesupport/lib/active_support/logger_thread_safe_level.rb b/activesupport/lib/active_support/logger_thread_safe_level.rb
index 22ab4cc28c..f16c90cfc6 100644
--- a/activesupport/lib/active_support/logger_thread_safe_level.rb
+++ b/activesupport/lib/active_support/logger_thread_safe_level.rb
@@ -1,14 +1,30 @@
# frozen_string_literal: true
require "active_support/concern"
+require "active_support/core_ext/module/attribute_accessors"
require "concurrent"
module ActiveSupport
module LoggerThreadSafeLevel # :nodoc:
extend ActiveSupport::Concern
+ included do
+ cattr_accessor :local_levels, default: Concurrent::Map.new(initial_capacity: 2), instance_accessor: false
+ end
+
+ Logger::Severity.constants.each do |severity|
+ class_eval(<<-EOT, __FILE__, __LINE__ + 1)
+ def #{severity.downcase}? # def debug?
+ Logger::#{severity} >= level # DEBUG >= level
+ end # end
+ EOT
+ end
+
def after_initialize
- @local_levels = Concurrent::Map.new(initial_capacity: 2)
+ ActiveSupport::Deprecation.warn(
+ "Logger don't need to call #after_initialize directly anymore. It will be deprecated without replacement in " \
+ "Rails 6.1."
+ )
end
def local_log_id
@@ -16,19 +32,24 @@ module ActiveSupport
end
def local_level
- @local_levels[local_log_id]
+ self.class.local_levels[local_log_id]
end
def local_level=(level)
if level
- @local_levels[local_log_id] = level
+ self.class.local_levels[local_log_id] = level
else
- @local_levels.delete(local_log_id)
+ self.class.local_levels.delete(local_log_id)
end
end
def level
local_level || super
end
+
+ def add(severity, message = nil, progname = nil, &block) # :nodoc:
+ return true if @logdev.nil? || (severity || UNKNOWN) < level
+ super
+ end
end
end
diff --git a/activesupport/test/broadcast_logger_test.rb b/activesupport/test/broadcast_logger_test.rb
index 181113e70a..7dfa8a62bd 100644
--- a/activesupport/test/broadcast_logger_test.rb
+++ b/activesupport/test/broadcast_logger_test.rb
@@ -114,7 +114,17 @@ module ActiveSupport
assert_equal [[::Logger::FATAL, "seen", nil]], log2.adds
end
+ test "Including top constant LoggerSilence is deprecated" do
+ assert_deprecated("Please use `ActiveSupport::LoggerSilence`") do
+ Class.new(CustomLogger) do
+ include ::LoggerSilence
+ end
+ end
+ end
+
class CustomLogger
+ include ActiveSupport::LoggerSilence
+
attr_reader :adds, :closed, :chevrons
attr_accessor :level, :progname, :formatter, :local_level
@@ -166,7 +176,6 @@ module ActiveSupport
end
class FakeLogger < CustomLogger
- include LoggerSilence
end
end
end
diff --git a/activesupport/test/core_ext/module/introspection_test.rb b/activesupport/test/core_ext/module/introspection_test.rb
index 76d3012239..d8409d5e44 100644
--- a/activesupport/test/core_ext/module/introspection_test.rb
+++ b/activesupport/test/core_ext/module/introspection_test.rb
@@ -15,25 +15,43 @@ module ParentA
end
class IntrospectionTest < ActiveSupport::TestCase
+ def test_module_parent_name
+ assert_equal "ParentA", ParentA::B.module_parent_name
+ assert_equal "ParentA::B", ParentA::B::C.module_parent_name
+ assert_nil ParentA.module_parent_name
+ end
+
+ def test_module_parent_name_when_frozen
+ assert_equal "ParentA", ParentA::FrozenB.module_parent_name
+ assert_equal "ParentA::B", ParentA::B::FrozenC.module_parent_name
+ end
+
def test_parent_name
- assert_equal "ParentA", ParentA::B.parent_name
- assert_equal "ParentA::B", ParentA::B::C.parent_name
- assert_nil ParentA.parent_name
+ assert_deprecated do
+ assert_equal "ParentA", ParentA::B.parent_name
+ end
end
- def test_parent_name_when_frozen
- assert_equal "ParentA", ParentA::FrozenB.parent_name
- assert_equal "ParentA::B", ParentA::B::FrozenC.parent_name
+ def test_module_parent
+ assert_equal ParentA::B, ParentA::B::C.module_parent
+ assert_equal ParentA, ParentA::B.module_parent
+ assert_equal Object, ParentA.module_parent
end
def test_parent
- assert_equal ParentA::B, ParentA::B::C.parent
- assert_equal ParentA, ParentA::B.parent
- assert_equal Object, ParentA.parent
+ assert_deprecated do
+ assert_equal ParentA, ParentA::B.parent
+ end
+ end
+
+ def test_module_parents
+ assert_equal [ParentA::B, ParentA, Object], ParentA::B::C.module_parents
+ assert_equal [ParentA, Object], ParentA::B.module_parents
end
def test_parents
- assert_equal [ParentA::B, ParentA, Object], ParentA::B::C.parents
- assert_equal [ParentA, Object], ParentA::B.parents
+ assert_deprecated do
+ assert_equal [ParentA, Object], ParentA::B.parents
+ end
end
end
diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb
index aa120a6f9a..2468fe3603 100644
--- a/activesupport/test/core_ext/string_ext_test.rb
+++ b/activesupport/test/core_ext/string_ext_test.rb
@@ -469,6 +469,15 @@ 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)
+ end
+ end
+
test "#last returns the last character" do
assert_equal "o", "hello".last
assert_equal "x", "x".last
@@ -487,6 +496,15 @@ 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)
+ end
+ end
+
test "access returns a real string" do
hash = {}
hash["h"] = true
diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb
index e1cb22fda8..7078f3506d 100644
--- a/activesupport/test/core_ext/time_ext_test.rb
+++ b/activesupport/test/core_ext/time_ext_test.rb
@@ -950,39 +950,39 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
end
class TimeExtMarshalingTest < ActiveSupport::TestCase
- def test_marshaling_with_utc_instance
+ def test_marshalling_with_utc_instance
t = Time.utc(2000)
- unmarshaled = Marshal.load(Marshal.dump(t))
- assert_equal "UTC", unmarshaled.zone
- assert_equal t, unmarshaled
+ unmarshalled = Marshal.load(Marshal.dump(t))
+ assert_equal "UTC", unmarshalled.zone
+ assert_equal t, unmarshalled
end
- def test_marshaling_with_local_instance
+ def test_marshalling_with_local_instance
t = Time.local(2000)
- unmarshaled = Marshal.load(Marshal.dump(t))
- assert_equal t.zone, unmarshaled.zone
- assert_equal t, unmarshaled
+ unmarshalled = Marshal.load(Marshal.dump(t))
+ assert_equal t.zone, unmarshalled.zone
+ assert_equal t, unmarshalled
end
- def test_marshaling_with_frozen_utc_instance
+ def test_marshalling_with_frozen_utc_instance
t = Time.utc(2000).freeze
- unmarshaled = Marshal.load(Marshal.dump(t))
- assert_equal "UTC", unmarshaled.zone
- assert_equal t, unmarshaled
+ unmarshalled = Marshal.load(Marshal.dump(t))
+ assert_equal "UTC", unmarshalled.zone
+ assert_equal t, unmarshalled
end
- def test_marshaling_with_frozen_local_instance
+ def test_marshalling_with_frozen_local_instance
t = Time.local(2000).freeze
- unmarshaled = Marshal.load(Marshal.dump(t))
- assert_equal t.zone, unmarshaled.zone
- assert_equal t, unmarshaled
+ unmarshalled = Marshal.load(Marshal.dump(t))
+ assert_equal t.zone, unmarshalled.zone
+ assert_equal t, unmarshalled
end
def test_marshalling_preserves_fractional_seconds
t = Time.parse("00:00:00.500")
- unmarshaled = Marshal.load(Marshal.dump(t))
- assert_equal t.to_f, unmarshaled.to_f
- assert_equal t, unmarshaled
+ unmarshalled = Marshal.load(Marshal.dump(t))
+ assert_equal t.to_f, unmarshalled.to_f
+ assert_equal t, unmarshalled
end
def test_last_quarter_on_31st
diff --git a/activesupport/test/silence_logger_test.rb b/activesupport/test/silence_logger_test.rb
new file mode 100644
index 0000000000..bd0c6b7f86
--- /dev/null
+++ b/activesupport/test/silence_logger_test.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require "abstract_unit"
+require "active_support/logger_silence"
+require "logger"
+
+class LoggerSilenceTest < ActiveSupport::TestCase
+ class MyLogger < ::Logger
+ include ActiveSupport::LoggerSilence
+ end
+
+ setup do
+ @io = StringIO.new
+ @logger = MyLogger.new(@io)
+ end
+
+ test "#silence silences the log" do
+ @logger.silence(Logger::ERROR) do
+ @logger.info("Foo")
+ end
+ @io.rewind
+
+ assert_empty @io.read
+ end
+
+ test "#debug? is true when setting the temporary level to Logger::DEBUG" do
+ @logger.level = Logger::INFO
+
+ @logger.silence(Logger::DEBUG) do
+ assert_predicate @logger, :debug?
+ end
+
+ assert_predicate @logger, :info?
+ end
+end
diff --git a/guides/source/3_0_release_notes.md b/guides/source/3_0_release_notes.md
index e793146c2c..e936644daf 100644
--- a/guides/source/3_0_release_notes.md
+++ b/guides/source/3_0_release_notes.md
@@ -38,7 +38,7 @@ If you're upgrading an existing application, it's a great idea to have good test
Rails 3.0 requires Ruby 1.8.7 or higher. Support for all of the previous Ruby versions has been dropped officially and you should upgrade as early as possible. Rails 3.0 is also compatible with Ruby 1.9.2.
-TIP: Note that Ruby 1.8.7 p248 and p249 have marshaling bugs that crash Rails 3.0. Ruby Enterprise Edition have these fixed since release 1.8.7-2010.02 though. On the 1.9 front, Ruby 1.9.1 is not usable because it outright segfaults on Rails 3.0, so if you want to use Rails 3 with 1.9.x jump on 1.9.2 for smooth sailing.
+TIP: Note that Ruby 1.8.7 p248 and p249 have marshalling bugs that crash Rails 3.0. Ruby Enterprise Edition have these fixed since release 1.8.7-2010.02 though. On the 1.9 front, Ruby 1.9.1 is not usable because it outright segfaults on Rails 3.0, so if you want to use Rails 3 with 1.9.x jump on 1.9.2 for smooth sailing.
### Rails Application object
diff --git a/guides/source/3_1_release_notes.md b/guides/source/3_1_release_notes.md
index 8c3dc3454d..d6981656ee 100644
--- a/guides/source/3_1_release_notes.md
+++ b/guides/source/3_1_release_notes.md
@@ -26,7 +26,7 @@ If you're upgrading an existing application, it's a great idea to have good test
Rails 3.1 requires Ruby 1.8.7 or higher. Support for all of the previous Ruby versions has been dropped officially and you should upgrade as early as possible. Rails 3.1 is also compatible with Ruby 1.9.2.
-TIP: Note that Ruby 1.8.7 p248 and p249 have marshaling bugs that crash Rails. Ruby Enterprise Edition have these fixed since release 1.8.7-2010.02 though. On the 1.9 front, Ruby 1.9.1 is not usable because it outright segfaults, so if you want to use 1.9.x jump on 1.9.2 for smooth sailing.
+TIP: Note that Ruby 1.8.7 p248 and p249 have marshalling bugs that crash Rails. Ruby Enterprise Edition have these fixed since release 1.8.7-2010.02 though. On the 1.9 front, Ruby 1.9.1 is not usable because it outright segfaults, so if you want to use 1.9.x jump on 1.9.2 for smooth sailing.
### What to update in your apps
diff --git a/guides/source/4_2_release_notes.md b/guides/source/4_2_release_notes.md
index f7c40d19e9..51d06bd07d 100644
--- a/guides/source/4_2_release_notes.md
+++ b/guides/source/4_2_release_notes.md
@@ -44,7 +44,7 @@ to their respective adapters. Active Job comes pre-configured with an inline
runner that executes jobs right away.
Jobs often need to take Active Record objects as arguments. Active Job passes
-object references as URIs (uniform resource identifiers) instead of marshaling
+object references as URIs (uniform resource identifiers) instead of marshalling
the object itself. The new [Global ID](https://github.com/rails/globalid)
library builds URIs and looks up the objects they reference. Passing Active
Record objects as job arguments just works by using Global ID internally.
diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md
index f9fc7044ba..6b0554bb5f 100644
--- a/guides/source/active_support_core_extensions.md
+++ b/guides/source/active_support_core_extensions.md
@@ -590,9 +590,9 @@ NOTE: Defined in `active_support/core_ext/module/attribute_accessors.rb`.
### Parents
-#### `parent`
+#### `module_parent`
-The `parent` method on a nested named module returns the module that contains its corresponding constant:
+The `module_parent` method on a nested named module returns the module that contains its corresponding constant:
```ruby
module X
@@ -603,19 +603,19 @@ module X
end
M = X::Y::Z
-X::Y::Z.parent # => X::Y
-M.parent # => X::Y
+X::Y::Z.module_parent # => X::Y
+M.module_parent # => X::Y
```
-If the module is anonymous or belongs to the top-level, `parent` returns `Object`.
+If the module is anonymous or belongs to the top-level, `module_parent` returns `Object`.
-WARNING: Note that in that case `parent_name` returns `nil`.
+WARNING: Note that in that case `module_parent_name` returns `nil`.
NOTE: Defined in `active_support/core_ext/module/introspection.rb`.
-#### `parent_name`
+#### `module_parent_name`
-The `parent_name` method on a nested named module returns the fully qualified name of the module that contains its corresponding constant:
+The `module_parent_name` method on a nested named module returns the fully qualified name of the module that contains its corresponding constant:
```ruby
module X
@@ -626,19 +626,19 @@ module X
end
M = X::Y::Z
-X::Y::Z.parent_name # => "X::Y"
-M.parent_name # => "X::Y"
+X::Y::Z.module_parent_name # => "X::Y"
+M.module_parent_name # => "X::Y"
```
-For top-level or anonymous modules `parent_name` returns `nil`.
+For top-level or anonymous modules `module_parent_name` returns `nil`.
-WARNING: Note that in that case `parent` returns `Object`.
+WARNING: Note that in that case `module_parent` returns `Object`.
NOTE: Defined in `active_support/core_ext/module/introspection.rb`.
-#### `parents`
+#### `module_parents`
-The method `parents` calls `parent` on the receiver and upwards until `Object` is reached. The chain is returned in an array, from bottom to top:
+The method `module_parents` calls `module_parent` on the receiver and upwards until `Object` is reached. The chain is returned in an array, from bottom to top:
```ruby
module X
@@ -649,8 +649,8 @@ module X
end
M = X::Y::Z
-X::Y::Z.parents # => [X::Y, X, Object]
-M.parents # => [X::Y, X, Object]
+X::Y::Z.module_parents # => [X::Y, X, Object]
+M.module_parents # => [X::Y, X, Object]
```
NOTE: Defined in `active_support/core_ext/module/introspection.rb`.
diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md
index bf046a3341..66cf9da33b 100644
--- a/guides/source/asset_pipeline.md
+++ b/guides/source/asset_pipeline.md
@@ -184,9 +184,8 @@ the file `scaffolds.css` (or `scaffolds.scss` if `sass-rails` is in the
`Gemfile`.)
For example, if you generate a `ProjectsController`, Rails will also add a new
-file at `app/assets/javascripts/projects.coffee` and another at
-`app/assets/stylesheets/projects.scss`. By default these files will be ready
-to use by your application immediately using the `require_tree` directive. See
+file at `app/assets/stylesheets/projects.scss`. By default these files will be
+ready to use by your application immediately using the `require_tree` directive. See
[Manifest Files and Directives](#manifest-files-and-directives) for more details
on require_tree.
diff --git a/guides/source/command_line.md b/guides/source/command_line.md
index 7fa0a49203..5fd3ad17de 100644
--- a/guides/source/command_line.md
+++ b/guides/source/command_line.md
@@ -185,7 +185,7 @@ The controller generator is expecting parameters in the form of `generate contro
```bash
$ rails generate controller Greetings hello
create app/controllers/greetings_controller.rb
- route get "greetings/hello"
+ route get 'greetings/hello'
invoke erb
create app/views/greetings
create app/views/greetings/hello.html.erb
@@ -193,9 +193,8 @@ $ rails generate controller Greetings hello
create test/controllers/greetings_controller_test.rb
invoke helper
create app/helpers/greetings_helper.rb
+ invoke test_unit
invoke assets
- invoke coffee
- create app/assets/javascripts/greetings.coffee
invoke scss
create app/assets/stylesheets/greetings.scss
```
diff --git a/guides/source/configuring.md b/guides/source/configuring.md
index 18a377a02e..812565b207 100644
--- a/guides/source/configuring.md
+++ b/guides/source/configuring.md
@@ -119,12 +119,11 @@ defaults to `:debug` for all environments. The available log levels are: `:debug
* `config.logger` is the logger that will be used for `Rails.logger` and any related Rails logging such as `ActiveRecord::Base.logger`. It defaults to an instance of `ActiveSupport::TaggedLogging` that wraps an instance of `ActiveSupport::Logger` which outputs a log to the `log/` directory. You can supply a custom logger, to get full compatibility you must follow these guidelines:
* To support a formatter, you must manually assign a formatter from the `config.log_formatter` value to the logger.
* To support tagged logs, the log instance must be wrapped with `ActiveSupport::TaggedLogging`.
- * To support silencing, the logger must include `LoggerSilence` and `ActiveSupport::LoggerThreadSafeLevel` modules. The `ActiveSupport::Logger` class already includes these modules.
+ * To support silencing, the logger must include `ActiveSupport::LoggerSilence` module. The `ActiveSupport::Logger` class already includes these modules.
```ruby
class MyLogger < ::Logger
- include ActiveSupport::LoggerThreadSafeLevel
- include LoggerSilence
+ include ActiveSupport::LoggerSilence
end
mylogger = MyLogger.new(STDOUT)
diff --git a/guides/source/generators.md b/guides/source/generators.md
index 89424a161b..f028d14998 100644
--- a/guides/source/generators.md
+++ b/guides/source/generators.md
@@ -203,8 +203,6 @@ $ rails generate scaffold User name:string
create test/application_system_test_case.rb
create test/system/users_test.rb
invoke assets
- invoke coffee
- create app/assets/javascripts/users.coffee
invoke scss
create app/assets/stylesheets/users.scss
invoke scss
@@ -426,9 +424,8 @@ $ rails generate scaffold Comment body:text
create test/application_system_test_case.rb
create test/system/comments_test.rb
invoke assets
- invoke coffee
- create app/assets/javascripts/comments.coffee
invoke scss
+ create app/assets/stylesheets/scaffolds.scss
```
Fallbacks allow your generators to have a single responsibility, increasing code reuse and reducing the amount of duplication.
diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md
index 197a198db7..9eb77d2a50 100644
--- a/guides/source/getting_started.md
+++ b/guides/source/getting_started.md
@@ -272,8 +272,6 @@ invoke helper
create app/helpers/welcome_helper.rb
invoke test_unit
invoke assets
-invoke coffee
-create app/assets/javascripts/welcome.coffee
invoke scss
create app/assets/stylesheets/welcome.scss
```
@@ -1665,7 +1663,6 @@ This creates five files and one empty directory:
| app/views/comments/ | Views of the controller are stored here |
| test/controllers/comments_controller_test.rb | The test for the controller |
| app/helpers/comments_helper.rb | A view helper file |
-| app/assets/javascripts/comments.coffee | CoffeeScript for the controller |
| app/assets/stylesheets/comments.scss | Cascading style sheet for the controller |
Like with any blog, our readers will create their comments directly after
diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md
index befd4e08c0..a0553c1ccc 100644
--- a/guides/source/upgrading_ruby_on_rails.md
+++ b/guides/source/upgrading_ruby_on_rails.md
@@ -41,7 +41,7 @@ Rails generally stays close to the latest released Ruby version when it's releas
* Rails 3.2.x is the last branch to support Ruby 1.8.7.
* Rails 3 and above require Ruby 1.8.7 or higher. Support for all of the previous Ruby versions has been dropped officially. You should upgrade as early as possible.
-TIP: Ruby 1.8.7 p248 and p249 have marshaling bugs that crash Rails. Ruby Enterprise Edition has these fixed since the release of 1.8.7-2010.02. On the 1.9 front, Ruby 1.9.1 is not usable because it outright segfaults, so if you want to use 1.9.x, jump straight to 1.9.3 for smooth sailing.
+TIP: Ruby 1.8.7 p248 and p249 have marshalling bugs that crash Rails. Ruby Enterprise Edition has these fixed since the release of 1.8.7-2010.02. On the 1.9 front, Ruby 1.9.1 is not usable because it outright segfaults, so if you want to use 1.9.x, jump straight to 1.9.3 for smooth sailing.
### The Update Task
diff --git a/guides/source/working_with_javascript_in_rails.md b/guides/source/working_with_javascript_in_rails.md
index 36f5039883..c36b3faa6c 100644
--- a/guides/source/working_with_javascript_in_rails.md
+++ b/guides/source/working_with_javascript_in_rails.md
@@ -494,10 +494,6 @@ replace the entire `<body>` of the page with the `<body>` of the response. It
will then use PushState to change the URL to the correct one, preserving
refresh semantics and giving you pretty URLs.
-The only thing you have to do to enable Turbolinks is have it in your `Gemfile`,
-and put `//= require turbolinks` in your JavaScript manifest, which is usually
-`app/assets/javascripts/application.js`.
-
If you want to disable Turbolinks for certain links, add a `data-turbolinks="false"`
attribute to the tag:
diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb
index 88dd932370..a67b90e285 100644
--- a/railties/lib/rails/railtie.rb
+++ b/railties/lib/rails/railtie.rb
@@ -224,7 +224,7 @@ module Rails
end
def railtie_namespace #:nodoc:
- @railtie_namespace ||= self.class.parents.detect { |n| n.respond_to?(:railtie_namespace) }
+ @railtie_namespace ||= self.class.module_parents.detect { |n| n.respond_to?(:railtie_namespace) }
end
protected