diff options
Diffstat (limited to 'activerecord')
193 files changed, 1162 insertions, 684 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 2b5fc1c2f8..8d4b01e995 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,9 +1,36 @@ -* Fix table comment also being applied to the primary key column +* PostgreSQL: Fix GROUP BY with ORDER BY virtual count attribute. + + Fixes #36022. + + *Ryuta Kamizono* + +* Make ActiveRecord `ConnectionPool.connections` method thread-safe. + + Fixes #36465. + + *Jeff Doering* + +* Add support for multiple databases to `rails db:abort_if_pending_migrations`. + + *Mark Lee* + +* Fix sqlite3 collation parsing when using decimal columns. + + *Martin R. Schuster* + +* Fix invalid schema when primary key column has a comment. + + Fixes #29966. + + *Guilherme Goettems Schneider* + +* Fix table comment also being applied to the primary key column. *Guilherme Goettems Schneider* * Allow generated `create_table` migrations to include or skip timestamps. - *Michael Duchemin* + *Michael Duchemin* + Please check [6-0-stable](https://github.com/rails/rails/blob/6-0-stable/activerecord/CHANGELOG.md) for previous changes. diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb index 3250e29b82..aa08124158 100644 --- a/activerecord/lib/active_record/aggregations.rb +++ b/activerecord/lib/active_record/aggregations.rb @@ -14,7 +14,6 @@ module ActiveRecord end private - def clear_aggregation_cache @aggregation_cache.clear if persisted? end diff --git a/activerecord/lib/active_record/association_relation.rb b/activerecord/lib/active_record/association_relation.rb index 4c538ef2bd..de9892e48d 100644 --- a/activerecord/lib/active_record/association_relation.rb +++ b/activerecord/lib/active_record/association_relation.rb @@ -29,7 +29,6 @@ module ActiveRecord end private - def exec_queries super do |record| @association.set_inverse_instance_from_queries(record) diff --git a/activerecord/lib/active_record/associations/alias_tracker.rb b/activerecord/lib/active_record/associations/alias_tracker.rb index 272eede824..ac90ba0137 100644 --- a/activerecord/lib/active_record/associations/alias_tracker.rb +++ b/activerecord/lib/active_record/associations/alias_tracker.rb @@ -72,7 +72,6 @@ module ActiveRecord attr_reader :aliases private - def truncate(name) name.slice(0, @connection.table_alias_length - 2) end diff --git a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb index 0140aa15c8..6ad4c75fb5 100644 --- a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb +++ b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb @@ -46,7 +46,6 @@ module ActiveRecord::Associations::Builder # :nodoc: end private - def self.suppress_composite_primary_key(pk) pk unless pk.is_a?(Array) end @@ -73,7 +72,6 @@ module ActiveRecord::Associations::Builder # :nodoc: end private - def middle_options(join_model) middle_options = {} middle_options[:class_name] = "#{lhs_model.name}::#{join_model.name}" diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 797d647900..0db0ad8595 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -1101,7 +1101,6 @@ module ActiveRecord delegate(*delegate_methods, to: :scope) private - def find_nth_with_limit(index, limit) load_target if find_from_target? super diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index 5972846940..dd2ed55279 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -37,7 +37,6 @@ module ActiveRecord end private - # Returns the number of records in this collection. # # If the association has a counter cache it gets that value. Otherwise diff --git a/activerecord/lib/active_record/associations/preloader.rb b/activerecord/lib/active_record/associations/preloader.rb index 6b57e5093a..d4e8b364e1 100644 --- a/activerecord/lib/active_record/associations/preloader.rb +++ b/activerecord/lib/active_record/associations/preloader.rb @@ -95,7 +95,6 @@ module ActiveRecord end private - # Loads all the given data into +records+ for the +association+. def preloaders_on(association, records, scope, polymorphic_parent = false) case association diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb index 342d9e7a5a..4c7b0e6f07 100644 --- a/activerecord/lib/active_record/associations/preloader/association.rb +++ b/activerecord/lib/active_record/associations/preloader/association.rb @@ -27,7 +27,9 @@ module ActiveRecord end def records_by_owner - @records_by_owner ||= preloaded_records.each_with_object({}) do |record, result| + # owners can be duplicated when a relation has a collection association join + # #compare_by_identity makes such owners different hash keys + @records_by_owner ||= preloaded_records.each_with_object({}.compare_by_identity) do |record, result| owners_by_key[convert_key(record[association_key_name])].each do |owner| (result[owner] ||= []) << record end diff --git a/activerecord/lib/active_record/attribute_assignment.rb b/activerecord/lib/active_record/attribute_assignment.rb index 929045f29b..acb8ba7e5a 100644 --- a/activerecord/lib/active_record/attribute_assignment.rb +++ b/activerecord/lib/active_record/attribute_assignment.rb @@ -7,7 +7,6 @@ module ActiveRecord include ActiveModel::AttributeAssignment private - def _assign_attributes(attributes) multi_parameter_attributes = {} nested_parameter_attributes = {} diff --git a/activerecord/lib/active_record/attribute_decorators.rb b/activerecord/lib/active_record/attribute_decorators.rb index 98b7805c0a..0b66043d2a 100644 --- a/activerecord/lib/active_record/attribute_decorators.rb +++ b/activerecord/lib/active_record/attribute_decorators.rb @@ -46,7 +46,6 @@ module ActiveRecord end private - def load_schema! super attribute_types.each do |name, type| @@ -75,7 +74,6 @@ module ActiveRecord end private - def decorators_for(name, type) matching(name, type).map(&:last) end diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index fd32eaaf3a..21f72bb6c7 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -159,59 +159,6 @@ module ActiveRecord end end - # Regexp for column names (with or without a table name prefix). Matches - # the following: - # "#{table_name}.#{column_name}" - # "#{column_name}" - COLUMN_NAME = /\A(?:\w+\.)?\w+\z/i - - # Regexp for column names with order (with or without a table name - # prefix, with or without various order modifiers). Matches the following: - # "#{table_name}.#{column_name}" - # "#{table_name}.#{column_name} #{direction}" - # "#{table_name}.#{column_name} #{direction} NULLS FIRST" - # "#{table_name}.#{column_name} NULLS LAST" - # "#{column_name}" - # "#{column_name} #{direction}" - # "#{column_name} #{direction} NULLS FIRST" - # "#{column_name} NULLS LAST" - COLUMN_NAME_WITH_ORDER = / - \A - (?:\w+\.)? - \w+ - (?:\s+asc|\s+desc)? - (?:\s+nulls\s+(?:first|last))? - \z - /ix - - def disallow_raw_sql!(args, permit: COLUMN_NAME) # :nodoc: - unexpected = nil - args.each do |arg| - next if arg.is_a?(Symbol) || Arel.arel_node?(arg) || - arg.to_s.split(/\s*,\s*/).all? { |part| permit.match?(part) } - (unexpected ||= []) << arg - end - - return unless unexpected - - if allow_unsafe_raw_sql == :deprecated - ActiveSupport::Deprecation.warn( - "Dangerous query method (method whose arguments are used as raw " \ - "SQL) called with non-attribute argument(s): " \ - "#{unexpected.map(&:inspect).join(", ")}. Non-attribute " \ - "arguments will be disallowed in Rails 6.1. This method should " \ - "not be called with user-provided values, such as request " \ - "parameters or model attributes. Known-safe values can be passed " \ - "by wrapping them in Arel.sql()." - ) - else - raise(ActiveRecord::UnknownAttributeReference, - "Query method called with non-attribute argument(s): " + - unexpected.map(&:inspect).join(", ") - ) - end - end - # Returns true if the given attribute exists, otherwise false. # # class Person < ActiveRecord::Base diff --git a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb index 3d917ec9b1..4a7b6c60e5 100644 --- a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb +++ b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb @@ -66,7 +66,6 @@ module ActiveRecord end private - # Dispatch target for <tt>*_before_type_cast</tt> attribute methods. def attribute_before_type_cast(attribute_name) read_attribute_before_type_cast(attribute_name) diff --git a/activerecord/lib/active_record/attribute_methods/primary_key.rb b/activerecord/lib/active_record/attribute_methods/primary_key.rb index b4f5e6e75a..768c5f8c05 100644 --- a/activerecord/lib/active_record/attribute_methods/primary_key.rb +++ b/activerecord/lib/active_record/attribute_methods/primary_key.rb @@ -45,7 +45,6 @@ module ActiveRecord end private - def attribute_method?(attr_name) attr_name == "id" || super end @@ -120,7 +119,6 @@ module ActiveRecord end private - def suppress_composite_primary_key(pk) return pk unless pk.is_a?(Array) diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb index 0562327a9a..0f0e721b24 100644 --- a/activerecord/lib/active_record/attribute_methods/read.rb +++ b/activerecord/lib/active_record/attribute_methods/read.rb @@ -7,7 +7,6 @@ module ActiveRecord module ClassMethods # :nodoc: private - def define_method_attribute(name) ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method( generated_attribute_methods, name diff --git a/activerecord/lib/active_record/attribute_methods/serialization.rb b/activerecord/lib/active_record/attribute_methods/serialization.rb index 6e0e90f39c..7bc03b9eed 100644 --- a/activerecord/lib/active_record/attribute_methods/serialization.rb +++ b/activerecord/lib/active_record/attribute_methods/serialization.rb @@ -79,7 +79,6 @@ module ActiveRecord end private - def type_incompatible_with_serialize?(type, class_name) type.is_a?(ActiveRecord::Type::Json) && class_name == ::JSON || type.respond_to?(:type_cast_array, true) && class_name == ::Array diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb index 294a3dc32c..fb44232dff 100644 --- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb +++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb @@ -25,7 +25,6 @@ module ActiveRecord end private - def convert_time_to_time_zone(value) return if value.nil? @@ -64,7 +63,6 @@ module ActiveRecord module ClassMethods # :nodoc: private - def inherited(subclass) super # We need to apply this decorator here, rather than on module inclusion. The closure diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb index 1c63b553d0..66536a8ddf 100644 --- a/activerecord/lib/active_record/attribute_methods/write.rb +++ b/activerecord/lib/active_record/attribute_methods/write.rb @@ -11,7 +11,6 @@ module ActiveRecord module ClassMethods # :nodoc: private - def define_method_attribute=(name) ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method( generated_attribute_methods, name, writer: true, diff --git a/activerecord/lib/active_record/attributes.rb b/activerecord/lib/active_record/attributes.rb index 7cf421c184..c7846dbe7a 100644 --- a/activerecord/lib/active_record/attributes.rb +++ b/activerecord/lib/active_record/attributes.rb @@ -255,7 +255,6 @@ module ActiveRecord end private - NO_DEFAULT_PROVIDED = Object.new # :nodoc: private_constant :NO_DEFAULT_PROVIDED diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb index 8d89e7d84a..a7709b444d 100644 --- a/activerecord/lib/active_record/autosave_association.rb +++ b/activerecord/lib/active_record/autosave_association.rb @@ -147,7 +147,6 @@ module ActiveRecord module ClassMethods # :nodoc: private - def define_non_cyclic_method(name, &block) return if instance_methods(false).include?(name) define_method(name) do |*args| @@ -267,7 +266,6 @@ module ActiveRecord end private - # Returns the record for an association collection that should be validated # or saved. If +autosave+ is +false+ only new records will be returned, # unless the parent is/was a new record itself. diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb index ef5444dfc3..a9ab9ab7a9 100644 --- a/activerecord/lib/active_record/callbacks.rb +++ b/activerecord/lib/active_record/callbacks.rb @@ -323,7 +323,6 @@ module ActiveRecord end private - def create_or_update(**) _run_save_callbacks { super } end diff --git a/activerecord/lib/active_record/coders/yaml_column.rb b/activerecord/lib/active_record/coders/yaml_column.rb index 11559141c7..881f0bcdb0 100644 --- a/activerecord/lib/active_record/coders/yaml_column.rb +++ b/activerecord/lib/active_record/coders/yaml_column.rb @@ -39,7 +39,6 @@ module ActiveRecord end private - def check_arity_of_constructor load(nil) rescue ArgumentError diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb index 7628ef5537..9b3f5260f7 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -20,6 +20,26 @@ module ActiveRecord end module ConnectionAdapters + module AbstractPool # :nodoc: + def get_schema_cache(connection) + @schema_cache ||= SchemaCache.new(connection) + @schema_cache.connection = connection + @schema_cache + end + + def set_schema_cache(cache) + @schema_cache = cache + end + end + + class NullPool # :nodoc: + include ConnectionAdapters::AbstractPool + + def initialize + @schema_cache = nil + end + end + # Connection pool base class for managing Active Record database # connections. # @@ -147,7 +167,6 @@ module ActiveRecord end private - def internal_poll(timeout) no_wait_poll || (timeout && wait_poll(timeout)) end @@ -310,7 +329,6 @@ module ActiveRecord end private - def spawn_thread(frequency) Thread.new(frequency) do |t| loop do @@ -336,9 +354,10 @@ module ActiveRecord include MonitorMixin include QueryCache::ConnectionPoolConfiguration + include ConnectionAdapters::AbstractPool attr_accessor :automatic_reconnect, :checkout_timeout, :schema_cache - attr_reader :spec, :connections, :size, :reaper + attr_reader :spec, :size, :reaper # Creates a new ConnectionPool object. +spec+ is a ConnectionSpecification # object which describes database connection information (e.g. adapter, @@ -451,6 +470,21 @@ module ActiveRecord synchronize { @connections.any? } end + # Returns an array containing the connections currently in the pool. + # Access to the array does not require synchronization on the pool because + # the array is newly created and not retained by the pool. + # + # However; this method bypasses the ConnectionPool's thread-safe connection + # access pattern. A returned connection may be owned by another thread, + # unowned, or by happen-stance owned by the calling thread. + # + # Calling methods on a connection without ownership is subject to the + # thread-safety guarantees of the underlying method. Many of the methods + # on connection adapter classes are inherently multi-thread unsafe. + def connections + synchronize { @connections.dup } + end + # Disconnects all connections in the pool, and clears the pool. # # Raises: @@ -837,7 +871,6 @@ module ActiveRecord def new_connection Base.send(spec.adapter_method, spec.config).tap do |conn| - conn.schema_cache = schema_cache.dup if schema_cache conn.check_version end end @@ -966,15 +999,30 @@ module ActiveRecord end end + attr_reader :prevent_writes + def initialize # These caches are keyed by spec.name (ConnectionSpecification#name). @owner_to_pool = ConnectionHandler.create_owner_to_pool + @prevent_writes = false # Backup finalizer: if the forked child never needed a pool, the above # early discard has not occurred ObjectSpace.define_finalizer self, ConnectionHandler.unowned_pool_finalizer(@owner_to_pool) end + # Prevent writing to the database regardless of role. + # + # In some cases you may want to prevent writes to the database + # even if you are on a database that can write. `while_preventing_writes` + # will prevent writes to the database for the duration of the block. + def while_preventing_writes + original, @prevent_writes = @prevent_writes, true + yield + ensure + @prevent_writes = original + end + def connection_pool_list owner_to_pool.values.compact end @@ -1092,7 +1140,6 @@ module ActiveRecord end private - def owner_to_pool @owner_to_pool[Process.pid] end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb index a7753e3e9c..6fec4dbd81 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb @@ -109,7 +109,6 @@ module ActiveRecord end private - def cache_sql(sql, name, binds) @lock.synchronize do result = diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb index 2877530917..93273f6cf6 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb @@ -114,16 +114,16 @@ module ActiveRecord # if the value is a Time responding to usec. def quoted_date(value) if value.acts_like?(:time) - zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal - - if value.respond_to?(zone_conversion_method) - value = value.send(zone_conversion_method) + if ActiveRecord::Base.default_timezone == :utc + value = value.getutc if value.respond_to?(:getutc) && !value.utc? + else + value = value.getlocal if value.respond_to?(:getlocal) end end result = value.to_s(:db) if value.respond_to?(:usec) && value.usec > 0 - "#{result}.#{sprintf("%06d", value.usec)}" + result << "." << sprintf("%06d", value.usec) else result end @@ -142,6 +142,59 @@ module ActiveRecord value.to_s.gsub(%r{ (/ (?: | \g<1>) \*) \+? \s* | \s* (\* (?: | \g<2>) /) }x, "") end + def column_name_matcher # :nodoc: + COLUMN_NAME + end + + def column_name_with_order_matcher # :nodoc: + COLUMN_NAME_WITH_ORDER + end + + # Regexp for column names (with or without a table name prefix). + # Matches the following: + # + # "#{table_name}.#{column_name}" + # "#{column_name}" + COLUMN_NAME = / + \A + ( + (?: + # table_name.column_name | function(one or no argument) + ((?:\w+\.)?\w+) | \w+\((?:|\g<2>)\) + ) + (?:(?:\s+AS)?\s+\w+)? + ) + (?:\s*,\s*\g<1>)* + \z + /ix + + # Regexp for column names with order (with or without a table name prefix, + # with or without various order modifiers). Matches the following: + # + # "#{table_name}.#{column_name}" + # "#{table_name}.#{column_name} #{direction}" + # "#{table_name}.#{column_name} #{direction} NULLS FIRST" + # "#{table_name}.#{column_name} NULLS LAST" + # "#{column_name}" + # "#{column_name} #{direction}" + # "#{column_name} #{direction} NULLS FIRST" + # "#{column_name} NULLS LAST" + COLUMN_NAME_WITH_ORDER = / + \A + ( + (?: + # table_name.column_name | function(one or no argument) + ((?:\w+\.)?\w+) | \w+\((?:|\g<2>)\) + ) + (?:\s+ASC|\s+DESC)? + (?:\s+NULLS\s+(?:FIRST|LAST))? + ) + (?:\s*,\s*\g<1>)* + \z + /ix + + private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER + private def type_casted_binds(binds) if binds.first.is_a?(Array) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb index 7d20825a75..23c993cfc3 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb @@ -19,7 +19,6 @@ module ActiveRecord to: :@conn, private: true private - def visit_AlterTable(o) sql = +"ALTER TABLE #{quote_table_name(o.name)} " sql << o.adds.map { |col| accept col }.join(" ") diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb index 622e00fffb..fb56e712be 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb @@ -15,7 +15,7 @@ module ActiveRecord def column_spec_for_primary_key(column) return {} if default_primary_key?(column) spec = { id: schema_type(column).inspect } - spec.merge!(prepare_column_options(column).except!(:null)) + spec.merge!(prepare_column_options(column).except!(:null, :comment)) spec[:default] ||= "nil" if explicit_primary_key_default?(column) spec end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index cf57af5473..79dc98607a 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -310,6 +310,8 @@ module ActiveRecord if force drop_table(table_name, force: force, if_exists: true) + else + schema_cache.clear_data_source_cache!(table_name.to_s) end result = execute schema_creation.accept td @@ -499,6 +501,7 @@ module ActiveRecord # it can be helpful to provide these in a migration's +change+ method so it can be reverted. # In that case, +options+ and the block will be used by #create_table. def drop_table(table_name, options = {}) + schema_cache.clear_data_source_cache!(table_name.to_s) execute "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}" end @@ -1061,8 +1064,8 @@ module ActiveRecord options end - def dump_schema_information #:nodoc: - versions = ActiveRecord::SchemaMigration.all_versions + def dump_schema_information # :nodoc: + versions = schema_migration.all_versions insert_versions_sql(versions) if versions.any? end @@ -1078,7 +1081,7 @@ module ActiveRecord end version = version.to_i - sm_table = quote_table_name(ActiveRecord::SchemaMigration.table_name) + sm_table = quote_table_name(schema_migration.table_name) migrated = migration_context.get_all_versions versions = migration_context.migrations.map(&:version) @@ -1451,7 +1454,7 @@ module ActiveRecord end def insert_versions_sql(versions) - sm_table = quote_table_name(ActiveRecord::SchemaMigration.table_name) + sm_table = quote_table_name(schema_migration.table_name) if versions.is_a?(Array) sql = +"INSERT INTO #{sm_table} (version) VALUES\n" diff --git a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb index 7b6321d83b..53ce8df491 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb @@ -5,10 +5,11 @@ module ActiveRecord class TransactionState def initialize(state = nil) @state = state - @children = [] + @children = nil end def add_child(state) + @children ||= [] @children << state end @@ -41,12 +42,12 @@ module ActiveRecord end def rollback! - @children.each { |c| c.rollback! } + @children&.each { |c| c.rollback! } @state = :rolledback end def full_rollback! - @children.each { |c| c.rollback! } + @children&.each { |c| c.rollback! } @state = :fully_rolledback end @@ -75,18 +76,19 @@ module ActiveRecord class Transaction #:nodoc: attr_reader :connection, :state, :records, :savepoint_name, :isolation_level - def initialize(connection, options, run_commit_callbacks: false) + def initialize(connection, isolation: nil, joinable: true, run_commit_callbacks: false) @connection = connection @state = TransactionState.new - @records = [] - @isolation_level = options[:isolation] + @records = nil + @isolation_level = isolation @materialized = false - @joinable = options.fetch(:joinable, true) + @joinable = joinable @run_commit_callbacks = run_commit_callbacks end def add_record(record) - records << record + @records ||= [] + @records << record end def materialize! @@ -98,6 +100,7 @@ module ActiveRecord end def rollback_records + return unless records ite = records.uniq(&:object_id) already_run_callbacks = {} while record = ite.shift @@ -107,16 +110,17 @@ module ActiveRecord record.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: should_run_callbacks) end ensure - ite.each do |i| + ite&.each do |i| i.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: false) end end def before_commit_records - records.uniq.each(&:before_committed!) if @run_commit_callbacks + records.uniq.each(&:before_committed!) if records && @run_commit_callbacks end def commit_records + return unless records ite = records.uniq(&:object_id) already_run_callbacks = {} while record = ite.shift @@ -131,7 +135,7 @@ module ActiveRecord end end ensure - ite.each { |i| i.committed!(should_run_callbacks: false) } + ite&.each { |i| i.committed!(should_run_callbacks: false) } end def full_rollback?; true; end @@ -141,8 +145,8 @@ module ActiveRecord end class SavepointTransaction < Transaction - def initialize(connection, savepoint_name, parent_transaction, *args) - super(connection, *args) + def initialize(connection, savepoint_name, parent_transaction, **options) + super(connection, options) parent_transaction.state.add_child(@state) @@ -202,18 +206,29 @@ module ActiveRecord @lazy_transactions_enabled = true end - def begin_transaction(options = {}) + def begin_transaction(isolation: nil, joinable: true, _lazy: true) @connection.lock.synchronize do run_commit_callbacks = !current_transaction.joinable? transaction = if @stack.empty? - RealTransaction.new(@connection, options, run_commit_callbacks: run_commit_callbacks) + RealTransaction.new( + @connection, + isolation: isolation, + joinable: joinable, + run_commit_callbacks: run_commit_callbacks + ) else - SavepointTransaction.new(@connection, "active_record_#{@stack.size}", @stack.last, options, - run_commit_callbacks: run_commit_callbacks) + SavepointTransaction.new( + @connection, + "active_record_#{@stack.size}", + @stack.last, + isolation: isolation, + joinable: joinable, + run_commit_callbacks: run_commit_callbacks + ) end - if @connection.supports_lazy_transactions? && lazy_transactions_enabled? && options[:_lazy] != false + if @connection.supports_lazy_transactions? && lazy_transactions_enabled? && _lazy @has_unmaterialized_transactions = true else transaction.materialize! @@ -274,9 +289,9 @@ module ActiveRecord end end - def within_new_transaction(options = {}) + def within_new_transaction(isolation: nil, joinable: true) @connection.lock.synchronize do - transaction = begin_transaction options + transaction = begin_transaction(isolation: isolation, joinable: joinable) yield rescue Exception => error if transaction @@ -309,7 +324,6 @@ module ActiveRecord end private - NULL_TRANSACTION = NullTransaction.new # Deallocate invalidated prepared statements outside of the transaction diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index bf0bb84c93..c0ead17b3b 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -78,7 +78,7 @@ module ActiveRecord SIMPLE_INT = /\A\d+\z/ attr_accessor :pool - attr_reader :schema_cache, :visitor, :owner, :logger, :lock, :prepared_statements, :prevent_writes + attr_reader :visitor, :owner, :logger, :lock, :prepared_statements alias :in_use? :owner set_callback :checkin, :after, :enable_lazy_transactions! @@ -114,11 +114,9 @@ module ActiveRecord @instrumenter = ActiveSupport::Notifications.instrumenter @logger = logger @config = config - @pool = nil + @pool = ActiveRecord::ConnectionAdapters::NullPool.new @idle_since = Concurrent.monotonic_time - @schema_cache = SchemaCache.new self @quoted_column_names, @quoted_table_names = {}, {} - @prevent_writes = false @visitor = arel_visitor @statements = build_statement_pool @lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new @@ -144,19 +142,7 @@ module ActiveRecord # Returns true if the connection is a replica, or if +prevent_writes+ # is set to true. def preventing_writes? - replica? || prevent_writes - end - - # Prevent writing to the database regardless of role. - # - # In some cases you may want to prevent writes to the database - # even if you are on a database that can write. `while_preventing_writes` - # will prevent writes to the database for the duration of the block. - def while_preventing_writes - original, @prevent_writes = @prevent_writes, true - yield - ensure - @prevent_writes = original + replica? || ActiveRecord::Base.connection_handler.prevent_writes end def migrations_paths # :nodoc: @@ -164,7 +150,22 @@ module ActiveRecord end def migration_context # :nodoc: - MigrationContext.new(migrations_paths) + MigrationContext.new(migrations_paths, schema_migration) + end + + def schema_migration # :nodoc: + @schema_migration ||= begin + conn = self + spec_name = conn.pool.spec.name + name = "#{spec_name}::SchemaMigration" + + Class.new(ActiveRecord::SchemaMigration) do + define_singleton_method(:name) { name } + define_singleton_method(:to_s) { name } + + self.connection_specification_name = spec_name + end + end end class Version @@ -206,9 +207,13 @@ module ActiveRecord @owner = Thread.current end + def schema_cache + @pool.get_schema_cache(self) + end + def schema_cache=(cache) cache.connection = self - @schema_cache = cache + @pool.set_schema_cache(cache) end # this method must only be called while holding connection pool's mutex @@ -487,6 +492,9 @@ module ActiveRecord # # Prevent @connection's finalizer from touching the socket, or # otherwise communicating with its server, when it is collected. + if schema_cache.connection == self + schema_cache.connection = nil + end end # Reset the state of this connection, directing the DBMS to clear @@ -587,7 +595,6 @@ module ActiveRecord end private - def type_map @type_map ||= Type::TypeMap.new.tap do |mapping| initialize_type_map(mapping) diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index ef33d712ad..70292e6d63 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -45,7 +45,6 @@ module ActiveRecord class StatementPool < ConnectionAdapters::StatementPool # :nodoc: private - def dealloc(stmt) stmt.close end @@ -289,6 +288,8 @@ module ActiveRecord # Example: # rename_table('octopuses', 'octopi') def rename_table(table_name, new_name) + schema_cache.clear_data_source_cache!(table_name.to_s) + schema_cache.clear_data_source_cache!(new_name.to_s) execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}" rename_table_indexes(table_name, new_name) end @@ -309,6 +310,7 @@ module ActiveRecord # it can be helpful to provide these in a migration's +change+ method so it can be reverted. # In that case, +options+ and the block will be used by create_table. def drop_table(table_name, options = {}) + schema_cache.clear_data_source_cache!(table_name.to_s) execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}" end @@ -513,7 +515,6 @@ module ActiveRecord end private - def initialize_type_map(m = type_map) super @@ -795,7 +796,6 @@ module ActiveRecord end private - def cast_value(value) case value when true then "1" diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb index 9eaf9d9a89..df26f67c6e 100644 --- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb @@ -56,7 +56,6 @@ module ActiveRecord end private - attr_reader :uri def uri_parser diff --git a/activerecord/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb b/activerecord/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb index 1df4dea2d8..97d74df529 100644 --- a/activerecord/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +++ b/activerecord/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb @@ -5,7 +5,7 @@ module ActiveRecord module DetermineIfPreparableVisitor attr_accessor :preparable - def accept(*) + def accept(object, collector) @preparable = true super end @@ -20,7 +20,7 @@ module ActiveRecord super end - def visit_Arel_Nodes_SqlLiteral(*) + def visit_Arel_Nodes_SqlLiteral(o, collector) @preparable = false super end diff --git a/activerecord/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb b/activerecord/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb index 20c3c83664..edd5ea0542 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb @@ -37,7 +37,6 @@ module ActiveRecord end private - def compute_column_widths(result) [].tap do |widths| result.columns.each_with_index do |column, i| diff --git a/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb index 75564a61d6..dfed5471f4 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb @@ -32,12 +32,49 @@ module ActiveRecord "x'#{value.hex}'" end - def _type_cast(value) - case value - when Date, Time then value - else super - end + def column_name_matcher + COLUMN_NAME + end + + def column_name_with_order_matcher + COLUMN_NAME_WITH_ORDER end + + COLUMN_NAME = / + \A + ( + (?: + # `table_name`.`column_name` | function(one or no argument) + ((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`)) | \w+\((?:|\g<2>)\) + ) + (?:(?:\s+AS)?\s+(?:\w+|`\w+`))? + ) + (?:\s*,\s*\g<1>)* + \z + /ix + + COLUMN_NAME_WITH_ORDER = / + \A + ( + (?: + # `table_name`.`column_name` | function(one or no argument) + ((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`)) | \w+\((?:|\g<2>)\) + ) + (?:\s+ASC|\s+DESC)? + ) + (?:\s*,\s*\g<1>)* + \z + /ix + + private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER + + private + def _type_cast(value) + case value + when Date, Time then value + else super + end + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/mysql/schema_creation.rb b/activerecord/lib/active_record/connection_adapters/mysql/schema_creation.rb index 82ed320617..0f5ab7562a 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/schema_creation.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/schema_creation.rb @@ -7,7 +7,6 @@ module ActiveRecord delegate :add_sql_comment!, :mariadb?, to: :@conn, private: true private - def visit_DropForeignKey(name) "DROP FOREIGN KEY #{name}" end diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index 5b0335c22b..53510c62c2 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -109,12 +109,12 @@ module ActiveRecord end def discard! # :nodoc: + super @connection.automatic_close = false @connection = nil end private - def connect @connection = Mysql2::Client.new(@config) configure_connection diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb index b1dfbde86e..0bbe98145a 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb @@ -77,7 +77,6 @@ module ActiveRecord end private - def type_cast_array(value, method) if value.is_a?(::Array) value.map { |item| type_cast_array(item, method) } diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb index f70f09ad95..bae34472e1 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb @@ -10,7 +10,6 @@ module ActiveRecord end private - def cast_value(value) value.to_s end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb index 7b42677101..8d4dacbd64 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb @@ -46,7 +46,6 @@ module ActiveRecord end private - HstorePair = begin quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/ unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/ diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb index 7f6adc351c..e52d4385ef 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb @@ -34,7 +34,6 @@ module ActiveRecord end private - def number_for_point(number) number.to_s.gsub(/\.0$/, "") end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb index 8c74cecc4d..e81e18ff70 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb @@ -50,7 +50,6 @@ module ActiveRecord end private - def number_for_point(number) number.to_s.gsub(/\.0$/, "") end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb index aa7701e038..d19f1f9cf8 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb @@ -58,7 +58,6 @@ module ActiveRecord end private - def type_cast_single(value) infinity?(value) ? value : @subtype.deserialize(value) end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/uuid.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/uuid.rb index 28abdbd073..74a28eef58 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/uuid.rb @@ -14,7 +14,6 @@ module ActiveRecord end private - def cast_value(value) casted = value.to_s casted if casted.match?(ACCEPTABLE_UUID) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb index d40e0ef1f0..0c800dca83 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb @@ -78,6 +78,43 @@ module ActiveRecord type_map.lookup(column.oid, column.fmod, column.sql_type) end + def column_name_matcher + COLUMN_NAME + end + + def column_name_with_order_matcher + COLUMN_NAME_WITH_ORDER + end + + COLUMN_NAME = / + \A + ( + (?: + # "table_name"."column_name"::type_name | function(one or no argument)::type_name + ((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")(?:::\w+)?) | \w+\((?:|\g<2>)\)(?:::\w+)? + ) + (?:(?:\s+AS)?\s+(?:\w+|"\w+"))? + ) + (?:\s*,\s*\g<1>)* + \z + /ix + + COLUMN_NAME_WITH_ORDER = / + \A + ( + (?: + # "table_name"."column_name"::type_name | function(one or no argument)::type_name + ((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")(?:::\w+)?) | \w+\((?:|\g<2>)\)(?:::\w+)? + ) + (?:\s+ASC|\s+DESC)? + (?:\s+NULLS\s+(?:FIRST|LAST))? + ) + (?:\s*,\s*\g<1>)* + \z + /ix + + private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER + private def lookup_cast_type(sql_type) super(query_value("SELECT #{quote(sql_type)}::regtype::oid", "SCHEMA").to_i) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb index 84643d20da..d201e40190 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb @@ -5,7 +5,6 @@ module ActiveRecord module PostgreSQL class SchemaDumper < ConnectionAdapters::SchemaDumper # :nodoc: private - def extensions(stream) extensions = @connection.extensions if extensions.any? diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index 40c5e51d92..0062952667 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -55,6 +55,7 @@ module ActiveRecord end def drop_table(table_name, options = {}) # :nodoc: + schema_cache.clear_data_source_cache!(table_name.to_s) execute "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}" end @@ -376,6 +377,8 @@ module ActiveRecord # rename_table('octopuses', 'octopi') def rename_table(table_name, new_name) clear_cache! + schema_cache.clear_data_source_cache!(table_name.to_s) + schema_cache.clear_data_source_cache!(new_name.to_s) execute "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}" pk, seq = pk_and_sequence_for(new_name) if pk diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/utils.rb b/activerecord/lib/active_record/connection_adapters/postgresql/utils.rb index f2f4701500..e8caeb8132 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/utils.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/utils.rb @@ -37,7 +37,6 @@ module ActiveRecord end protected - def parts @parts ||= [@schema, @identifier].compact end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 91318a0af1..6b18a12bce 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -302,6 +302,7 @@ module ActiveRecord end def discard! # :nodoc: + super @connection.socket_io.reopen(IO::NULL) rescue nil @connection = nil end @@ -452,7 +453,6 @@ module ActiveRecord end private - # See https://www.postgresql.org/docs/current/static/errcodes-appendix.html VALUE_LIMIT_VIOLATION = "22001" NUMERIC_VALUE_OUT_OF_RANGE = "22003" diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb b/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb index cb9d32a577..58787cf9db 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb @@ -45,8 +45,43 @@ module ActiveRecord 0 end - private + def column_name_matcher + COLUMN_NAME + end + + def column_name_with_order_matcher + COLUMN_NAME_WITH_ORDER + end + COLUMN_NAME = / + \A + ( + (?: + # "table_name"."column_name" | function(one or no argument) + ((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")) | \w+\((?:|\g<2>)\) + ) + (?:(?:\s+AS)?\s+(?:\w+|"\w+"))? + ) + (?:\s*,\s*\g<1>)* + \z + /ix + + COLUMN_NAME_WITH_ORDER = / + \A + ( + (?: + # "table_name"."column_name" | function(one or no argument) + ((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")) | \w+\((?:|\g<2>)\) + ) + (?:\s+ASC|\s+DESC)? + ) + (?:\s*,\s*\g<1>)* + \z + /ix + + private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER + + private def _type_cast(value) case value when BigDecimal diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index 733a8f1c86..da971fdba7 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -218,6 +218,8 @@ module ActiveRecord # Example: # rename_table('octopuses', 'octopi') def rename_table(table_name, new_name) + schema_cache.clear_data_source_cache!(table_name.to_s) + schema_cache.clear_data_source_cache!(new_name.to_s) exec_query "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}" rename_table_indexes(table_name, new_name) end @@ -478,9 +480,9 @@ module ActiveRecord result = exec_query(sql, "SCHEMA").first if result - # Splitting with left parentheses and picking up last will return all + # Splitting with left parentheses and discarding the first part will return all # columns separated with comma(,). - columns_string = result["sql"].split("(").last + columns_string = result["sql"].split("(", 2).last columns_string.split(",").each do |column_string| # This regex will match the column name and collation type and will save diff --git a/activerecord/lib/active_record/connection_adapters/statement_pool.rb b/activerecord/lib/active_record/connection_adapters/statement_pool.rb index 46bd831da7..0960feed84 100644 --- a/activerecord/lib/active_record/connection_adapters/statement_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/statement_pool.rb @@ -48,7 +48,6 @@ module ActiveRecord end private - def cache @cache[Process.pid] end diff --git a/activerecord/lib/active_record/connection_handling.rb b/activerecord/lib/active_record/connection_handling.rb index 040ebdb960..c8cefa9906 100644 --- a/activerecord/lib/active_record/connection_handling.rb +++ b/activerecord/lib/active_record/connection_handling.rb @@ -173,7 +173,7 @@ module ActiveRecord raise "Anonymous class is not allowed." unless name config_or_env ||= DEFAULT_ENV.call.to_sym - pool_name = self == Base ? "primary" : name + pool_name = primary_class? ? "primary" : name self.connection_specification_name = pool_name resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new(Base.configurations) @@ -204,11 +204,15 @@ module ActiveRecord # Return the specification name from the current class or its parent. def connection_specification_name if !defined?(@connection_specification_name) || @connection_specification_name.nil? - return self == Base ? "primary" : superclass.connection_specification_name + return primary_class? ? "primary" : superclass.connection_specification_name end @connection_specification_name end + def primary_class? # :nodoc: + self == Base || defined?(ApplicationRecord) && self == ApplicationRecord + end + # Returns the configuration of the associated connection as a hash: # # ActiveRecord::Base.connection_config @@ -252,7 +256,6 @@ module ActiveRecord :clear_all_connections!, :flush_idle_connections!, to: :connection_handler private - def swap_connection_handler(handler, &blk) # :nodoc: old_handler, ActiveRecord::Base.connection_handler = ActiveRecord::Base.connection_handler, handler yield diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index dfd33d3dd7..595ef4ee25 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -286,7 +286,6 @@ module ActiveRecord end private - def cached_find_by_statement(key, &block) cache = @find_by_statement_cache[connection.prepared_statements] cache.compute_if_absent(key) { StatementCache.create(connection, &block) } @@ -554,7 +553,6 @@ module ActiveRecord end private - # +Array#flatten+ will call +#to_ary+ (recursively) on each of the elements of # the array, and then rescues from the possible +NoMethodError+. If those elements are # +ActiveRecord::Base+'s, then this triggers the various +method_missing+'s that we have, diff --git a/activerecord/lib/active_record/database_configurations/url_config.rb b/activerecord/lib/active_record/database_configurations/url_config.rb index e2d30ae416..e6b4acc647 100644 --- a/activerecord/lib/active_record/database_configurations/url_config.rb +++ b/activerecord/lib/active_record/database_configurations/url_config.rb @@ -56,7 +56,6 @@ module ActiveRecord end private - def build_url_hash(url) if url.nil? || /^jdbc:/.match?(url) { "url" => url } diff --git a/activerecord/lib/active_record/dynamic_matchers.rb b/activerecord/lib/active_record/dynamic_matchers.rb index 398a029068..7d9e221faa 100644 --- a/activerecord/lib/active_record/dynamic_matchers.rb +++ b/activerecord/lib/active_record/dynamic_matchers.rb @@ -69,7 +69,6 @@ module ActiveRecord end private - def body "#{finder}(#{attributes_hash})" end diff --git a/activerecord/lib/active_record/explain.rb b/activerecord/lib/active_record/explain.rb index 919e96cd7a..5dca75c539 100644 --- a/activerecord/lib/active_record/explain.rb +++ b/activerecord/lib/active_record/explain.rb @@ -36,7 +36,6 @@ module ActiveRecord end private - def render_bind(attr) value = if attr.type.binary? && attr.value "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>" diff --git a/activerecord/lib/active_record/fixture_set/table_row.rb b/activerecord/lib/active_record/fixture_set/table_row.rb index cb4726f1ee..f65329f91d 100644 --- a/activerecord/lib/active_record/fixture_set/table_row.rb +++ b/activerecord/lib/active_record/fixture_set/table_row.rb @@ -48,7 +48,6 @@ module ActiveRecord end private - def model_metadata @table_rows.model_metadata end diff --git a/activerecord/lib/active_record/fixture_set/table_rows.rb b/activerecord/lib/active_record/fixture_set/table_rows.rb index 23814b6cb5..df1cd63963 100644 --- a/activerecord/lib/active_record/fixture_set/table_rows.rb +++ b/activerecord/lib/active_record/fixture_set/table_rows.rb @@ -29,7 +29,6 @@ module ActiveRecord end private - def build_table_rows_from(table_name, fixtures, config) now = config.default_timezone == :utc ? Time.now.utc : Time.now diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 327121a2a2..046ed0e95c 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -464,7 +464,6 @@ module ActiveRecord end private - def insert_class(class_names, name, klass) # We only want to deal with AR objects. if klass && klass < ActiveRecord::Base @@ -570,7 +569,6 @@ module ActiveRecord end private - def read_and_insert(fixtures_directory, fixture_files, class_names, connection) # :nodoc: fixtures_map = {} fixture_sets = fixture_files.map do |fixture_set_name| @@ -661,7 +659,6 @@ module ActiveRecord end private - def model_class=(class_name) if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any? @model_class = class_name diff --git a/activerecord/lib/active_record/inheritance.rb b/activerecord/lib/active_record/inheritance.rb index 9570bc6f86..5ca48fa18c 100644 --- a/activerecord/lib/active_record/inheritance.rb +++ b/activerecord/lib/active_record/inheritance.rb @@ -176,7 +176,6 @@ module ActiveRecord end protected - # Returns the class type of the record using the current module as a prefix. So descendants of # MyApp::Business::Account would appear as MyApp::Business::AccountSubclass. def compute_type(type_name) @@ -208,7 +207,6 @@ module ActiveRecord end private - # Called by +instantiate+ to decide which class to use for a new # record instance. For single-table inheritance, we check the record # for a +type+ column and return the corresponding class. @@ -272,7 +270,6 @@ module ActiveRecord end private - def initialize_internals_callback super ensure_proper_type diff --git a/activerecord/lib/active_record/internal_metadata.rb b/activerecord/lib/active_record/internal_metadata.rb index e6166581f1..8f3c6d0ee3 100644 --- a/activerecord/lib/active_record/internal_metadata.rb +++ b/activerecord/lib/active_record/internal_metadata.rb @@ -28,10 +28,6 @@ module ActiveRecord where(key: key).pluck(:value).first end - def table_exists? - connection.table_exists?(table_name) - end - # Creates an internal metadata table with columns +key+ and +value+ def create_table unless table_exists? diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index 6711ee9bf4..c2a083bf3b 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -156,7 +156,6 @@ module ActiveRecord end private - # We need to apply this decorator here, rather than on module inclusion. The closure # created by the matcher would otherwise evaluate for `ActiveRecord::Base`, not the # sub class being decorated. As such, changes to `lock_optimistically`, or diff --git a/activerecord/lib/active_record/middleware/database_selector.rb b/activerecord/lib/active_record/middleware/database_selector.rb index 93a1a39c3e..7374107048 100644 --- a/activerecord/lib/active_record/middleware/database_selector.rb +++ b/activerecord/lib/active_record/middleware/database_selector.rb @@ -55,7 +55,6 @@ module ActiveRecord end private - def select_database(request, &blk) context = context_klass.call(request) resolver = resolver_klass.call(context, options) diff --git a/activerecord/lib/active_record/middleware/database_selector/resolver.rb b/activerecord/lib/active_record/middleware/database_selector/resolver.rb index 80b8cd7cae..3eb1039c50 100644 --- a/activerecord/lib/active_record/middleware/database_selector/resolver.rb +++ b/activerecord/lib/active_record/middleware/database_selector/resolver.rb @@ -44,10 +44,9 @@ module ActiveRecord end private - def read_from_primary(&blk) - ActiveRecord::Base.connection.while_preventing_writes do - ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role) do + ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role) do + ActiveRecord::Base.connection_handler.while_preventing_writes do instrumenter.instrument("database_selector.active_record.read_from_primary") do yield end diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index f20edbeb93..9db017cded 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -494,9 +494,9 @@ module ActiveRecord # This migration will create the horses table for you on the way up, and # automatically figure out how to drop the table on the way down. # - # Some commands like +remove_column+ cannot be reversed. If you care to - # define how to move up and down in these cases, you should define the +up+ - # and +down+ methods as before. + # Some commands cannot be reversed. If you care to define how to move up + # and down in these cases, you should define the +up+ and +down+ methods + # as before. # # If a command cannot be reversed, an # <tt>ActiveRecord::IrreversibleMigration</tt> exception will be raised when @@ -568,7 +568,6 @@ module ActiveRecord end private - def connection ActiveRecord::Base.connection end @@ -885,13 +884,14 @@ module ActiveRecord def copy(destination, sources, options = {}) copied = [] + schema_migration = options[:schema_migration] || ActiveRecord::SchemaMigration FileUtils.mkdir_p(destination) unless File.exist?(destination) - destination_migrations = ActiveRecord::MigrationContext.new(destination).migrations + destination_migrations = ActiveRecord::MigrationContext.new(destination, schema_migration).migrations last = destination_migrations.last sources.each do |scope, path| - source_migrations = ActiveRecord::MigrationContext.new(path).migrations + source_migrations = ActiveRecord::MigrationContext.new(path, schema_migration).migrations source_migrations.each do |migration| source = File.binread(migration.filename) @@ -992,7 +992,6 @@ module ActiveRecord delegate :migrate, :announce, :write, :disable_ddl_transaction, to: :migration private - def migration @migration ||= load_migration end @@ -1014,10 +1013,11 @@ module ActiveRecord end class MigrationContext #:nodoc: - attr_reader :migrations_paths + attr_reader :migrations_paths, :schema_migration - def initialize(migrations_paths) + def initialize(migrations_paths, schema_migration) @migrations_paths = migrations_paths + @schema_migration = schema_migration end def migrate(target_version = nil, &block) @@ -1048,7 +1048,7 @@ module ActiveRecord migrations end - Migrator.new(:up, selected_migrations, target_version).migrate + Migrator.new(:up, selected_migrations, schema_migration, target_version).migrate end def down(target_version = nil) @@ -1058,20 +1058,20 @@ module ActiveRecord migrations end - Migrator.new(:down, selected_migrations, target_version).migrate + Migrator.new(:down, selected_migrations, schema_migration, target_version).migrate end def run(direction, target_version) - Migrator.new(direction, migrations, target_version).run + Migrator.new(direction, migrations, schema_migration, target_version).run end def open - Migrator.new(:up, migrations, nil) + Migrator.new(:up, migrations, schema_migration) end def get_all_versions - if SchemaMigration.table_exists? - SchemaMigration.all_versions.map(&:to_i) + if schema_migration.table_exists? + schema_migration.all_versions else [] end @@ -1108,12 +1108,12 @@ module ActiveRecord end def migrations_status - db_list = ActiveRecord::SchemaMigration.normalized_versions + db_list = schema_migration.normalized_versions file_list = migration_files.map do |file| version, name, scope = parse_migration_filename(file) raise IllegalMigrationNameError.new(file) unless version - version = ActiveRecord::SchemaMigration.normalize_migration_number(version) + version = schema_migration.normalize_migration_number(version) status = db_list.delete(version) ? "up" : "down" [status, version, (name + scope).humanize] end.compact @@ -1153,7 +1153,7 @@ module ActiveRecord end def move(direction, steps) - migrator = Migrator.new(direction, migrations) + migrator = Migrator.new(direction, migrations, schema_migration) if current_version != 0 && !migrator.current_migration raise UnknownMigrationVersionError.new(current_version) @@ -1172,27 +1172,28 @@ module ActiveRecord end end - class Migrator #:nodoc: + class Migrator # :nodoc: class << self attr_accessor :migrations_paths # For cases where a table doesn't exist like loading from schema cache def current_version - MigrationContext.new(migrations_paths).current_version + MigrationContext.new(migrations_paths, SchemaMigration).current_version end end self.migrations_paths = ["db/migrate"] - def initialize(direction, migrations, target_version = nil) + def initialize(direction, migrations, schema_migration, target_version = nil) @direction = direction @target_version = target_version @migrated_versions = nil @migrations = migrations + @schema_migration = schema_migration validate(@migrations) - ActiveRecord::SchemaMigration.create_table + @schema_migration.create_table ActiveRecord::InternalMetadata.create_table end @@ -1246,11 +1247,10 @@ module ActiveRecord end def load_migrated - @migrated_versions = Set.new(Base.connection.migration_context.get_all_versions) + @migrated_versions = Set.new(@schema_migration.all_versions) end private - # Used for running a specific migration. def run_without_lock migration = migrations.detect { |m| m.version == @target_version } @@ -1330,10 +1330,10 @@ module ActiveRecord def record_version_state_after_migrating(version) if down? migrated.delete(version) - ActiveRecord::SchemaMigration.delete_by(version: version.to_s) + @schema_migration.delete_by(version: version.to_s) else migrated << version - ActiveRecord::SchemaMigration.create!(version: version.to_s) + @schema_migration.create!(version: version.to_s) end end diff --git a/activerecord/lib/active_record/migration/command_recorder.rb b/activerecord/lib/active_record/migration/command_recorder.rb index efed4b0e26..67172ef395 100644 --- a/activerecord/lib/active_record/migration/command_recorder.rb +++ b/activerecord/lib/active_record/migration/command_recorder.rb @@ -118,7 +118,6 @@ module ActiveRecord end private - module StraightReversions # :nodoc: private { diff --git a/activerecord/lib/active_record/migration/join_table.rb b/activerecord/lib/active_record/migration/join_table.rb index 9abb289bb0..45169617c1 100644 --- a/activerecord/lib/active_record/migration/join_table.rb +++ b/activerecord/lib/active_record/migration/join_table.rb @@ -4,7 +4,6 @@ module ActiveRecord class Migration module JoinTable #:nodoc: private - def find_join_table_name(table_1, table_2, options = {}) options.delete(:table_name) || join_table_name(table_1, table_2) end diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb index 55fc58e339..2a45f63d64 100644 --- a/activerecord/lib/active_record/model_schema.rb +++ b/activerecord/lib/active_record/model_schema.rb @@ -456,13 +456,11 @@ module ActiveRecord end protected - def initialize_load_schema_monitor @load_schema_monitor = Monitor.new end private - def inherited(child_class) super child_class.initialize_load_schema_monitor diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb index 8b9098df6c..cab2369b71 100644 --- a/activerecord/lib/active_record/nested_attributes.rb +++ b/activerecord/lib/active_record/nested_attributes.rb @@ -354,7 +354,6 @@ module ActiveRecord end private - # Generates a writer method for this association. Serves as a point for # accessing the objects in the association. For example, this method # could generate the following: @@ -386,7 +385,6 @@ module ActiveRecord end private - # Attribute hash keys that should not be assigned as normal attributes. # These hash keys are nested attributes implementation details. UNASSIGNABLE_KEYS = %w( id _destroy ) diff --git a/activerecord/lib/active_record/null_relation.rb b/activerecord/lib/active_record/null_relation.rb index cf0de0fdeb..bee5b5f24a 100644 --- a/activerecord/lib/active_record/null_relation.rb +++ b/activerecord/lib/active_record/null_relation.rb @@ -60,7 +60,6 @@ module ActiveRecord end private - def exec_queries @records = [].freeze end diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index b7bc4b3b8e..323b01ab2d 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -865,7 +865,6 @@ module ActiveRecord end private - # A hook to be overridden by association modules. def destroy_associations end diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb index a1d7c893bf..d5375390c7 100644 --- a/activerecord/lib/active_record/railtie.rb +++ b/activerecord/lib/active_record/railtie.rb @@ -134,7 +134,6 @@ end_error cache = YAML.load(File.read(filename)) if cache.version == current_version - connection.schema_cache = cache connection_pool.schema_cache = cache.dup else warn "Ignoring db/schema_cache.yml because it has expired. The current schema version is #{current_version}, but the one in the cache is #{cache.version}." diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index e0bc5180c0..d17acc408c 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -250,7 +250,11 @@ db_namespace = namespace :db do # desc "Raises an error if there are pending migrations" task abort_if_pending_migrations: :load_config do - pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations + pending_migrations = ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).flat_map do |db_config| + ActiveRecord::Base.establish_connection(db_config.config) + + ActiveRecord::Base.connection.migration_context.open.pending_migrations + end if pending_migrations.any? puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}" @@ -261,17 +265,56 @@ db_namespace = namespace :db do end end + namespace :abort_if_pending_migrations do + ActiveRecord::Tasks::DatabaseTasks.for_each do |spec_name| + # desc "Raises an error if there are pending migrations for #{spec_name} database" + task spec_name => :load_config do + db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name) + ActiveRecord::Base.establish_connection(db_config.config) + + pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations + + if pending_migrations.any? + puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}" + pending_migrations.each do |pending_migration| + puts " %4d %s" % [pending_migration.version, pending_migration.name] + end + abort %{Run `rails db:migrate:#{spec_name}` to update your database then try again.} + end + end + end + end + desc "Creates the database, loads the schema, and initializes with the seed data (use db:reset to also drop the database first)" task setup: ["db:schema:load_if_ruby", "db:structure:load_if_sql", :seed] desc "Runs setup if database does not exist, or runs migrations if it does" task prepare: :load_config do + seed = false + ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config| ActiveRecord::Base.establish_connection(db_config.config) - db_namespace["migrate"].invoke + + ActiveRecord::Tasks::DatabaseTasks.migrate + + # Skipped when no database + ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config.config, ActiveRecord::Base.schema_format, db_config.spec_name) + rescue ActiveRecord::NoDatabaseError - db_namespace["setup"].invoke + ActiveRecord::Tasks::DatabaseTasks.create_current(db_config.env_name, db_config.spec_name) + ActiveRecord::Tasks::DatabaseTasks.load_schema( + db_config.config, + ActiveRecord::Base.schema_format, + nil, + db_config.env_name, + db_config.spec_name + ) + + seed = true end + + ActiveRecord::Base.establish_connection + ActiveRecord::Tasks::DatabaseTasks.load_seed if seed end desc "Loads the seed data from db/seeds.rb" @@ -336,13 +379,9 @@ db_namespace = namespace :db do namespace :schema do desc "Creates a db/schema.rb file that is portable against any DB supported by Active Record" task dump: :load_config do - require "active_record/schema_dumper" ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config| - filename = ActiveRecord::Tasks::DatabaseTasks.dump_filename(db_config.spec_name, :ruby) - File.open(filename, "w:utf-8") do |file| - ActiveRecord::Base.establish_connection(db_config.config) - ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file) - end + ActiveRecord::Base.establish_connection(db_config.config) + ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config.config, :ruby, db_config.spec_name) end db_namespace["schema:dump"].reenable @@ -385,14 +424,7 @@ db_namespace = namespace :db do task dump: :load_config do ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config| ActiveRecord::Base.establish_connection(db_config.config) - filename = ActiveRecord::Tasks::DatabaseTasks.dump_filename(db_config.spec_name, :sql) - ActiveRecord::Tasks::DatabaseTasks.structure_dump(db_config.config, filename) - if ActiveRecord::SchemaMigration.table_exists? - File.open(filename, "a") do |f| - f.puts ActiveRecord::Base.connection.dump_schema_information - f.print "\n" - end - end + ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config.config, :sql, db_config.spec_name) end db_namespace["structure:dump"].reenable diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index eefda2b8f4..cbfa60d4d9 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -590,7 +590,6 @@ module ActiveRecord end private - def calculate_constructable(macro, options) true end @@ -704,7 +703,6 @@ module ActiveRecord end private - def calculate_constructable(macro, options) !options[:through] end diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb index 9c579843b1..30b8edd0bd 100644 --- a/activerecord/lib/active_record/relation/batches.rb +++ b/activerecord/lib/active_record/relation/batches.rb @@ -258,7 +258,6 @@ module ActiveRecord end private - def apply_limits(relation, start, finish) relation = apply_start_limit(relation, start) if start relation = apply_finish_limit(relation, finish) if finish diff --git a/activerecord/lib/active_record/relation/delegation.rb b/activerecord/lib/active_record/relation/delegation.rb index d59331053e..2f61c05eca 100644 --- a/activerecord/lib/active_record/relation/delegation.rb +++ b/activerecord/lib/active_record/relation/delegation.rb @@ -99,7 +99,6 @@ module ActiveRecord end private - def method_missing(method, *args, &block) if @klass.respond_to?(method) @klass.generate_relation_method(method) @@ -116,7 +115,6 @@ module ActiveRecord end private - def relation_class_for(klass) klass.relation_delegate_class(self) end diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 9c7ac80447..6deb9c7da8 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -346,7 +346,6 @@ module ActiveRecord end private - def offset_index offset_value || 0 end diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb index 84fe424ef0..e1735c0522 100644 --- a/activerecord/lib/active_record/relation/merger.rb +++ b/activerecord/lib/active_record/relation/merger.rb @@ -89,7 +89,6 @@ module ActiveRecord end private - def merge_preloads return if other.preload_values.empty? && other.includes_values.empty? diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 50ff733dc7..87a53966e4 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -1159,8 +1159,9 @@ module ActiveRecord columns.flat_map do |field| case field when Symbol - field = field.to_s - arel_column(field, &connection.method(:quote_table_name)) + arel_column(field.to_s) do |attr_name| + connection.quote_table_name(attr_name) + end when String arel_column(field, &:itself) when Proc @@ -1247,6 +1248,7 @@ module ActiveRecord end def preprocess_order_args(order_args) + order_args.reject!(&:blank?) order_args.map! do |arg| klass.sanitize_sql_for_order(arg) end @@ -1254,7 +1256,7 @@ module ActiveRecord @klass.disallow_raw_sql!( order_args.flat_map { |a| a.is_a?(Hash) ? a.keys : a }, - permit: AttributeMethods::ClassMethods::COLUMN_NAME_WITH_ORDER + permit: connection.column_name_with_order_matcher ) validate_order_args(order_args) @@ -1267,20 +1269,14 @@ module ActiveRecord order_args.map! do |arg| case arg when Symbol - arg = arg.to_s - arel_column(arg) { - Arel.sql(connection.quote_table_name(arg)) - }.asc + order_column(arg.to_s).asc when Hash arg.map { |field, dir| case field when Arel::Nodes::SqlLiteral field.send(dir.downcase) else - field = field.to_s - arel_column(field) { - Arel.sql(connection.quote_table_name(field)) - }.send(dir.downcase) + order_column(field.to_s).send(dir.downcase) end } else @@ -1289,6 +1285,16 @@ module ActiveRecord end.flatten! end + def order_column(field) + arel_column(field) do |attr_name| + if attr_name == "count" && !group_values.empty? + arel_attribute(attr_name) + else + Arel.sql(connection.quote_table_name(attr_name)) + end + end + end + # Checks to make sure that the arguments are not blank. Note that if some # blank-like object were initially passed into the query method, then this # method will not raise an error. diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb index efc4b447aa..3f6dd50139 100644 --- a/activerecord/lib/active_record/relation/spawn_methods.rb +++ b/activerecord/lib/active_record/relation/spawn_methods.rb @@ -67,7 +67,6 @@ module ActiveRecord end private - def relation_with(values) result = Relation.create(klass, values: values) result.extend(*extending_values) if extending_values.any? diff --git a/activerecord/lib/active_record/relation/where_clause.rb b/activerecord/lib/active_record/relation/where_clause.rb index b91b135867..8fae380b0a 100644 --- a/activerecord/lib/active_record/relation/where_clause.rb +++ b/activerecord/lib/active_record/relation/where_clause.rb @@ -87,7 +87,6 @@ module ActiveRecord end protected - attr_reader :predicates def referenced_columns diff --git a/activerecord/lib/active_record/result.rb b/activerecord/lib/active_record/result.rb index da6d10b6ec..3b615f29a3 100644 --- a/activerecord/lib/active_record/result.rb +++ b/activerecord/lib/active_record/result.rb @@ -132,7 +132,6 @@ module ActiveRecord end private - def column_type(name, type_overrides = {}) type_overrides.fetch(name) do column_types.fetch(name, Type.default_value) diff --git a/activerecord/lib/active_record/sanitization.rb b/activerecord/lib/active_record/sanitization.rb index 750766714d..b16cbb0f84 100644 --- a/activerecord/lib/active_record/sanitization.rb +++ b/activerecord/lib/active_record/sanitization.rb @@ -61,8 +61,9 @@ module ActiveRecord # # => "id ASC" def sanitize_sql_for_order(condition) if condition.is_a?(Array) && condition.first.to_s.include?("?") - disallow_raw_sql!([condition.first], - permit: AttributeMethods::ClassMethods::COLUMN_NAME_WITH_ORDER + disallow_raw_sql!( + [condition.first], + permit: connection.column_name_with_order_matcher ) # Ensure we aren't dealing with a subclass of String that might @@ -133,6 +134,33 @@ module ActiveRecord end end + def disallow_raw_sql!(args, permit: connection.column_name_matcher) # :nodoc: + unexpected = nil + args.each do |arg| + next if arg.is_a?(Symbol) || Arel.arel_node?(arg) || permit.match?(arg.to_s) + (unexpected ||= []) << arg + end + + return unless unexpected + + if allow_unsafe_raw_sql == :deprecated + ActiveSupport::Deprecation.warn( + "Dangerous query method (method whose arguments are used as raw " \ + "SQL) called with non-attribute argument(s): " \ + "#{unexpected.map(&:inspect).join(", ")}. Non-attribute " \ + "arguments will be disallowed in Rails 6.1. This method should " \ + "not be called with user-provided values, such as request " \ + "parameters or model attributes. Known-safe values can be passed " \ + "by wrapping them in Arel.sql()." + ) + else + raise(ActiveRecord::UnknownAttributeReference, + "Query method called with non-attribute argument(s): " + + unexpected.map(&:inspect).join(", ") + ) + end + end + private def replace_bind_variables(statement, values) raise_if_bind_arity_mismatch(statement, statement.count("?"), values.size) diff --git a/activerecord/lib/active_record/schema.rb b/activerecord/lib/active_record/schema.rb index 76bf53387d..aba25fb375 100644 --- a/activerecord/lib/active_record/schema.rb +++ b/activerecord/lib/active_record/schema.rb @@ -50,7 +50,7 @@ module ActiveRecord instance_eval(&block) if info[:version].present? - ActiveRecord::SchemaMigration.create_table + connection.schema_migration.create_table connection.assume_migrated_upto_version(info[:version]) end diff --git a/activerecord/lib/active_record/schema_migration.rb b/activerecord/lib/active_record/schema_migration.rb index 74547de862..58b21d2cc8 100644 --- a/activerecord/lib/active_record/schema_migration.rb +++ b/activerecord/lib/active_record/schema_migration.rb @@ -22,10 +22,6 @@ module ActiveRecord "#{table_name_prefix}#{schema_migrations_table_name}#{table_name_suffix}" end - def table_exists? - connection.table_exists?(table_name) - end - def create_table unless table_exists? version_options = connection.internal_string_options_for_primary_key @@ -49,7 +45,7 @@ module ActiveRecord end def all_versions - order(:version).pluck(:version) + order(:version).pluck(:version).map(&:to_i) end end diff --git a/activerecord/lib/active_record/scoping.rb b/activerecord/lib/active_record/scoping.rb index 35e9dcbffc..62c7988bd8 100644 --- a/activerecord/lib/active_record/scoping.rb +++ b/activerecord/lib/active_record/scoping.rb @@ -95,7 +95,6 @@ module ActiveRecord end private - def raise_invalid_scope_type!(scope_type) if !VALID_SCOPE_TYPES.include?(scope_type) raise ArgumentError, "Invalid scope type '#{scope_type}' sent to the registry. Scope types must be included in VALID_SCOPE_TYPES" diff --git a/activerecord/lib/active_record/scoping/default.rb b/activerecord/lib/active_record/scoping/default.rb index 87bcfd5181..151eef362b 100644 --- a/activerecord/lib/active_record/scoping/default.rb +++ b/activerecord/lib/active_record/scoping/default.rb @@ -44,7 +44,6 @@ module ActiveRecord end private - # Use this macro in your model to set a default scope for all operations on # the model. # diff --git a/activerecord/lib/active_record/scoping/named.rb b/activerecord/lib/active_record/scoping/named.rb index cd9801b7a0..7baef99e83 100644 --- a/activerecord/lib/active_record/scoping/named.rb +++ b/activerecord/lib/active_record/scoping/named.rb @@ -204,7 +204,6 @@ module ActiveRecord end private - def valid_scope_name?(name) if respond_to?(name, true) && logger logger.warn "Creating scope :#{name}. " \ diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb index c79ed8db60..aecc9350e8 100644 --- a/activerecord/lib/active_record/tasks/database_tasks.rb +++ b/activerecord/lib/active_record/tasks/database_tasks.rb @@ -169,8 +169,8 @@ module ActiveRecord end end - def create_current(environment = env) - each_current_configuration(environment) { |configuration| + def create_current(environment = env, spec_name = nil) + each_current_configuration(environment, spec_name) { |configuration| create configuration } ActiveRecord::Base.establish_connection(environment.to_sym) @@ -200,9 +200,10 @@ module ActiveRecord def truncate_tables(configuration) ActiveRecord::Base.connected_to(database: { truncation: configuration }) do - table_names = ActiveRecord::Base.connection.tables + conn = ActiveRecord::Base.connection + table_names = conn.tables table_names -= [ - SchemaMigration.table_name, + conn.schema_migration.table_name, InternalMetadata.table_name ] @@ -233,7 +234,7 @@ module ActiveRecord end def migrate_status - unless ActiveRecord::SchemaMigration.table_exists? + unless ActiveRecord::Base.connection.schema_migration.table_exists? Kernel.abort "Schema migrations table does not exist yet." end @@ -325,6 +326,27 @@ module ActiveRecord Migration.verbose = verbose_was end + def dump_schema(configuration, format = ActiveRecord::Base.schema_format, spec_name = "primary") # :nodoc: + require "active_record/schema_dumper" + filename = dump_filename(spec_name, format) + connection = ActiveRecord::Base.connection + + case format + when :ruby + File.open(filename, "w:utf-8") do |file| + ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file) + end + when :sql + structure_dump(configuration, filename) + if connection.schema_migration.table_exists? + File.open(filename, "a") do |f| + f.puts connection.dump_schema_information + f.print "\n" + end + end + end + end + def schema_file(format = ActiveRecord::Base.schema_format) File.join(db_dir, schema_file_type(format)) end @@ -406,12 +428,14 @@ module ActiveRecord task.is_a?(String) ? task.constantize : task end - def each_current_configuration(environment) + def each_current_configuration(environment, spec_name = nil) environments = [environment] environments << "test" if environment == "development" environments.each do |env| ActiveRecord::Base.configurations.configs_for(env_name: env).each do |db_config| + next if spec_name && spec_name != db_config.spec_name + yield db_config.config, db_config.spec_name, env end end diff --git a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb index 1c1b29b5e1..0d9917a4db 100644 --- a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb +++ b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb @@ -67,7 +67,6 @@ module ActiveRecord end private - attr_reader :configuration def configuration_without_database diff --git a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb index 8acb11f75f..626ffdfdf9 100644 --- a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb +++ b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb @@ -89,7 +89,6 @@ module ActiveRecord end private - attr_reader :configuration def encoding diff --git a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb index a82cea80ca..f67a3498b6 100644 --- a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb +++ b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb @@ -59,7 +59,6 @@ module ActiveRecord end private - attr_reader :configuration, :root def run_cmd(cmd, args, out) diff --git a/activerecord/lib/active_record/test_fixtures.rb b/activerecord/lib/active_record/test_fixtures.rb index 8c60d71669..1d6fef1eb9 100644 --- a/activerecord/lib/active_record/test_fixtures.rb +++ b/activerecord/lib/active_record/test_fixtures.rb @@ -179,7 +179,6 @@ module ActiveRecord end private - # Shares the writing connection pool with connections on # other handlers. # diff --git a/activerecord/lib/active_record/timestamp.rb b/activerecord/lib/active_record/timestamp.rb index a5862ae06b..c883d368b5 100644 --- a/activerecord/lib/active_record/timestamp.rb +++ b/activerecord/lib/active_record/timestamp.rb @@ -96,7 +96,6 @@ module ActiveRecord end private - def _create_record if record_timestamps current_time = current_time_from_proper_timezone diff --git a/activerecord/lib/active_record/touch_later.rb b/activerecord/lib/active_record/touch_later.rb index bc63c8d987..3981bd46ad 100644 --- a/activerecord/lib/active_record/touch_later.rb +++ b/activerecord/lib/active_record/touch_later.rb @@ -36,7 +36,6 @@ module ActiveRecord end private - def surreptitiously_touch(attrs) attrs.each { |attr| write_attribute attr, @_touch_time } clear_attribute_changes attrs diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index cbb970ac98..5113e08e8e 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -282,7 +282,6 @@ module ActiveRecord end private - def set_options_for_callbacks!(args, enforced_options = {}) options = args.extract_options!.merge!(enforced_options) args << options diff --git a/activerecord/lib/active_record/type.rb b/activerecord/lib/active_record/type.rb index 03d00006b7..4c1ef1a7e4 100644 --- a/activerecord/lib/active_record/type.rb +++ b/activerecord/lib/active_record/type.rb @@ -47,7 +47,6 @@ module ActiveRecord end private - def current_adapter_name ActiveRecord::Base.connection.adapter_name.downcase.to_sym end diff --git a/activerecord/lib/active_record/type/adapter_specific_registry.rb b/activerecord/lib/active_record/type/adapter_specific_registry.rb index b300fdfa05..c8c16635b1 100644 --- a/activerecord/lib/active_record/type/adapter_specific_registry.rb +++ b/activerecord/lib/active_record/type/adapter_specific_registry.rb @@ -11,7 +11,6 @@ module ActiveRecord end private - def registration_klass Registration end @@ -53,7 +52,6 @@ module ActiveRecord end protected - attr_reader :name, :block, :adapter, :override def priority @@ -72,7 +70,6 @@ module ActiveRecord end private - def matches_adapter?(adapter: nil, **) (self.adapter.nil? || adapter == self.adapter) end diff --git a/activerecord/lib/active_record/type/hash_lookup_type_map.rb b/activerecord/lib/active_record/type/hash_lookup_type_map.rb index db9853fbcc..b260464df5 100644 --- a/activerecord/lib/active_record/type/hash_lookup_type_map.rb +++ b/activerecord/lib/active_record/type/hash_lookup_type_map.rb @@ -16,7 +16,6 @@ module ActiveRecord end private - def perform_fetch(type, *args, &block) @mapping.fetch(type, block).call(type, *args) end diff --git a/activerecord/lib/active_record/type/serialized.rb b/activerecord/lib/active_record/type/serialized.rb index 0a2f6cb9fb..a34b2fe702 100644 --- a/activerecord/lib/active_record/type/serialized.rb +++ b/activerecord/lib/active_record/type/serialized.rb @@ -56,7 +56,6 @@ module ActiveRecord end private - def default_value?(value) value == coder.load(nil) end diff --git a/activerecord/lib/active_record/type/type_map.rb b/activerecord/lib/active_record/type/type_map.rb index fc40b460f0..58f25ba075 100644 --- a/activerecord/lib/active_record/type/type_map.rb +++ b/activerecord/lib/active_record/type/type_map.rb @@ -45,7 +45,6 @@ module ActiveRecord end private - def perform_fetch(lookup_key, *args) matching_pair = @mapping.reverse_each.detect do |key, _| key === lookup_key diff --git a/activerecord/lib/active_record/type/unsigned_integer.rb b/activerecord/lib/active_record/type/unsigned_integer.rb index 4619528f81..535369e630 100644 --- a/activerecord/lib/active_record/type/unsigned_integer.rb +++ b/activerecord/lib/active_record/type/unsigned_integer.rb @@ -4,7 +4,6 @@ module ActiveRecord module Type class UnsignedInteger < ActiveModel::Type::Integer # :nodoc: private - def max_value super * 2 end diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index ca27a3f0ab..23e8d53168 100644 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -71,7 +71,6 @@ module ActiveRecord alias_method :validate, :valid? private - def default_validation_context new_record? ? :create : :update end diff --git a/activerecord/lib/active_record/validations/associated.rb b/activerecord/lib/active_record/validations/associated.rb index 3538aeec22..dc89df4be7 100644 --- a/activerecord/lib/active_record/validations/associated.rb +++ b/activerecord/lib/active_record/validations/associated.rb @@ -10,7 +10,6 @@ module ActiveRecord end private - def valid_object?(record) (record.respond_to?(:marked_for_destruction?) && record.marked_for_destruction?) || record.valid? end diff --git a/activerecord/lib/arel.rb b/activerecord/lib/arel.rb index 361cd915cc..0fc07e1ede 100644 --- a/activerecord/lib/arel.rb +++ b/activerecord/lib/arel.rb @@ -12,7 +12,7 @@ require "arel/math" require "arel/alias_predication" require "arel/order_predications" require "arel/table" -require "arel/attributes" +require "arel/attributes/attribute" require "arel/visitors" require "arel/collectors/sql_string" diff --git a/activerecord/lib/arel/attributes.rb b/activerecord/lib/arel/attributes.rb deleted file mode 100644 index 35d586c948..0000000000 --- a/activerecord/lib/arel/attributes.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -require "arel/attributes/attribute" - -module Arel # :nodoc: all - module Attributes - ### - # Factory method to wrap a raw database +column+ to an Arel Attribute. - def self.for(column) - case column.type - when :string, :text, :binary then String - when :integer then Integer - when :float then Float - when :decimal then Decimal - when :date, :datetime, :timestamp, :time then Time - when :boolean then Boolean - else - Undefined - end - end - end -end diff --git a/activerecord/lib/arel/predications.rb b/activerecord/lib/arel/predications.rb index 7dafde4952..dece478615 100644 --- a/activerecord/lib/arel/predications.rb +++ b/activerecord/lib/arel/predications.rb @@ -221,7 +221,6 @@ Passing a range to `#not_in` is deprecated. Call `#not_between`, instead. end private - def grouping_any(method_id, others, *extras) nodes = others.map { |expr| send(method_id, expr, *extras) } Nodes::Grouping.new nodes.inject { |memo, node| diff --git a/activerecord/lib/arel/visitors/depth_first.rb b/activerecord/lib/arel/visitors/depth_first.rb index d696edc507..98c3f92cf1 100644 --- a/activerecord/lib/arel/visitors/depth_first.rb +++ b/activerecord/lib/arel/visitors/depth_first.rb @@ -9,8 +9,7 @@ module Arel # :nodoc: all end private - - def visit(o) + def visit(o, _ = nil) super @block.call o end diff --git a/activerecord/lib/arel/visitors/dot.rb b/activerecord/lib/arel/visitors/dot.rb index ecc386de07..c4ea07bcfe 100644 --- a/activerecord/lib/arel/visitors/dot.rb +++ b/activerecord/lib/arel/visitors/dot.rb @@ -31,7 +31,6 @@ module Arel # :nodoc: all end private - def visit_Arel_Nodes_Ordering(o) visit_edge o, "expr" end diff --git a/activerecord/lib/arel/visitors/mssql.rb b/activerecord/lib/arel/visitors/mssql.rb index 8475139870..92eb94f802 100644 --- a/activerecord/lib/arel/visitors/mssql.rb +++ b/activerecord/lib/arel/visitors/mssql.rb @@ -11,7 +11,6 @@ module Arel # :nodoc: all end private - def visit_Arel_Nodes_IsNotDistinctFrom(o, collector) right = o.right diff --git a/activerecord/lib/arel/visitors/oracle.rb b/activerecord/lib/arel/visitors/oracle.rb index f96bf65ee5..aab66301ef 100644 --- a/activerecord/lib/arel/visitors/oracle.rb +++ b/activerecord/lib/arel/visitors/oracle.rb @@ -4,7 +4,6 @@ module Arel # :nodoc: all module Visitors class Oracle < Arel::Visitors::ToSql private - def visit_Arel_Nodes_SelectStatement(o, collector) o = order_hacks(o) diff --git a/activerecord/lib/arel/visitors/oracle12.rb b/activerecord/lib/arel/visitors/oracle12.rb index 6269bc3907..36783243b5 100644 --- a/activerecord/lib/arel/visitors/oracle12.rb +++ b/activerecord/lib/arel/visitors/oracle12.rb @@ -4,7 +4,6 @@ module Arel # :nodoc: all module Visitors class Oracle12 < Arel::Visitors::ToSql private - def visit_Arel_Nodes_SelectStatement(o, collector) # Oracle does not allow LIMIT clause with select for update if o.limit && o.lock diff --git a/activerecord/lib/arel/visitors/postgresql.rb b/activerecord/lib/arel/visitors/postgresql.rb index 8296f1cdc1..d4f21ff93e 100644 --- a/activerecord/lib/arel/visitors/postgresql.rb +++ b/activerecord/lib/arel/visitors/postgresql.rb @@ -4,7 +4,6 @@ module Arel # :nodoc: all module Visitors class PostgreSQL < Arel::Visitors::ToSql private - def visit_Arel_Nodes_Matches(o, collector) op = o.case_sensitive ? " LIKE " : " ILIKE " collector = infix_value o, collector, op diff --git a/activerecord/lib/arel/visitors/sqlite.rb b/activerecord/lib/arel/visitors/sqlite.rb index af6f7e856a..62ec74ad82 100644 --- a/activerecord/lib/arel/visitors/sqlite.rb +++ b/activerecord/lib/arel/visitors/sqlite.rb @@ -4,7 +4,6 @@ module Arel # :nodoc: all module Visitors class SQLite < Arel::Visitors::ToSql private - # Locks are not supported in SQLite def visit_Arel_Nodes_Lock(o, collector) collector diff --git a/activerecord/lib/arel/visitors/to_sql.rb b/activerecord/lib/arel/visitors/to_sql.rb index 4740e6d94f..eff7a0d036 100644 --- a/activerecord/lib/arel/visitors/to_sql.rb +++ b/activerecord/lib/arel/visitors/to_sql.rb @@ -19,7 +19,6 @@ module Arel # :nodoc: all end private - def visit_Arel_Nodes_DeleteStatement(o, collector) o = prepare_delete_statement(o) @@ -52,10 +51,14 @@ module Arel # :nodoc: all def visit_Arel_Nodes_InsertStatement(o, collector) collector << "INSERT INTO " collector = visit o.relation, collector - if o.columns.any? - collector << " (#{o.columns.map { |x| - quote_column_name x.name - }.join ', '})" + + unless o.columns.empty? + collector << " (" + o.columns.each_with_index do |x, i| + collector << ", " unless i == 0 + collector << quote_column_name(x.name) + end + collector << ")" end if o.values @@ -97,22 +100,20 @@ module Arel # :nodoc: all def visit_Arel_Nodes_ValuesList(o, collector) collector << "VALUES " - len = o.rows.length - 1 - o.rows.each_with_index { |row, i| + o.rows.each_with_index do |row, i| + collector << ", " unless i == 0 collector << "(" - row_len = row.length - 1 row.each_with_index do |value, k| + collector << ", " unless k == 0 case value when Nodes::SqlLiteral, Nodes::BindParam collector = visit(value, collector) else collector << quote(value).to_s end - collector << ", " unless k == row_len end collector << ")" - collector << ", " unless i == len - } + end collector end @@ -128,11 +129,10 @@ module Arel # :nodoc: all unless o.orders.empty? collector << " ORDER BY " - len = o.orders.length - 1 - o.orders.each_with_index { |x, i| + o.orders.each_with_index do |x, i| + collector << ", " unless i == 0 collector = visit(x, collector) - collector << ", " unless len == i - } + end end visit_Arel_Nodes_SelectOptions(o, collector) @@ -506,7 +506,7 @@ module Arel # :nodoc: all def visit_Arel_Table(o, collector) if o.table_alias - collector << "#{quote_table_name o.name} #{quote_table_name o.table_alias}" + collector << quote_table_name(o.name) << " " << quote_table_name(o.table_alias) else collector << quote_table_name(o.name) end @@ -682,20 +682,13 @@ module Arel # :nodoc: all end def visit_Arel_Nodes_UnqualifiedColumn(o, collector) - collector << "#{quote_column_name o.name}" - collector + collector << quote_column_name(o.name) end def visit_Arel_Attributes_Attribute(o, collector) join_name = o.relation.table_alias || o.relation.name - collector << "#{quote_table_name join_name}.#{quote_column_name o.name}" + collector << quote_table_name(join_name) << "." << quote_column_name(o.name) end - alias :visit_Arel_Attributes_Integer :visit_Arel_Attributes_Attribute - alias :visit_Arel_Attributes_Float :visit_Arel_Attributes_Attribute - alias :visit_Arel_Attributes_Decimal :visit_Arel_Attributes_Attribute - alias :visit_Arel_Attributes_String :visit_Arel_Attributes_Attribute - alias :visit_Arel_Attributes_Time :visit_Arel_Attributes_Attribute - alias :visit_Arel_Attributes_Boolean :visit_Arel_Attributes_Attribute def literal(o, collector); collector << o.to_s; end @@ -785,14 +778,11 @@ module Arel # :nodoc: all end def inject_join(list, collector, join_str) - len = list.length - 1 - list.each_with_index.inject(collector) { |c, (x, i)| - if i == len - visit x, c - else - visit(x, c) << join_str - end - } + list.each_with_index do |x, i| + collector << join_str unless i == 0 + collector = visit(x, collector) + end + collector end def unboundable?(value) diff --git a/activerecord/lib/arel/visitors/visitor.rb b/activerecord/lib/arel/visitors/visitor.rb index 1c17184e86..d65ac820bc 100644 --- a/activerecord/lib/arel/visitors/visitor.rb +++ b/activerecord/lib/arel/visitors/visitor.rb @@ -7,12 +7,11 @@ module Arel # :nodoc: all @dispatch = get_dispatch_cache end - def accept(object, *args) - visit object, *args + def accept(object, collector = nil) + visit object, collector end private - attr_reader :dispatch def self.dispatch_cache @@ -25,9 +24,13 @@ module Arel # :nodoc: all self.class.dispatch_cache end - def visit(object, *args) + def visit(object, collector = nil) dispatch_method = dispatch[object.class] - send dispatch_method, object, *args + if collector + send dispatch_method, object, collector + else + send dispatch_method, object + end rescue NoMethodError => e raise e if respond_to?(dispatch_method, true) superklass = object.class.ancestors.find { |klass| diff --git a/activerecord/lib/arel/visitors/where_sql.rb b/activerecord/lib/arel/visitors/where_sql.rb index c6caf5e7c9..8fb299d1c8 100644 --- a/activerecord/lib/arel/visitors/where_sql.rb +++ b/activerecord/lib/arel/visitors/where_sql.rb @@ -9,7 +9,6 @@ module Arel # :nodoc: all end private - def visit_Arel_Nodes_SelectCore(o, collector) collector << "WHERE " wheres = o.wheres.map do |where| diff --git a/activerecord/lib/rails/generators/active_record/application_record/application_record_generator.rb b/activerecord/lib/rails/generators/active_record/application_record/application_record_generator.rb index 35d5664400..56b9628a92 100644 --- a/activerecord/lib/rails/generators/active_record/application_record/application_record_generator.rb +++ b/activerecord/lib/rails/generators/active_record/application_record/application_record_generator.rb @@ -13,7 +13,6 @@ module ActiveRecord end private - def application_record_file_name @application_record_file_name ||= if namespaced? diff --git a/activerecord/lib/rails/generators/active_record/migration.rb b/activerecord/lib/rails/generators/active_record/migration.rb index cbb88d571d..af753071a9 100644 --- a/activerecord/lib/rails/generators/active_record/migration.rb +++ b/activerecord/lib/rails/generators/active_record/migration.rb @@ -17,7 +17,6 @@ module ActiveRecord end private - def primary_key_type key_type = options[:primary_key_type] ", id: :#{key_type}" if key_type diff --git a/activerecord/lib/rails/generators/active_record/model/model_generator.rb b/activerecord/lib/rails/generators/active_record/model/model_generator.rb index c71bbdcab8..d4733f948f 100644 --- a/activerecord/lib/rails/generators/active_record/model/model_generator.rb +++ b/activerecord/lib/rails/generators/active_record/model/model_generator.rb @@ -35,7 +35,6 @@ module ActiveRecord hook_for :test_framework private - def attributes_with_index attributes.select { |a| !a.reference? && a.has_index? } end diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index ce2ed06c1d..0bc617edbe 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -12,6 +12,7 @@ module ActiveRecord def setup @connection = ActiveRecord::Base.connection @connection.materialize_transactions + @connection_handler = ActiveRecord::Base.connection_handler end ## @@ -166,7 +167,7 @@ module ActiveRecord def test_preventing_writes_predicate assert_not_predicate @connection, :preventing_writes? - @connection.while_preventing_writes do + @connection_handler.while_preventing_writes do assert_predicate @connection, :preventing_writes? end @@ -176,7 +177,7 @@ module ActiveRecord def test_errors_when_an_insert_query_is_called_while_preventing_writes assert_no_queries do assert_raises(ActiveRecord::ReadOnlyError) do - @connection.while_preventing_writes do + @connection_handler.while_preventing_writes do @connection.transaction do @connection.insert("INSERT INTO subscribers(nick) VALUES ('138853948594')", nil, false) end @@ -190,7 +191,7 @@ module ActiveRecord assert_no_queries do assert_raises(ActiveRecord::ReadOnlyError) do - @connection.while_preventing_writes do + @connection_handler.while_preventing_writes do @connection.transaction do @connection.update("UPDATE subscribers SET nick = '9989' WHERE nick = '138853948594'") end @@ -204,7 +205,7 @@ module ActiveRecord assert_no_queries do assert_raises(ActiveRecord::ReadOnlyError) do - @connection.while_preventing_writes do + @connection_handler.while_preventing_writes do @connection.transaction do @connection.delete("DELETE FROM subscribers WHERE nick = '138853948594'") end @@ -216,7 +217,7 @@ module ActiveRecord def test_doesnt_error_when_a_select_query_is_called_while_preventing_writes @connection.insert("INSERT INTO subscribers(nick) VALUES ('138853948594')") - @connection.while_preventing_writes do + @connection_handler.while_preventing_writes do result = @connection.select_all("SELECT subscribers.* FROM subscribers WHERE nick = '138853948594'") assert_equal 1, result.length end @@ -559,7 +560,6 @@ module ActiveRecord end private - def reset_fixtures(*fixture_names) ActiveRecord::FixtureSet.reset_cache diff --git a/activerecord/test/cases/adapters/mysql2/connection_test.rb b/activerecord/test/cases/adapters/mysql2/connection_test.rb index 9c6566106a..cb7461a8d5 100644 --- a/activerecord/test/cases/adapters/mysql2/connection_test.rb +++ b/activerecord/test/cases/adapters/mysql2/connection_test.rb @@ -197,7 +197,6 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase end private - def test_lock_free(lock_name) @connection.select_value("SELECT IS_FREE_LOCK(#{@connection.quote(lock_name)})") == 1 end diff --git a/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb b/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb index 6ade2eec24..e1f7a0b7c5 100644 --- a/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb +++ b/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb @@ -8,6 +8,7 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase def setup @conn = ActiveRecord::Base.connection + @connection_handler = ActiveRecord::Base.connection_handler end def test_exec_query_nothing_raises_with_no_result_queries @@ -148,7 +149,7 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase def test_errors_when_an_insert_query_is_called_while_preventing_writes assert_raises(ActiveRecord::ReadOnlyError) do - @conn.while_preventing_writes do + @connection_handler.while_preventing_writes do @conn.insert("INSERT INTO `engines` (`car_id`) VALUES ('138853948594')") end end @@ -158,7 +159,7 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase @conn.insert("INSERT INTO `engines` (`car_id`) VALUES ('138853948594')") assert_raises(ActiveRecord::ReadOnlyError) do - @conn.while_preventing_writes do + @connection_handler.while_preventing_writes do @conn.update("UPDATE `engines` SET `engines`.`car_id` = '9989' WHERE `engines`.`car_id` = '138853948594'") end end @@ -168,7 +169,7 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase @conn.execute("INSERT INTO `engines` (`car_id`) VALUES ('138853948594')") assert_raises(ActiveRecord::ReadOnlyError) do - @conn.while_preventing_writes do + @connection_handler.while_preventing_writes do @conn.execute("DELETE FROM `engines` where `engines`.`car_id` = '138853948594'") end end @@ -178,7 +179,7 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase @conn.execute("INSERT INTO `engines` (`car_id`) VALUES ('138853948594')") assert_raises(ActiveRecord::ReadOnlyError) do - @conn.while_preventing_writes do + @connection_handler.while_preventing_writes do @conn.execute("REPLACE INTO `engines` SET `engines`.`car_id` = '249823948'") end end @@ -187,19 +188,19 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase def test_doesnt_error_when_a_select_query_is_called_while_preventing_writes @conn.execute("INSERT INTO `engines` (`car_id`) VALUES ('138853948594')") - @conn.while_preventing_writes do + @connection_handler.while_preventing_writes do assert_equal 1, @conn.execute("SELECT `engines`.* FROM `engines` WHERE `engines`.`car_id` = '138853948594'").entries.count end end def test_doesnt_error_when_a_show_query_is_called_while_preventing_writes - @conn.while_preventing_writes do + @connection_handler.while_preventing_writes do assert_equal 2, @conn.execute("SHOW FULL FIELDS FROM `engines`").entries.count end end def test_doesnt_error_when_a_set_query_is_called_while_preventing_writes - @conn.while_preventing_writes do + @connection_handler.while_preventing_writes do assert_nil @conn.execute("SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci") end end @@ -207,13 +208,12 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase def test_doesnt_error_when_a_read_query_with_leading_chars_is_called_while_preventing_writes @conn.execute("INSERT INTO `engines` (`car_id`) VALUES ('138853948594')") - @conn.while_preventing_writes do + @connection_handler.while_preventing_writes do assert_equal 1, @conn.execute("(\n( SELECT `engines`.* FROM `engines` WHERE `engines`.`car_id` = '138853948594' ) )").entries.count end end private - def with_example_table(definition = "id int auto_increment primary key, number int, data varchar(255)", &block) super(@conn, "ex", definition, &block) end diff --git a/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb b/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb index d7d9a2d732..182d5a3e58 100644 --- a/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb +++ b/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb @@ -40,7 +40,6 @@ class SchemaMigrationsTest < ActiveRecord::Mysql2TestCase end private - def with_encoding_utf8mb4 database_name = connection.current_database database_info = connection.select_one("SELECT * FROM information_schema.schemata WHERE schema_name = '#{database_name}'") diff --git a/activerecord/test/cases/adapters/mysql2/table_options_test.rb b/activerecord/test/cases/adapters/mysql2/table_options_test.rb index 1c92df940f..13cf1daa08 100644 --- a/activerecord/test/cases/adapters/mysql2/table_options_test.rb +++ b/activerecord/test/cases/adapters/mysql2/table_options_test.rb @@ -73,7 +73,7 @@ class Mysql2DefaultEngineOptionSchemaDumpTest < ActiveRecord::Mysql2TestCase end end.new - ActiveRecord::Migrator.new(:up, [migration]).migrate + ActiveRecord::Migrator.new(:up, [migration], ActiveRecord::Base.connection.schema_migration).migrate output = dump_table_schema("mysql_table_options") options = %r{create_table "mysql_table_options", options: "(?<options>.*)"}.match(output)[:options] @@ -112,7 +112,7 @@ class Mysql2DefaultEngineOptionSqlOutputTest < ActiveRecord::Mysql2TestCase end end.new - ActiveRecord::Migrator.new(:up, [migration]).migrate + ActiveRecord::Migrator.new(:up, [migration], ActiveRecord::Base.connection.schema_migration).migrate assert_match %r{ENGINE=InnoDB}, @log.string end diff --git a/activerecord/test/cases/adapters/postgresql/connection_test.rb b/activerecord/test/cases/adapters/postgresql/connection_test.rb index 9494863a75..dcee4fd22d 100644 --- a/activerecord/test/cases/adapters/postgresql/connection_test.rb +++ b/activerecord/test/cases/adapters/postgresql/connection_test.rb @@ -239,7 +239,6 @@ module ActiveRecord end private - def with_warning_suppression log_level = @connection.client_min_messages @connection.client_min_messages = "error" diff --git a/activerecord/test/cases/adapters/postgresql/extension_migration_test.rb b/activerecord/test/cases/adapters/postgresql/extension_migration_test.rb index 0fd7b2c6ed..16baa8933d 100644 --- a/activerecord/test/cases/adapters/postgresql/extension_migration_test.rb +++ b/activerecord/test/cases/adapters/postgresql/extension_migration_test.rb @@ -27,20 +27,20 @@ class PostgresqlExtensionMigrationTest < ActiveRecord::PostgreSQLTestCase ActiveRecord::Base.table_name_prefix = "p_" ActiveRecord::Base.table_name_suffix = "_s" - ActiveRecord::SchemaMigration.reset_table_name + @connection.schema_migration.reset_table_name ActiveRecord::InternalMetadata.reset_table_name - ActiveRecord::SchemaMigration.delete_all rescue nil + @connection.schema_migration.delete_all rescue nil ActiveRecord::Migration.verbose = false end def teardown - ActiveRecord::SchemaMigration.delete_all rescue nil + @connection.schema_migration.delete_all rescue nil ActiveRecord::Migration.verbose = true ActiveRecord::Base.table_name_prefix = @old_table_name_prefix ActiveRecord::Base.table_name_suffix = @old_table_name_suffix - ActiveRecord::SchemaMigration.reset_table_name + @connection.schema_migration.reset_table_name ActiveRecord::InternalMetadata.reset_table_name super @@ -50,7 +50,7 @@ class PostgresqlExtensionMigrationTest < ActiveRecord::PostgreSQLTestCase @connection.disable_extension("hstore") migrations = [EnableHstore.new(nil, 1)] - ActiveRecord::Migrator.new(:up, migrations).migrate + ActiveRecord::Migrator.new(:up, migrations, ActiveRecord::Base.connection.schema_migration).migrate assert @connection.extension_enabled?("hstore"), "extension hstore should be enabled" end @@ -58,7 +58,7 @@ class PostgresqlExtensionMigrationTest < ActiveRecord::PostgreSQLTestCase @connection.enable_extension("hstore") migrations = [DisableHstore.new(nil, 1)] - ActiveRecord::Migrator.new(:up, migrations).migrate + ActiveRecord::Migrator.new(:up, migrations, ActiveRecord::Base.connection.schema_migration).migrate assert_not @connection.extension_enabled?("hstore"), "extension hstore should not be enabled" end end diff --git a/activerecord/test/cases/adapters/postgresql/geometric_test.rb b/activerecord/test/cases/adapters/postgresql/geometric_test.rb index 14c262f4ce..f312b6e23d 100644 --- a/activerecord/test/cases/adapters/postgresql/geometric_test.rb +++ b/activerecord/test/cases/adapters/postgresql/geometric_test.rb @@ -361,7 +361,6 @@ class PostgreSQLGeometricTypesTest < ActiveRecord::PostgreSQLTestCase end private - def assert_column_exists(column_name) assert connection.column_exists?(table_name, column_name) end diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb index fbd3cbf90f..68bc87eaf8 100644 --- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb +++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb @@ -13,6 +13,7 @@ module ActiveRecord def setup @connection = ActiveRecord::Base.connection + @connection_handler = ActiveRecord::Base.connection_handler end def test_bad_connection @@ -379,7 +380,7 @@ module ActiveRecord def test_errors_when_an_insert_query_is_called_while_preventing_writes with_example_table do assert_raises(ActiveRecord::ReadOnlyError) do - @connection.while_preventing_writes do + @connection_handler.while_preventing_writes do @connection.execute("INSERT INTO ex (data) VALUES ('138853948594')") end end @@ -391,7 +392,7 @@ module ActiveRecord @connection.execute("INSERT INTO ex (data) VALUES ('138853948594')") assert_raises(ActiveRecord::ReadOnlyError) do - @connection.while_preventing_writes do + @connection_handler.while_preventing_writes do @connection.execute("UPDATE ex SET data = '9989' WHERE data = '138853948594'") end end @@ -403,7 +404,7 @@ module ActiveRecord @connection.execute("INSERT INTO ex (data) VALUES ('138853948594')") assert_raises(ActiveRecord::ReadOnlyError) do - @connection.while_preventing_writes do + @connection_handler.while_preventing_writes do @connection.execute("DELETE FROM ex where data = '138853948594'") end end @@ -414,20 +415,20 @@ module ActiveRecord with_example_table do @connection.execute("INSERT INTO ex (data) VALUES ('138853948594')") - @connection.while_preventing_writes do + @connection_handler.while_preventing_writes do assert_equal 1, @connection.execute("SELECT * FROM ex WHERE data = '138853948594'").entries.count end end end def test_doesnt_error_when_a_show_query_is_called_while_preventing_writes - @connection.while_preventing_writes do + @connection_handler.while_preventing_writes do assert_equal 1, @connection.execute("SHOW TIME ZONE").entries.count end end def test_doesnt_error_when_a_set_query_is_called_while_preventing_writes - @connection.while_preventing_writes do + @connection_handler.while_preventing_writes do assert_equal [], @connection.execute("SET standard_conforming_strings = on").entries end end @@ -436,14 +437,13 @@ module ActiveRecord with_example_table do @connection.execute("INSERT INTO ex (data) VALUES ('138853948594')") - @connection.while_preventing_writes do + @connection_handler.while_preventing_writes do assert_equal 1, @connection.execute("(\n( SELECT * FROM ex WHERE data = '138853948594' ) )").entries.count end end end private - def with_example_table(definition = "id serial primary key, number integer, data character varying(255)", &block) super(@connection, "ex", definition, &block) end diff --git a/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb b/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb index 96cfabf58f..a4f722c063 100644 --- a/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb +++ b/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb @@ -106,7 +106,6 @@ class PostgreSQLReferentialIntegrityTest < ActiveRecord::PostgreSQLTestCase end private - def assert_transaction_is_not_broken assert_equal 1, @connection.select_value("SELECT 1") end diff --git a/activerecord/test/cases/adapters/postgresql/rename_table_test.rb b/activerecord/test/cases/adapters/postgresql/rename_table_test.rb index 7eccaf4aa2..fae20de086 100644 --- a/activerecord/test/cases/adapters/postgresql/rename_table_test.rb +++ b/activerecord/test/cases/adapters/postgresql/rename_table_test.rb @@ -25,7 +25,6 @@ class PostgresqlRenameTableTest < ActiveRecord::PostgreSQLTestCase end private - def num_indices_named(name) @connection.execute(<<~SQL).values.length SELECT 1 FROM "pg_index" diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb index 336cec30ca..fe6a3deff4 100644 --- a/activerecord/test/cases/adapters/postgresql/schema_test.rb +++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb @@ -104,7 +104,11 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase end def test_schema_names - assert_equal ["public", "test_schema", "test_schema2"], @connection.schema_names + schema_names = @connection.schema_names + assert_includes schema_names, "public" + assert_includes schema_names, "test_schema" + assert_includes schema_names, "test_schema2" + assert_includes schema_names, "hint_plan" if @connection.supports_optimizer_hints? end def test_create_schema diff --git a/activerecord/test/cases/adapters/postgresql/transaction_test.rb b/activerecord/test/cases/adapters/postgresql/transaction_test.rb index 919ff3d158..311863a418 100644 --- a/activerecord/test/cases/adapters/postgresql/transaction_test.rb +++ b/activerecord/test/cases/adapters/postgresql/transaction_test.rb @@ -177,7 +177,6 @@ module ActiveRecord end private - def with_warning_suppression log_level = ActiveRecord::Base.connection.client_min_messages ActiveRecord::Base.connection.client_min_messages = "error" diff --git a/activerecord/test/cases/adapters/postgresql/uuid_test.rb b/activerecord/test/cases/adapters/postgresql/uuid_test.rb index d2d8ea8042..a1c985fc71 100644 --- a/activerecord/test/cases/adapters/postgresql/uuid_test.rb +++ b/activerecord/test/cases/adapters/postgresql/uuid_test.rb @@ -293,14 +293,16 @@ class PostgresqlUUIDGenerationTest < ActiveRecord::PostgreSQLTestCase create_table("pg_uuids_4", id: :uuid) end end.new - ActiveRecord::Migrator.new(:up, [migration]).migrate + ActiveRecord::Migrator.new(:up, [migration], ActiveRecord::Base.connection.schema_migration).migrate schema = dump_table_schema "pg_uuids_4" assert_match(/\bcreate_table "pg_uuids_4", id: :uuid, default: -> { "uuid_generate_v4\(\)" }/, schema) ensure drop_table "pg_uuids_4" ActiveRecord::Migration.verbose = @verbose_was + ActiveRecord::Base.connection.schema_migration.delete_all end + uses_transaction :test_schema_dumper_for_uuid_primary_key_default_in_legacy_migration end class PostgresqlUUIDTestNilDefault < ActiveRecord::PostgreSQLTestCase @@ -341,14 +343,16 @@ class PostgresqlUUIDTestNilDefault < ActiveRecord::PostgreSQLTestCase create_table("pg_uuids_4", id: :uuid, default: nil) end end.new - ActiveRecord::Migrator.new(:up, [migration]).migrate + ActiveRecord::Migrator.new(:up, [migration], ActiveRecord::Base.connection.schema_migration).migrate schema = dump_table_schema "pg_uuids_4" assert_match(/\bcreate_table "pg_uuids_4", id: :uuid, default: nil/, schema) ensure drop_table "pg_uuids_4" ActiveRecord::Migration.verbose = @verbose_was + ActiveRecord::Base.connection.schema_migration.delete_all end + uses_transaction :test_schema_dumper_for_uuid_primary_key_with_default_nil_in_legacy_migration end class PostgresqlUUIDTestInverseOf < ActiveRecord::PostgreSQLTestCase diff --git a/activerecord/test/cases/adapters/sqlite3/collation_test.rb b/activerecord/test/cases/adapters/sqlite3/collation_test.rb index 76c8f7d8dd..d938b5ff2f 100644 --- a/activerecord/test/cases/adapters/sqlite3/collation_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/collation_test.rb @@ -11,6 +11,10 @@ class SQLite3CollationTest < ActiveRecord::SQLite3TestCase @connection.create_table :collation_table_sqlite3, force: true do |t| t.string :string_nocase, collation: "NOCASE" t.text :text_rtrim, collation: "RTRIM" + # The decimal column might interfere with collation parsing. + # Thus, add this column type and some other string column afterwards. + t.decimal :decimal_col, precision: 6, scale: 2 + t.string :string_after_decimal_nocase, collation: "NOCASE" end end @@ -22,6 +26,11 @@ class SQLite3CollationTest < ActiveRecord::SQLite3TestCase column = @connection.columns(:collation_table_sqlite3).find { |c| c.name == "string_nocase" } assert_equal :string, column.type assert_equal "NOCASE", column.collation + + # Verify collation of a column behind the decimal column as well. + column = @connection.columns(:collation_table_sqlite3).find { |c| c.name == "string_after_decimal_nocase" } + assert_equal :string, column.type + assert_equal "NOCASE", column.collation end test "text column with collation" do diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb index 806cfbfc00..508f7d8945 100644 --- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb @@ -19,6 +19,8 @@ module ActiveRecord @conn = Base.sqlite3_connection database: ":memory:", adapter: "sqlite3", timeout: 100 + + @connection_handler = ActiveRecord::Base.connection_handler end def test_bad_connection @@ -572,7 +574,7 @@ module ActiveRecord def test_errors_when_an_insert_query_is_called_while_preventing_writes with_example_table "id int, data string" do assert_raises(ActiveRecord::ReadOnlyError) do - @conn.while_preventing_writes do + @connection_handler.while_preventing_writes do @conn.execute("INSERT INTO ex (data) VALUES ('138853948594')") end end @@ -584,7 +586,7 @@ module ActiveRecord @conn.execute("INSERT INTO ex (data) VALUES ('138853948594')") assert_raises(ActiveRecord::ReadOnlyError) do - @conn.while_preventing_writes do + @connection_handler.while_preventing_writes do @conn.execute("UPDATE ex SET data = '9989' WHERE data = '138853948594'") end end @@ -596,7 +598,7 @@ module ActiveRecord @conn.execute("INSERT INTO ex (data) VALUES ('138853948594')") assert_raises(ActiveRecord::ReadOnlyError) do - @conn.while_preventing_writes do + @connection_handler.while_preventing_writes do @conn.execute("DELETE FROM ex where data = '138853948594'") end end @@ -608,7 +610,7 @@ module ActiveRecord @conn.execute("INSERT INTO ex (data) VALUES ('138853948594')") assert_raises(ActiveRecord::ReadOnlyError) do - @conn.while_preventing_writes do + @connection_handler.while_preventing_writes do @conn.execute("REPLACE INTO ex (data) VALUES ('249823948')") end end @@ -619,7 +621,7 @@ module ActiveRecord with_example_table "id int, data string" do @conn.execute("INSERT INTO ex (data) VALUES ('138853948594')") - @conn.while_preventing_writes do + @connection_handler.while_preventing_writes do assert_equal 1, @conn.execute("SELECT data from ex WHERE data = '138853948594'").count end end @@ -629,14 +631,13 @@ module ActiveRecord with_example_table "id int, data string" do @conn.execute("INSERT INTO ex (data) VALUES ('138853948594')") - @conn.while_preventing_writes do + @connection_handler.while_preventing_writes do assert_equal 1, @conn.execute(" SELECT data from ex WHERE data = '138853948594'").count end end end private - def assert_logged(logs) subscriber = SQLSubscriber.new subscription = ActiveSupport::Notifications.subscribe("sql.active_record", subscriber) diff --git a/activerecord/test/cases/ar_schema_test.rb b/activerecord/test/cases/ar_schema_test.rb index 7aa6d089c5..2d5a06a4ac 100644 --- a/activerecord/test/cases/ar_schema_test.rb +++ b/activerecord/test/cases/ar_schema_test.rb @@ -9,7 +9,8 @@ class ActiveRecordSchemaTest < ActiveRecord::TestCase @original_verbose = ActiveRecord::Migration.verbose ActiveRecord::Migration.verbose = false @connection = ActiveRecord::Base.connection - ActiveRecord::SchemaMigration.drop_table + @schema_migration = @connection.schema_migration + @schema_migration.drop_table end teardown do @@ -18,21 +19,21 @@ class ActiveRecordSchemaTest < ActiveRecord::TestCase @connection.drop_table :nep_schema_migrations rescue nil @connection.drop_table :has_timestamps rescue nil @connection.drop_table :multiple_indexes rescue nil - ActiveRecord::SchemaMigration.delete_all rescue nil + @schema_migration.delete_all rescue nil ActiveRecord::Migration.verbose = @original_verbose end def test_has_primary_key old_primary_key_prefix_type = ActiveRecord::Base.primary_key_prefix_type ActiveRecord::Base.primary_key_prefix_type = :table_name_with_underscore - assert_equal "version", ActiveRecord::SchemaMigration.primary_key + assert_equal "version", @schema_migration.primary_key - ActiveRecord::SchemaMigration.create_table - assert_difference "ActiveRecord::SchemaMigration.count", 1 do - ActiveRecord::SchemaMigration.create version: 12 + @schema_migration.create_table + assert_difference "@schema_migration.count", 1 do + @schema_migration.create version: 12 end ensure - ActiveRecord::SchemaMigration.drop_table + @schema_migration.drop_table ActiveRecord::Base.primary_key_prefix_type = old_primary_key_prefix_type end @@ -54,7 +55,7 @@ class ActiveRecordSchemaTest < ActiveRecord::TestCase def test_schema_define_with_table_name_prefix old_table_name_prefix = ActiveRecord::Base.table_name_prefix ActiveRecord::Base.table_name_prefix = "nep_" - ActiveRecord::SchemaMigration.reset_table_name + @schema_migration.reset_table_name ActiveRecord::InternalMetadata.reset_table_name ActiveRecord::Schema.define(version: 7) do create_table :fruits do |t| @@ -67,7 +68,7 @@ class ActiveRecordSchemaTest < ActiveRecord::TestCase assert_equal 7, @connection.migration_context.current_version ensure ActiveRecord::Base.table_name_prefix = old_table_name_prefix - ActiveRecord::SchemaMigration.reset_table_name + @schema_migration.reset_table_name ActiveRecord::InternalMetadata.reset_table_name end @@ -89,10 +90,10 @@ class ActiveRecordSchemaTest < ActiveRecord::TestCase end def test_normalize_version - assert_equal "118", ActiveRecord::SchemaMigration.normalize_migration_number("0000118") - assert_equal "002", ActiveRecord::SchemaMigration.normalize_migration_number("2") - assert_equal "017", ActiveRecord::SchemaMigration.normalize_migration_number("0017") - assert_equal "20131219224947", ActiveRecord::SchemaMigration.normalize_migration_number("20131219224947") + assert_equal "118", @schema_migration.normalize_migration_number("0000118") + assert_equal "002", @schema_migration.normalize_migration_number("2") + assert_equal "017", @schema_migration.normalize_migration_number("0017") + assert_equal "20131219224947", @schema_migration.normalize_migration_number("20131219224947") end def test_schema_load_with_multiple_indexes_for_column_of_different_names diff --git a/activerecord/test/cases/arel/attributes_test.rb b/activerecord/test/cases/arel/attributes_test.rb index b00af4bd29..1712633ae9 100644 --- a/activerecord/test/cases/arel/attributes_test.rb +++ b/activerecord/test/cases/arel/attributes_test.rb @@ -23,46 +23,5 @@ module Arel assert_equal 2, array.uniq.size end end - - describe "for" do - it "deals with unknown column types" do - column = Struct.new(:type).new :crazy - Attributes.for(column).must_equal Attributes::Undefined - end - - it "returns the correct constant for strings" do - [:string, :text, :binary].each do |type| - column = Struct.new(:type).new type - Attributes.for(column).must_equal Attributes::String - end - end - - it "returns the correct constant for ints" do - column = Struct.new(:type).new :integer - Attributes.for(column).must_equal Attributes::Integer - end - - it "returns the correct constant for floats" do - column = Struct.new(:type).new :float - Attributes.for(column).must_equal Attributes::Float - end - - it "returns the correct constant for decimals" do - column = Struct.new(:type).new :decimal - Attributes.for(column).must_equal Attributes::Decimal - end - - it "returns the correct constant for boolean" do - column = Struct.new(:type).new :boolean - Attributes.for(column).must_equal Attributes::Boolean - end - - it "returns the correct constant for time" do - [:date, :datetime, :timestamp, :time].each do |type| - column = Struct.new(:type).new type - Attributes.for(column).must_equal Attributes::Time - end - end - end end end diff --git a/activerecord/test/cases/associations/eager_load_nested_include_test.rb b/activerecord/test/cases/associations/eager_load_nested_include_test.rb index 849939de75..9be21b23db 100644 --- a/activerecord/test/cases/associations/eager_load_nested_include_test.rb +++ b/activerecord/test/cases/associations/eager_load_nested_include_test.rb @@ -14,6 +14,7 @@ module Remembered included do after_create :remember + private def remember; self.class.remembered << self; end end diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index f7aad9d775..cb46f9e053 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -523,7 +523,7 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_eager_association_loading_with_belongs_to_and_order_string_with_quoted_table_name quoted_posts_id = Comment.connection.quote_table_name("posts") + "." + Comment.connection.quote_column_name("id") assert_nothing_raised do - Comment.includes(:post).references(:posts).order(Arel.sql(quoted_posts_id)) + Comment.includes(:post).references(:posts).order(quoted_posts_id) end end @@ -789,7 +789,6 @@ class EagerAssociationTest < ActiveRecord::TestCase .where("comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'") .references(:comments) .scoping do - posts = authors(:david).posts.limit(2).to_a assert_equal 2, posts.size end @@ -798,7 +797,6 @@ class EagerAssociationTest < ActiveRecord::TestCase .where("authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')") .references(:authors, :comments) .scoping do - count = Post.limit(2).count assert_equal count, posts.size end @@ -970,14 +968,14 @@ class EagerAssociationTest < ActiveRecord::TestCase posts(:thinking, :sti_comments), Post.all.merge!( includes: [:author, :comments], where: { "authors.name" => "David" }, - order: Arel.sql("UPPER(posts.title)"), limit: 2, offset: 1 + order: "UPPER(posts.title)", limit: 2, offset: 1 ).to_a ) assert_equal( posts(:sti_post_and_comments, :sti_comments), Post.all.merge!( includes: [:author, :comments], where: { "authors.name" => "David" }, - order: Arel.sql("UPPER(posts.title) DESC"), limit: 2, offset: 1 + order: "UPPER(posts.title) DESC", limit: 2, offset: 1 ).to_a ) end @@ -987,14 +985,14 @@ class EagerAssociationTest < ActiveRecord::TestCase posts(:thinking, :sti_comments), Post.all.merge!( includes: [:author, :comments], where: { "authors.name" => "David" }, - order: [Arel.sql("UPPER(posts.title)"), "posts.id"], limit: 2, offset: 1 + order: ["UPPER(posts.title)", "posts.id"], limit: 2, offset: 1 ).to_a ) assert_equal( posts(:sti_post_and_comments, :sti_comments), Post.all.merge!( includes: [:author, :comments], where: { "authors.name" => "David" }, - order: [Arel.sql("UPPER(posts.title) DESC"), "posts.id"], limit: 2, offset: 1 + order: ["UPPER(posts.title) DESC", "posts.id"], limit: 2, offset: 1 ).to_a ) end diff --git a/activerecord/test/cases/associations/extension_test.rb b/activerecord/test/cases/associations/extension_test.rb index 5e6e3e8ec4..604a52655c 100644 --- a/activerecord/test/cases/associations/extension_test.rb +++ b/activerecord/test/cases/associations/extension_test.rb @@ -87,7 +87,6 @@ class AssociationsExtensionsTest < ActiveRecord::TestCase end private - def extend!(model) ActiveRecord::Associations::Builder::HasMany.send(:define_extensions, model, :association_name) { } end diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 545bc77fed..6c54c2f1cd 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -2932,8 +2932,12 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal [], reference.ideal_jobs end - private + def test_has_many_preloading_with_duplicate_records + posts = Post.joins(:comments).preload(:comments).to_a + assert_equal [1, 2], posts.first.comments.map(&:id) + end + private def force_signal37_to_load_all_clients_of_firm companies(:first_firm).clients_of_firm.load_target end diff --git a/activerecord/test/cases/associations/nested_through_associations_test.rb b/activerecord/test/cases/associations/nested_through_associations_test.rb index 35da74102d..8d74ae3961 100644 --- a/activerecord/test/cases/associations/nested_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_through_associations_test.rb @@ -626,7 +626,6 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase end private - def assert_includes_and_joins_equal(query, expected, association) actual = assert_queries(1) { query.joins(association).to_a.uniq } assert_equal expected, actual diff --git a/activerecord/test/cases/associations/required_test.rb b/activerecord/test/cases/associations/required_test.rb index c7a78e6bc4..db7f945a36 100644 --- a/activerecord/test/cases/associations/required_test.rb +++ b/activerecord/test/cases/associations/required_test.rb @@ -117,7 +117,6 @@ class RequiredAssociationsTest < ActiveRecord::TestCase end private - def subclass_of(klass, &block) subclass = Class.new(klass, &block) def subclass.name diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index 5cbe5d796d..71b5407dcc 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -1087,7 +1087,6 @@ class AttributeMethodsTest < ActiveRecord::TestCase end private - def new_topic_like_ar_class(&block) klass = Class.new(ActiveRecord::Base) do self.table_name = "topics" diff --git a/activerecord/test/cases/attributes_test.rb b/activerecord/test/cases/attributes_test.rb index a6fb9f0af7..d6ac5a1057 100644 --- a/activerecord/test/cases/attributes_test.rb +++ b/activerecord/test/cases/attributes_test.rb @@ -241,7 +241,7 @@ module ActiveRecord test "attributes not backed by database columns are always initialized" do OverloadedType.create! - model = OverloadedType.first + model = OverloadedType.last assert_nil model.non_existent_decimal model.non_existent_decimal = "123" @@ -253,7 +253,7 @@ module ActiveRecord attribute :non_existent_decimal, :decimal, default: 123 end child.create! - model = child.first + model = child.last assert_equal 123, model.non_existent_decimal end @@ -264,7 +264,7 @@ module ActiveRecord attribute :foo, :string, default: "lol" end child.create! - model = child.first + model = child.last assert_equal "lol", model.foo diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb index 2fb5ca4152..7e61ac9d8b 100644 --- a/activerecord/test/cases/autosave_association_test.rb +++ b/activerecord/test/cases/autosave_association_test.rb @@ -39,7 +39,6 @@ class TestAutosaveAssociationsInGeneral < ActiveRecord::TestCase def self.name; "Person"; end private - def should_be_cool unless first_name == "cool" errors.add :first_name, "not cool" @@ -82,7 +81,6 @@ class TestAutosaveAssociationsInGeneral < ActiveRecord::TestCase end private - def assert_no_difference_when_adding_callbacks_twice_for(model, association_name) reflection = model.reflect_on_association(association_name) assert_no_difference "callbacks_for_model(#{model.name}).length" do diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 1c83100a75..983a46a2d0 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1499,7 +1499,7 @@ class BasicsTest < ActiveRecord::TestCase test "creating a record raises if preventing writes" do error = assert_raises ActiveRecord::ReadOnlyError do - ActiveRecord::Base.connection.while_preventing_writes do + ActiveRecord::Base.connection_handler.while_preventing_writes do Bird.create! name: "Bluejay" end end @@ -1511,7 +1511,7 @@ class BasicsTest < ActiveRecord::TestCase bird = Bird.create! name: "Bluejay" error = assert_raises ActiveRecord::ReadOnlyError do - ActiveRecord::Base.connection.while_preventing_writes do + ActiveRecord::Base.connection_handler.while_preventing_writes do bird.update! name: "Robin" end end @@ -1523,7 +1523,7 @@ class BasicsTest < ActiveRecord::TestCase bird = Bird.create! name: "Bluejay" error = assert_raises ActiveRecord::ReadOnlyError do - ActiveRecord::Base.connection.while_preventing_writes do + ActiveRecord::Base.connection_handler.while_preventing_writes do bird.destroy! end end @@ -1534,7 +1534,7 @@ class BasicsTest < ActiveRecord::TestCase test "selecting a record does not raise if preventing writes" do bird = Bird.create! name: "Bluejay" - ActiveRecord::Base.connection.while_preventing_writes do + ActiveRecord::Base.connection_handler.while_preventing_writes do assert_equal bird, Bird.where(name: "Bluejay").first end end @@ -1542,13 +1542,13 @@ class BasicsTest < ActiveRecord::TestCase test "an explain query does not raise if preventing writes" do Bird.create!(name: "Bluejay") - ActiveRecord::Base.connection.while_preventing_writes do + ActiveRecord::Base.connection_handler.while_preventing_writes do assert_queries(2) { Bird.where(name: "Bluejay").explain } end end test "an empty transaction does not raise if preventing writes" do - ActiveRecord::Base.connection.while_preventing_writes do + ActiveRecord::Base.connection_handler.while_preventing_writes do assert_queries(2, ignore_none: true) do Bird.transaction do ActiveRecord::Base.connection.materialize_transactions @@ -1556,4 +1556,59 @@ class BasicsTest < ActiveRecord::TestCase end end end + + test "preventing writes applies to all connections on a handler" do + conn1_error = assert_raises ActiveRecord::ReadOnlyError do + ActiveRecord::Base.connection_handler.while_preventing_writes do + assert_equal ActiveRecord::Base.connection, Bird.connection + assert_not_equal ARUnit2Model.connection, Bird.connection + Bird.create!(name: "Bluejay") + end + end + + assert_match %r/\AWrite query attempted while in readonly mode: INSERT /, conn1_error.message + + conn2_error = assert_raises ActiveRecord::ReadOnlyError do + ActiveRecord::Base.connection_handler.while_preventing_writes do + assert_not_equal ActiveRecord::Base.connection, Professor.connection + assert_equal ARUnit2Model.connection, Professor.connection + Professor.create!(name: "Professor Bluejay") + end + end + + assert_match %r/\AWrite query attempted while in readonly mode: INSERT /, conn2_error.message + end + + unless in_memory_db? + test "preventing writes with multiple handlers" do + ActiveRecord::Base.connects_to(database: { writing: :arunit, reading: :arunit }) + + conn1_error = assert_raises ActiveRecord::ReadOnlyError do + ActiveRecord::Base.connected_to(role: :writing) do + assert_equal :writing, ActiveRecord::Base.current_role + + ActiveRecord::Base.connection_handler.while_preventing_writes do + Bird.create!(name: "Bluejay") + end + end + end + + assert_match %r/\AWrite query attempted while in readonly mode: INSERT /, conn1_error.message + + conn2_error = assert_raises ActiveRecord::ReadOnlyError do + ActiveRecord::Base.connected_to(role: :reading) do + assert_equal :reading, ActiveRecord::Base.current_role + + ActiveRecord::Base.connection_handler.while_preventing_writes do + Bird.create!(name: "Bluejay") + end + end + end + + assert_match %r/\AWrite query attempted while in readonly mode: INSERT /, conn2_error.message + ensure + ActiveRecord::Base.connection_handlers = { writing: ActiveRecord::Base.default_connection_handler } + ActiveRecord::Base.establish_connection(:arunit) + end + end end diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index e42af3686e..525085bb28 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -589,11 +589,7 @@ class CalculationsTest < ActiveRecord::TestCase end def test_should_sum_expression - if current_adapter?(:SQLite3Adapter, :Mysql2Adapter, :PostgreSQLAdapter, :OracleAdapter) - assert_equal 636, Account.sum("2 * credit_limit") - else - assert_equal 636, Account.sum("2 * credit_limit").to_i - end + assert_equal 636, Account.sum("2 * credit_limit") end def test_sum_expression_returns_zero_when_no_records_to_sum @@ -771,6 +767,12 @@ class CalculationsTest < ActiveRecord::TestCase assert_equal [[2, 2], [4, 4]], Reply.includes(:topic).pluck(:id, :"topics.id") end + def test_group_by_with_order_by_virtual_count_attribute + expected = { "SpecialPost" => 1, "StiPost" => 2 } + actual = Post.group(:type).order(:count).limit(2).maximum(:comments_count) + assert_equal expected, actual + end if current_adapter?(:PostgreSQLAdapter) + def test_group_by_with_limit expected = { "Post" => 8, "SpecialPost" => 1 } actual = Post.includes(:comments).group(:type).order(:type).limit(2).count("comments.id") diff --git a/activerecord/test/cases/comment_test.rb b/activerecord/test/cases/comment_test.rb index f2f28462d1..25e2f20676 100644 --- a/activerecord/test/cases/comment_test.rb +++ b/activerecord/test/cases/comment_test.rb @@ -14,6 +14,9 @@ if ActiveRecord::Base.connection.supports_comments? class BlankComment < ActiveRecord::Base end + class PkCommented < ActiveRecord::Base + end + setup do @connection = ActiveRecord::Base.connection @@ -35,8 +38,13 @@ if ActiveRecord::Base.connection.supports_comments? t.index :absent_comment end + @connection.create_table("pk_commenteds", comment: "Table comment", id: false, force: true) do |t| + t.integer :id, comment: "Primary key comment", primary_key: true + end + Commented.reset_column_information BlankComment.reset_column_information + PkCommented.reset_column_information end teardown do @@ -44,7 +52,7 @@ if ActiveRecord::Base.connection.supports_comments? @connection.drop_table "blank_comments", if_exists: true end - def test_primary_key_comment + def test_default_primary_key_comment column = Commented.columns_hash["id"] assert_nil column.comment end @@ -169,5 +177,17 @@ if ActiveRecord::Base.connection.supports_comments? column = Commented.columns_hash["name"] assert_nil column.comment end + + def test_comment_on_primary_key + column = PkCommented.columns_hash["id"] + assert_equal "Primary key comment", column.comment + assert_equal "Table comment", @connection.table_comment("pk_commenteds") + end + + def test_schema_dump_with_primary_key_comment + output = dump_table_schema "pk_commenteds" + assert_match %r[create_table "pk_commenteds",.*\s+comment: "Table comment"], output + assert_no_match %r[create_table "pk_commenteds",.*\s+comment: "Primary key comment"], output + end end end diff --git a/activerecord/test/cases/connection_adapters/connection_handler_test.rb b/activerecord/test/cases/connection_adapters/connection_handler_test.rb index 6282759a10..27589966af 100644 --- a/activerecord/test/cases/connection_adapters/connection_handler_test.rb +++ b/activerecord/test/cases/connection_adapters/connection_handler_test.rb @@ -367,11 +367,24 @@ module ActiveRecord assert_same klass2.connection, ActiveRecord::Base.connection end + class ApplicationRecord < ActiveRecord::Base + self.abstract_class = true + end + + class MyClass < ApplicationRecord + end + def test_connection_specification_name_should_fallback_to_parent klassA = Class.new(Base) klassB = Class.new(klassA) + klassC = Class.new(MyClass) assert_equal klassB.connection_specification_name, klassA.connection_specification_name + assert_equal klassC.connection_specification_name, klassA.connection_specification_name + + assert_equal "primary", klassA.connection_specification_name + assert_equal "primary", klassC.connection_specification_name + klassA.connection_specification_name = "readonly" assert_equal "readonly", klassB.connection_specification_name end diff --git a/activerecord/test/cases/connection_adapters/mysql_type_lookup_test.rb b/activerecord/test/cases/connection_adapters/mysql_type_lookup_test.rb index 38331aa641..bc823fd072 100644 --- a/activerecord/test/cases/connection_adapters/mysql_type_lookup_test.rb +++ b/activerecord/test/cases/connection_adapters/mysql_type_lookup_test.rb @@ -58,7 +58,6 @@ if current_adapter?(:Mysql2Adapter) end private - def assert_lookup_type(type, lookup) cast_type = @connection.send(:type_map).lookup(lookup) assert_equal type, cast_type.type diff --git a/activerecord/test/cases/connection_adapters/type_lookup_test.rb b/activerecord/test/cases/connection_adapters/type_lookup_test.rb index 1c79d776f0..e92bb40632 100644 --- a/activerecord/test/cases/connection_adapters/type_lookup_test.rb +++ b/activerecord/test/cases/connection_adapters/type_lookup_test.rb @@ -109,7 +109,6 @@ unless current_adapter?(:PostgreSQLAdapter) # PostgreSQL does not use type strin end private - def assert_lookup_type(type, lookup) cast_type = @connection.send(:type_map).lookup(lookup) assert_equal type, cast_type.type diff --git a/activerecord/test/cases/connection_pool_test.rb b/activerecord/test/cases/connection_pool_test.rb index a15ad9a45b..ccbb6e16cd 100644 --- a/activerecord/test/cases/connection_pool_test.rb +++ b/activerecord/test/cases/connection_pool_test.rb @@ -507,7 +507,6 @@ module ActiveRecord pool.schema_cache = schema_cache pool.with_connection do |conn| - assert_not_same pool.schema_cache, conn.schema_cache assert_equal pool.schema_cache.size, conn.schema_cache.size assert_same pool.schema_cache.columns(:posts), conn.schema_cache.columns(:posts) end @@ -695,6 +694,28 @@ module ActiveRecord end end + def test_public_connections_access_threadsafe + _conn1 = @pool.checkout + conn2 = @pool.checkout + + connections = @pool.connections + found_conn = nil + + # Without assuming too much about implementation + # details make sure that a concurrent change to + # the pool is thread-safe. + connections.each_index do |idx| + if connections[idx] == conn2 + Thread.new do + @pool.remove(conn2) + end.join + end + found_conn = connections[idx] + end + + assert_not_nil found_conn + end + private def with_single_connection_pool one_conn_spec = ActiveRecord::Base.connection_pool.spec.dup diff --git a/activerecord/test/cases/database_statements_test.rb b/activerecord/test/cases/database_statements_test.rb index 1c934602ec..119d48b85e 100644 --- a/activerecord/test/cases/database_statements_test.rb +++ b/activerecord/test/cases/database_statements_test.rb @@ -23,7 +23,6 @@ class DatabaseStatementsTest < ActiveRecord::TestCase end private - def return_the_inserted_id(method:) # Oracle adapter uses prefetched primary key values from sequence and passes them to connection adapter insert method if current_adapter?(:OracleAdapter) diff --git a/activerecord/test/cases/explain_test.rb b/activerecord/test/cases/explain_test.rb index a0e75f4e89..edd2c768d3 100644 --- a/activerecord/test/cases/explain_test.rb +++ b/activerecord/test/cases/explain_test.rb @@ -72,7 +72,6 @@ if ActiveRecord::Base.connection.supports_explain? end private - def stub_explain_for_query_plans(query_plans = ["query plan foo", "query plan bar"]) explain_called = 0 diff --git a/activerecord/test/cases/finder_respond_to_test.rb b/activerecord/test/cases/finder_respond_to_test.rb index 66413a98e4..d9e88b3feb 100644 --- a/activerecord/test/cases/finder_respond_to_test.rb +++ b/activerecord/test/cases/finder_respond_to_test.rb @@ -54,7 +54,6 @@ class FinderRespondToTest < ActiveRecord::TestCase end private - def ensure_topic_method_is_not_cached(method_id) Topic.singleton_class.remove_method method_id if Topic.public_methods.include? method_id end diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index 0cb868da6e..a7f01e898e 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -948,7 +948,6 @@ class TransactionalFixturesOnConnectionNotification < ActiveRecord::TestCase end private - def fire_connection_notification(connection) assert_called_with(ActiveRecord::Base.connection_handler, :retrieve_connection, ["book"], returns: connection) do message_bus = ActiveSupport::Notifications.instrumenter @@ -1367,7 +1366,6 @@ class MultipleDatabaseFixturesTest < ActiveRecord::TestCase end private - def with_temporary_connection_pool old_pool = ActiveRecord::Base.connection_handler.retrieve_connection_pool(ActiveRecord::Base.connection_specification_name) new_pool = ActiveRecord::ConnectionAdapters::ConnectionPool.new ActiveRecord::Base.connection_pool.spec diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb index 543a0aeb39..56c780c4a6 100644 --- a/activerecord/test/cases/helper.rb +++ b/activerecord/test/cases/helper.rb @@ -189,7 +189,6 @@ end module InTimeZone private - def in_time_zone(zone) old_zone = Time.zone old_tz = ActiveRecord::Base.time_zone_aware_attributes diff --git a/activerecord/test/cases/hot_compatibility_test.rb b/activerecord/test/cases/hot_compatibility_test.rb index 7b388ebc5e..f41aea6125 100644 --- a/activerecord/test/cases/hot_compatibility_test.rb +++ b/activerecord/test/cases/hot_compatibility_test.rb @@ -115,7 +115,6 @@ class HotCompatibilityTest < ActiveRecord::TestCase end private - def get_prepared_statement_cache(connection) connection.instance_variable_get(:@statements) .instance_variable_get(:@cache)[Process.pid] diff --git a/activerecord/test/cases/insert_all_test.rb b/activerecord/test/cases/insert_all_test.rb index f24c63031c..d086d77081 100644 --- a/activerecord/test/cases/insert_all_test.rb +++ b/activerecord/test/cases/insert_all_test.rb @@ -262,7 +262,6 @@ class InsertAllTest < ActiveRecord::TestCase end private - def capture_log_output output = StringIO.new old_logger, ActiveRecord::Base.logger = ActiveRecord::Base.logger, ActiveSupport::Logger.new(output) diff --git a/activerecord/test/cases/json_serialization_test.rb b/activerecord/test/cases/json_serialization_test.rb index 8f9b1e2ec1..d68e208617 100644 --- a/activerecord/test/cases/json_serialization_test.rb +++ b/activerecord/test/cases/json_serialization_test.rb @@ -10,7 +10,6 @@ require "models/comment" module JsonSerializationHelpers private - def set_include_root_in_json(value) original_root_in_json = ActiveRecord::Base.include_root_in_json ActiveRecord::Base.include_root_in_json = value diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb index 04f9b26960..b468da7c76 100644 --- a/activerecord/test/cases/locking_test.rb +++ b/activerecord/test/cases/locking_test.rb @@ -593,7 +593,6 @@ class OptimisticLockingWithSchemaChangeTest < ActiveRecord::TestCase end private - def add_counter_column_to(model, col = "test_count") model.connection.add_column model.table_name, col, :integer, null: false, default: 0 model.reset_column_information diff --git a/activerecord/test/cases/migration/compatibility_test.rb b/activerecord/test/cases/migration/compatibility_test.rb index 726ccf925e..ff2a694e66 100644 --- a/activerecord/test/cases/migration/compatibility_test.rb +++ b/activerecord/test/cases/migration/compatibility_test.rb @@ -12,6 +12,7 @@ module ActiveRecord def setup super @connection = ActiveRecord::Base.connection + @schema_migration = @connection.schema_migration @verbose_was = ActiveRecord::Migration.verbose ActiveRecord::Migration.verbose = false @@ -38,7 +39,7 @@ module ActiveRecord }.new assert connection.index_exists?(:testings, :foo, name: "custom_index_name") - assert_raise(StandardError) { ActiveRecord::Migrator.new(:up, [migration]).migrate } + assert_raise(StandardError) { ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate } assert connection.index_exists?(:testings, :foo, name: "custom_index_name") end @@ -53,7 +54,7 @@ module ActiveRecord }.new assert connection.index_exists?(:testings, :bar) - ActiveRecord::Migrator.new(:up, [migration]).migrate + ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate assert_not connection.index_exists?(:testings, :bar) end @@ -67,7 +68,7 @@ module ActiveRecord end }.new - ActiveRecord::Migrator.new(:up, [migration]).migrate + ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate assert_not connection.index_exists?(:more_testings, :foo_id) assert_not connection.index_exists?(:more_testings, :bar_id) @@ -84,7 +85,7 @@ module ActiveRecord end }.new - ActiveRecord::Migrator.new(:up, [migration]).migrate + ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate assert connection.column_exists?(:more_testings, :created_at, null: true) assert connection.column_exists?(:more_testings, :updated_at, null: true) @@ -101,7 +102,7 @@ module ActiveRecord end }.new - ActiveRecord::Migrator.new(:up, [migration]).migrate + ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate assert connection.column_exists?(:testings, :created_at, null: true) assert connection.column_exists?(:testings, :updated_at, null: true) @@ -117,7 +118,7 @@ module ActiveRecord end }.new - ActiveRecord::Migrator.new(:up, [migration]).migrate + ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate assert connection.column_exists?(:testings, :created_at, null: true) assert connection.column_exists?(:testings, :updated_at, null: true) @@ -131,7 +132,7 @@ module ActiveRecord end }.new - ActiveRecord::Migrator.new(:up, [migration]).migrate + ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate assert connection.column_exists?(:testings, :created_at, null: true) assert connection.column_exists?(:testings, :updated_at, null: true) @@ -146,7 +147,7 @@ module ActiveRecord end }.new - ActiveRecord::Migrator.new(:up, [migration]).migrate + ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate assert connection.column_exists?(:more_testings, :created_at, null: false, **precision_implicit_default) assert connection.column_exists?(:more_testings, :updated_at, null: false, **precision_implicit_default) @@ -163,7 +164,7 @@ module ActiveRecord end }.new - ActiveRecord::Migrator.new(:up, [migration]).migrate + ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate assert connection.column_exists?(:testings, :created_at, null: false, **precision_implicit_default) assert connection.column_exists?(:testings, :updated_at, null: false, **precision_implicit_default) @@ -179,7 +180,7 @@ module ActiveRecord end }.new - ActiveRecord::Migrator.new(:up, [migration]).migrate + ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate assert connection.column_exists?(:testings, :created_at, null: false, **precision_implicit_default) assert connection.column_exists?(:testings, :updated_at, null: false, **precision_implicit_default) @@ -193,7 +194,7 @@ module ActiveRecord end }.new - ActiveRecord::Migrator.new(:up, [migration]).migrate + ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate assert connection.column_exists?(:testings, :created_at, null: false, **precision_implicit_default) assert connection.column_exists?(:testings, :updated_at, null: false, **precision_implicit_default) @@ -230,7 +231,7 @@ module ActiveRecord end }.new - ActiveRecord::Migrator.new(:up, [migration]).migrate + ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate assert connection.column_exists?(:testings, :foo, comment: "comment") end @@ -243,7 +244,7 @@ module ActiveRecord end }.new - ActiveRecord::Migrator.new(:up, [migration]).migrate + ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate assert_equal "comment", connection.table_comment("testings") end @@ -261,7 +262,7 @@ module ActiveRecord }.new Testing.create! - ActiveRecord::Migrator.new(:up, [migration]).migrate + ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate assert_equal ["foobar"], Testing.all.map(&:foo) ensure ActiveRecord::Base.clear_cache! diff --git a/activerecord/test/cases/migration/create_join_table_test.rb b/activerecord/test/cases/migration/create_join_table_test.rb index e0cbb29dcf..0257545330 100644 --- a/activerecord/test/cases/migration/create_join_table_test.rb +++ b/activerecord/test/cases/migration/create_join_table_test.rb @@ -151,7 +151,6 @@ module ActiveRecord end private - def with_table_cleanup tables_before = connection.data_sources diff --git a/activerecord/test/cases/migration/helper.rb b/activerecord/test/cases/migration/helper.rb index c056199140..da8bdc472a 100644 --- a/activerecord/test/cases/migration/helper.rb +++ b/activerecord/test/cases/migration/helper.rb @@ -34,7 +34,6 @@ module ActiveRecord end private - delegate(*CONNECTION_METHODS, to: :connection) end end diff --git a/activerecord/test/cases/migration/logger_test.rb b/activerecord/test/cases/migration/logger_test.rb index 28f4cc124b..431047f957 100644 --- a/activerecord/test/cases/migration/logger_test.rb +++ b/activerecord/test/cases/migration/logger_test.rb @@ -17,19 +17,20 @@ module ActiveRecord def setup super - ActiveRecord::SchemaMigration.create_table - ActiveRecord::SchemaMigration.delete_all + @schema_migration = ActiveRecord::Base.connection.schema_migration + @schema_migration.create_table + @schema_migration.delete_all end teardown do - ActiveRecord::SchemaMigration.drop_table + @schema_migration.drop_table end def test_migration_should_be_run_without_logger previous_logger = ActiveRecord::Base.logger ActiveRecord::Base.logger = nil migrations = [Migration.new("a", 1), Migration.new("b", 2), Migration.new("c", 3)] - ActiveRecord::Migrator.new(:up, migrations).migrate + ActiveRecord::Migrator.new(:up, migrations, @schema_migration).migrate ensure ActiveRecord::Base.logger = previous_logger end diff --git a/activerecord/test/cases/migration/references_statements_test.rb b/activerecord/test/cases/migration/references_statements_test.rb index 769241ba12..451894fc54 100644 --- a/activerecord/test/cases/migration/references_statements_test.rb +++ b/activerecord/test/cases/migration/references_statements_test.rb @@ -126,7 +126,6 @@ module ActiveRecord end private - def with_polymorphic_column add_column table_name, :supplier_type, :string add_index table_name, [:supplier_id, :supplier_type] diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index 255885b599..20f577b2c5 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -38,6 +38,7 @@ class MigrationTest < ActiveRecord::TestCase end Reminder.reset_column_information @verbose_was, ActiveRecord::Migration.verbose = ActiveRecord::Migration.verbose, false + @schema_migration = ActiveRecord::Base.connection.schema_migration ActiveRecord::Base.connection.schema_cache.clear! end @@ -84,7 +85,7 @@ class MigrationTest < ActiveRecord::TestCase def test_migrator_versions migrations_path = MIGRATIONS_ROOT + "/valid" - migrator = ActiveRecord::MigrationContext.new(migrations_path) + migrator = ActiveRecord::MigrationContext.new(migrations_path, @schema_migration) migrator.up assert_equal 3, migrator.current_version @@ -102,23 +103,23 @@ class MigrationTest < ActiveRecord::TestCase ActiveRecord::Base.connection.drop_table "schema_migrations", if_exists: true migrations_path = MIGRATIONS_ROOT + "/valid" - migrator = ActiveRecord::MigrationContext.new(migrations_path) + migrator = ActiveRecord::MigrationContext.new(migrations_path, @schema_migration) assert_equal true, migrator.needs_migration? end def test_any_migrations - migrator = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/valid") + migrator = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/valid", @schema_migration) assert_predicate migrator, :any_migrations? - migrator_empty = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/empty") + migrator_empty = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/empty", @schema_migration) assert_not_predicate migrator_empty, :any_migrations? end def test_migration_version - migrator = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/version_check") + migrator = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/version_check", @schema_migration) assert_equal 0, migrator.current_version migrator.up(20131219224947) assert_equal 20131219224947, migrator.current_version @@ -190,6 +191,7 @@ class MigrationTest < ActiveRecord::TestCase assert_not_predicate BigNumber, :table_exists? GiveMeBigNumbers.up + assert_predicate BigNumber, :table_exists? BigNumber.reset_column_information assert BigNumber.create( @@ -248,7 +250,7 @@ class MigrationTest < ActiveRecord::TestCase assert_not_predicate Reminder, :table_exists? name_filter = lambda { |migration| migration.name == "ValidPeopleHaveLastNames" } - migrator = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/valid") + migrator = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/valid", @schema_migration) migrator.up(&name_filter) assert_column Person, :last_name @@ -310,7 +312,7 @@ class MigrationTest < ActiveRecord::TestCase end }.new - migrator = ActiveRecord::Migrator.new(:up, [migration], 100) + migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 100) e = assert_raise(StandardError) { migrator.migrate } @@ -331,7 +333,7 @@ class MigrationTest < ActiveRecord::TestCase end }.new - migrator = ActiveRecord::Migrator.new(:up, [migration], 100) + migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 100) e = assert_raise(StandardError) { migrator.run } @@ -354,7 +356,7 @@ class MigrationTest < ActiveRecord::TestCase end }.new - migrator = ActiveRecord::Migrator.new(:up, [migration], 101) + migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 101) e = assert_raise(StandardError) { migrator.migrate } assert_equal "An error has occurred, all later migrations canceled:\n\nSomething broke", e.message @@ -413,7 +415,7 @@ class MigrationTest < ActiveRecord::TestCase def test_internal_metadata_stores_environment current_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call migrations_path = MIGRATIONS_ROOT + "/valid" - migrator = ActiveRecord::MigrationContext.new(migrations_path) + migrator = ActiveRecord::MigrationContext.new(migrations_path, @schema_migration) migrator.up assert_equal current_env, ActiveRecord::InternalMetadata[:environment] @@ -441,7 +443,7 @@ class MigrationTest < ActiveRecord::TestCase current_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call migrations_path = MIGRATIONS_ROOT + "/valid" - migrator = ActiveRecord::MigrationContext.new(migrations_path) + migrator = ActiveRecord::MigrationContext.new(migrations_path, @schema_migration) migrator.up assert_equal current_env, ActiveRecord::InternalMetadata[:environment] assert_equal "bar", ActiveRecord::InternalMetadata[:foo] @@ -482,6 +484,7 @@ class MigrationTest < ActiveRecord::TestCase Thing.reset_table_name Thing.reset_sequence_name WeNeedThings.up + assert_predicate Thing, :table_exists? Thing.reset_column_information assert Thing.create("content" => "hello world") @@ -502,8 +505,9 @@ class MigrationTest < ActiveRecord::TestCase ActiveRecord::Base.table_name_suffix = "_suffix" Reminder.reset_table_name Reminder.reset_sequence_name - Reminder.reset_column_information WeNeedReminders.up + assert_predicate Reminder, :table_exists? + Reminder.reset_column_information assert Reminder.create("content" => "hello world", "remind_at" => Time.now) assert_equal "hello world", Reminder.first.content @@ -636,7 +640,7 @@ class MigrationTest < ActiveRecord::TestCase if ActiveRecord::Base.connection.supports_advisory_locks? def test_migrator_generates_valid_lock_id migration = Class.new(ActiveRecord::Migration::Current).new - migrator = ActiveRecord::Migrator.new(:up, [migration], 100) + migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 100) lock_id = migrator.send(:generate_migrator_advisory_lock_id) @@ -650,7 +654,7 @@ class MigrationTest < ActiveRecord::TestCase # It is important we are consistent with how we generate this so that # exclusive locking works across migrator versions migration = Class.new(ActiveRecord::Migration::Current).new - migrator = ActiveRecord::Migrator.new(:up, [migration], 100) + migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 100) lock_id = migrator.send(:generate_migrator_advisory_lock_id) @@ -672,7 +676,7 @@ class MigrationTest < ActiveRecord::TestCase end }.new - migrator = ActiveRecord::Migrator.new(:up, [migration], 100) + migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 100) lock_id = migrator.send(:generate_migrator_advisory_lock_id) with_another_process_holding_lock(lock_id) do @@ -693,7 +697,7 @@ class MigrationTest < ActiveRecord::TestCase end }.new - migrator = ActiveRecord::Migrator.new(:up, [migration], 100) + migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 100) lock_id = migrator.send(:generate_migrator_advisory_lock_id) with_another_process_holding_lock(lock_id) do @@ -706,7 +710,7 @@ class MigrationTest < ActiveRecord::TestCase def test_with_advisory_lock_raises_the_right_error_when_it_fails_to_release_lock migration = Class.new(ActiveRecord::Migration::Current).new - migrator = ActiveRecord::Migrator.new(:up, [migration], 100) + migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 100) lock_id = migrator.send(:generate_migrator_advisory_lock_id) e = assert_raises(ActiveRecord::ConcurrentMigrationError) do @@ -935,7 +939,6 @@ if ActiveRecord::Base.connection.supports_bulk_alter? end private - def with_bulk_change_table # Reset columns/indexes cache as we're changing the table @columns = @indexes = nil diff --git a/activerecord/test/cases/migrator_test.rb b/activerecord/test/cases/migrator_test.rb index 30e199f1c5..aeba8e1d14 100644 --- a/activerecord/test/cases/migrator_test.rb +++ b/activerecord/test/cases/migrator_test.rb @@ -23,8 +23,9 @@ class MigratorTest < ActiveRecord::TestCase def setup super - ActiveRecord::SchemaMigration.create_table - ActiveRecord::SchemaMigration.delete_all rescue nil + @schema_migration = ActiveRecord::Base.connection.schema_migration + @schema_migration.create_table + @schema_migration.delete_all rescue nil @verbose_was = ActiveRecord::Migration.verbose ActiveRecord::Migration.message_count = 0 ActiveRecord::Migration.class_eval do @@ -36,7 +37,7 @@ class MigratorTest < ActiveRecord::TestCase end teardown do - ActiveRecord::SchemaMigration.delete_all rescue nil + @schema_migration.delete_all rescue nil ActiveRecord::Migration.verbose = @verbose_was ActiveRecord::Migration.class_eval do undef :puts @@ -49,7 +50,7 @@ class MigratorTest < ActiveRecord::TestCase def test_migrator_with_duplicate_names e = assert_raises(ActiveRecord::DuplicateMigrationNameError) do list = [ActiveRecord::Migration.new("Chunky"), ActiveRecord::Migration.new("Chunky")] - ActiveRecord::Migrator.new(:up, list) + ActiveRecord::Migrator.new(:up, list, @schema_migration) end assert_match(/Multiple migrations have the name Chunky/, e.message) end @@ -57,39 +58,40 @@ class MigratorTest < ActiveRecord::TestCase def test_migrator_with_duplicate_versions assert_raises(ActiveRecord::DuplicateMigrationVersionError) do list = [ActiveRecord::Migration.new("Foo", 1), ActiveRecord::Migration.new("Bar", 1)] - ActiveRecord::Migrator.new(:up, list) + ActiveRecord::Migrator.new(:up, list, @schema_migration) end end def test_migrator_with_missing_version_numbers assert_raises(ActiveRecord::UnknownMigrationVersionError) do list = [ActiveRecord::Migration.new("Foo", 1), ActiveRecord::Migration.new("Bar", 2)] - ActiveRecord::Migrator.new(:up, list, 3).run + ActiveRecord::Migrator.new(:up, list, @schema_migration, 3).run end assert_raises(ActiveRecord::UnknownMigrationVersionError) do list = [ActiveRecord::Migration.new("Foo", 1), ActiveRecord::Migration.new("Bar", 2)] - ActiveRecord::Migrator.new(:up, list, -1).run + ActiveRecord::Migrator.new(:up, list, @schema_migration, -1).run end assert_raises(ActiveRecord::UnknownMigrationVersionError) do list = [ActiveRecord::Migration.new("Foo", 1), ActiveRecord::Migration.new("Bar", 2)] - ActiveRecord::Migrator.new(:up, list, 0).run + ActiveRecord::Migrator.new(:up, list, @schema_migration, 0).run end assert_raises(ActiveRecord::UnknownMigrationVersionError) do list = [ActiveRecord::Migration.new("Foo", 1), ActiveRecord::Migration.new("Bar", 2)] - ActiveRecord::Migrator.new(:up, list, 3).migrate + ActiveRecord::Migrator.new(:up, list, @schema_migration, 3).migrate end assert_raises(ActiveRecord::UnknownMigrationVersionError) do list = [ActiveRecord::Migration.new("Foo", 1), ActiveRecord::Migration.new("Bar", 2)] - ActiveRecord::Migrator.new(:up, list, -1).migrate + ActiveRecord::Migrator.new(:up, list, @schema_migration, -1).migrate end end def test_finds_migrations - migrations = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/valid").migrations + schema_migration = ActiveRecord::Base.connection.schema_migration + migrations = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/valid", schema_migration).migrations [[1, "ValidPeopleHaveLastNames"], [2, "WeNeedReminders"], [3, "InnocentJointable"]].each_with_index do |pair, i| assert_equal migrations[i].version, pair.first @@ -98,7 +100,8 @@ class MigratorTest < ActiveRecord::TestCase end def test_finds_migrations_in_subdirectories - migrations = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/valid_with_subdirectories").migrations + schema_migration = ActiveRecord::Base.connection.schema_migration + migrations = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/valid_with_subdirectories", schema_migration).migrations [[1, "ValidPeopleHaveLastNames"], [2, "WeNeedReminders"], [3, "InnocentJointable"]].each_with_index do |pair, i| assert_equal migrations[i].version, pair.first @@ -107,8 +110,9 @@ class MigratorTest < ActiveRecord::TestCase end def test_finds_migrations_from_two_directories + schema_migration = ActiveRecord::Base.connection.schema_migration directories = [MIGRATIONS_ROOT + "/valid_with_timestamps", MIGRATIONS_ROOT + "/to_copy_with_timestamps"] - migrations = ActiveRecord::MigrationContext.new(directories).migrations + migrations = ActiveRecord::MigrationContext.new(directories, schema_migration).migrations [[20090101010101, "PeopleHaveHobbies"], [20090101010202, "PeopleHaveDescriptions"], @@ -121,14 +125,16 @@ class MigratorTest < ActiveRecord::TestCase end def test_finds_migrations_in_numbered_directory - migrations = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/10_urban").migrations + schema_migration = ActiveRecord::Base.connection.schema_migration + migrations = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/10_urban", schema_migration).migrations assert_equal 9, migrations[0].version assert_equal "AddExpressions", migrations[0].name end def test_relative_migrations + schema_migration = ActiveRecord::Base.connection.schema_migration list = Dir.chdir(MIGRATIONS_ROOT) do - ActiveRecord::MigrationContext.new("valid").migrations + ActiveRecord::MigrationContext.new("valid", schema_migration).migrations end migration_proxy = list.find { |item| @@ -138,9 +144,9 @@ class MigratorTest < ActiveRecord::TestCase end def test_finds_pending_migrations - ActiveRecord::SchemaMigration.create!(version: "1") + @schema_migration.create!(version: "1") migration_list = [ActiveRecord::Migration.new("foo", 1), ActiveRecord::Migration.new("bar", 3)] - migrations = ActiveRecord::Migrator.new(:up, migration_list).pending_migrations + migrations = ActiveRecord::Migrator.new(:up, migration_list, @schema_migration).pending_migrations assert_equal 1, migrations.size assert_equal migration_list.last, migrations.first @@ -148,35 +154,38 @@ class MigratorTest < ActiveRecord::TestCase def test_migrations_status path = MIGRATIONS_ROOT + "/valid" + schema_migration = ActiveRecord::Base.connection.schema_migration - ActiveRecord::SchemaMigration.create(version: 2) - ActiveRecord::SchemaMigration.create(version: 10) + @schema_migration.create(version: 2) + @schema_migration.create(version: 10) assert_equal [ ["down", "001", "Valid people have last names"], ["up", "002", "We need reminders"], ["down", "003", "Innocent jointable"], ["up", "010", "********** NO FILE **********"], - ], ActiveRecord::MigrationContext.new(path).migrations_status + ], ActiveRecord::MigrationContext.new(path, schema_migration).migrations_status end def test_migrations_status_in_subdirectories path = MIGRATIONS_ROOT + "/valid_with_subdirectories" + schema_migration = ActiveRecord::Base.connection.schema_migration - ActiveRecord::SchemaMigration.create(version: 2) - ActiveRecord::SchemaMigration.create(version: 10) + @schema_migration.create(version: 2) + @schema_migration.create(version: 10) assert_equal [ ["down", "001", "Valid people have last names"], ["up", "002", "We need reminders"], ["down", "003", "Innocent jointable"], ["up", "010", "********** NO FILE **********"], - ], ActiveRecord::MigrationContext.new(path).migrations_status + ], ActiveRecord::MigrationContext.new(path, schema_migration).migrations_status end def test_migrations_status_with_schema_define_in_subdirectories path = MIGRATIONS_ROOT + "/valid_with_subdirectories" prev_paths = ActiveRecord::Migrator.migrations_paths + schema_migration = ActiveRecord::Base.connection.schema_migration ActiveRecord::Migrator.migrations_paths = path ActiveRecord::Schema.define(version: 3) do @@ -186,16 +195,17 @@ class MigratorTest < ActiveRecord::TestCase ["up", "001", "Valid people have last names"], ["up", "002", "We need reminders"], ["up", "003", "Innocent jointable"], - ], ActiveRecord::MigrationContext.new(path).migrations_status + ], ActiveRecord::MigrationContext.new(path, schema_migration).migrations_status ensure ActiveRecord::Migrator.migrations_paths = prev_paths end def test_migrations_status_from_two_directories paths = [MIGRATIONS_ROOT + "/valid_with_timestamps", MIGRATIONS_ROOT + "/to_copy_with_timestamps"] + schema_migration = ActiveRecord::Base.connection.schema_migration - ActiveRecord::SchemaMigration.create(version: "20100101010101") - ActiveRecord::SchemaMigration.create(version: "20160528010101") + @schema_migration.create(version: "20100101010101") + @schema_migration.create(version: "20160528010101") assert_equal [ ["down", "20090101010101", "People have hobbies"], @@ -204,18 +214,18 @@ class MigratorTest < ActiveRecord::TestCase ["down", "20100201010101", "Valid with timestamps we need reminders"], ["down", "20100301010101", "Valid with timestamps innocent jointable"], ["up", "20160528010101", "********** NO FILE **********"], - ], ActiveRecord::MigrationContext.new(paths).migrations_status + ], ActiveRecord::MigrationContext.new(paths, schema_migration).migrations_status end def test_migrator_interleaved_migrations pass_one = [Sensor.new("One", 1)] - ActiveRecord::Migrator.new(:up, pass_one).migrate + ActiveRecord::Migrator.new(:up, pass_one, @schema_migration).migrate assert pass_one.first.went_up assert_not pass_one.first.went_down pass_two = [Sensor.new("One", 1), Sensor.new("Three", 3)] - ActiveRecord::Migrator.new(:up, pass_two).migrate + ActiveRecord::Migrator.new(:up, pass_two, @schema_migration).migrate assert_not pass_two[0].went_up assert pass_two[1].went_up assert pass_two.all? { |x| !x.went_down } @@ -224,7 +234,7 @@ class MigratorTest < ActiveRecord::TestCase Sensor.new("Two", 2), Sensor.new("Three", 3)] - ActiveRecord::Migrator.new(:down, pass_three).migrate + ActiveRecord::Migrator.new(:down, pass_three, @schema_migration).migrate assert pass_three[0].went_down assert_not pass_three[1].went_down assert pass_three[2].went_down @@ -232,7 +242,7 @@ class MigratorTest < ActiveRecord::TestCase def test_up_calls_up migrations = [Sensor.new(nil, 0), Sensor.new(nil, 1), Sensor.new(nil, 2)] - migrator = ActiveRecord::Migrator.new(:up, migrations) + migrator = ActiveRecord::Migrator.new(:up, migrations, @schema_migration) migrator.migrate assert migrations.all?(&:went_up) assert migrations.all? { |m| !m.went_down } @@ -243,7 +253,7 @@ class MigratorTest < ActiveRecord::TestCase test_up_calls_up migrations = [Sensor.new(nil, 0), Sensor.new(nil, 1), Sensor.new(nil, 2)] - migrator = ActiveRecord::Migrator.new(:down, migrations) + migrator = ActiveRecord::Migrator.new(:down, migrations, @schema_migration) migrator.migrate assert migrations.all? { |m| !m.went_up } assert migrations.all?(&:went_down) @@ -251,30 +261,31 @@ class MigratorTest < ActiveRecord::TestCase end def test_current_version - ActiveRecord::SchemaMigration.create!(version: "1000") - migrator = ActiveRecord::MigrationContext.new("db/migrate") + @schema_migration.create!(version: "1000") + schema_migration = ActiveRecord::Base.connection.schema_migration + migrator = ActiveRecord::MigrationContext.new("db/migrate", schema_migration) assert_equal 1000, migrator.current_version end def test_migrator_one_up calls, migrations = sensors(3) - ActiveRecord::Migrator.new(:up, migrations, 1).migrate + ActiveRecord::Migrator.new(:up, migrations, @schema_migration, 1).migrate assert_equal [[:up, 1]], calls calls.clear - ActiveRecord::Migrator.new(:up, migrations, 2).migrate + ActiveRecord::Migrator.new(:up, migrations, @schema_migration, 2).migrate assert_equal [[:up, 2]], calls end def test_migrator_one_down calls, migrations = sensors(3) - ActiveRecord::Migrator.new(:up, migrations).migrate + ActiveRecord::Migrator.new(:up, migrations, @schema_migration).migrate assert_equal [[:up, 1], [:up, 2], [:up, 3]], calls calls.clear - ActiveRecord::Migrator.new(:down, migrations, 1).migrate + ActiveRecord::Migrator.new(:down, migrations, @schema_migration, 1).migrate assert_equal [[:down, 3], [:down, 2]], calls end @@ -282,17 +293,17 @@ class MigratorTest < ActiveRecord::TestCase def test_migrator_one_up_one_down calls, migrations = sensors(3) - ActiveRecord::Migrator.new(:up, migrations, 1).migrate + ActiveRecord::Migrator.new(:up, migrations, @schema_migration, 1).migrate assert_equal [[:up, 1]], calls calls.clear - ActiveRecord::Migrator.new(:down, migrations, 0).migrate + ActiveRecord::Migrator.new(:down, migrations, @schema_migration, 0).migrate assert_equal [[:down, 1]], calls end def test_migrator_double_up calls, migrations = sensors(3) - migrator = ActiveRecord::Migrator.new(:up, migrations, 1) + migrator = ActiveRecord::Migrator.new(:up, migrations, @schema_migration, 1) assert_equal(0, migrator.current_version) migrator.migrate @@ -305,7 +316,7 @@ class MigratorTest < ActiveRecord::TestCase def test_migrator_double_down calls, migrations = sensors(3) - migrator = ActiveRecord::Migrator.new(:up, migrations, 1) + migrator = ActiveRecord::Migrator.new(:up, migrations, @schema_migration, 1) assert_equal 0, migrator.current_version @@ -313,7 +324,7 @@ class MigratorTest < ActiveRecord::TestCase assert_equal [[:up, 1]], calls calls.clear - migrator = ActiveRecord::Migrator.new(:down, migrations, 1) + migrator = ActiveRecord::Migrator.new(:down, migrations, @schema_migration, 1) migrator.run assert_equal [[:down, 1]], calls calls.clear @@ -328,12 +339,12 @@ class MigratorTest < ActiveRecord::TestCase _, migrations = sensors(3) ActiveRecord::Migration.verbose = true - ActiveRecord::Migrator.new(:up, migrations, 1).migrate + ActiveRecord::Migrator.new(:up, migrations, @schema_migration, 1).migrate assert_not_equal 0, ActiveRecord::Migration.message_count ActiveRecord::Migration.message_count = 0 - ActiveRecord::Migrator.new(:down, migrations, 0).migrate + ActiveRecord::Migrator.new(:down, migrations, @schema_migration, 0).migrate assert_not_equal 0, ActiveRecord::Migration.message_count end @@ -341,9 +352,9 @@ class MigratorTest < ActiveRecord::TestCase _, migrations = sensors(3) ActiveRecord::Migration.verbose = false - ActiveRecord::Migrator.new(:up, migrations, 1).migrate + ActiveRecord::Migrator.new(:up, migrations, @schema_migration, 1).migrate assert_equal 0, ActiveRecord::Migration.message_count - ActiveRecord::Migrator.new(:down, migrations, 0).migrate + ActiveRecord::Migrator.new(:down, migrations, @schema_migration, 0).migrate assert_equal 0, ActiveRecord::Migration.message_count end @@ -351,23 +362,24 @@ class MigratorTest < ActiveRecord::TestCase calls, migrations = sensors(3) # migrate up to 1 - ActiveRecord::Migrator.new(:up, migrations, 1).migrate + ActiveRecord::Migrator.new(:up, migrations, @schema_migration, 1).migrate assert_equal [[:up, 1]], calls calls.clear # migrate down to 0 - ActiveRecord::Migrator.new(:down, migrations, 0).migrate + ActiveRecord::Migrator.new(:down, migrations, @schema_migration, 0).migrate assert_equal [[:down, 1]], calls calls.clear # migrate down to 0 again - ActiveRecord::Migrator.new(:down, migrations, 0).migrate + ActiveRecord::Migrator.new(:down, migrations, @schema_migration, 0).migrate assert_equal [], calls end def test_migrator_going_down_due_to_version_target + schema_migration = ActiveRecord::Base.connection.schema_migration calls, migrator = migrator_class(3) - migrator = migrator.new("valid") + migrator = migrator.new("valid", schema_migration) migrator.up(1) assert_equal [[:up, 1]], calls @@ -382,8 +394,9 @@ class MigratorTest < ActiveRecord::TestCase end def test_migrator_output_when_running_multiple_migrations + schema_migration = ActiveRecord::Base.connection.schema_migration _, migrator = migrator_class(3) - migrator = migrator.new("valid") + migrator = migrator.new("valid", schema_migration) result = migrator.migrate assert_equal(3, result.count) @@ -397,8 +410,9 @@ class MigratorTest < ActiveRecord::TestCase end def test_migrator_output_when_running_single_migration + schema_migration = ActiveRecord::Base.connection.schema_migration _, migrator = migrator_class(1) - migrator = migrator.new("valid") + migrator = migrator.new("valid", schema_migration) result = migrator.run(:up, 1) @@ -406,8 +420,9 @@ class MigratorTest < ActiveRecord::TestCase end def test_migrator_rollback + schema_migration = ActiveRecord::Base.connection.schema_migration _, migrator = migrator_class(3) - migrator = migrator.new("valid") + migrator = migrator.new("valid", schema_migration) migrator.migrate assert_equal(3, migrator.current_version) @@ -426,18 +441,20 @@ class MigratorTest < ActiveRecord::TestCase end def test_migrator_db_has_no_schema_migrations_table + schema_migration = ActiveRecord::Base.connection.schema_migration _, migrator = migrator_class(3) - migrator = migrator.new("valid") + migrator = migrator.new("valid", schema_migration) - ActiveRecord::Base.connection.drop_table "schema_migrations", if_exists: true - assert_not ActiveRecord::Base.connection.table_exists?("schema_migrations") + ActiveRecord::SchemaMigration.drop_table + assert_not_predicate ActiveRecord::SchemaMigration, :table_exists? migrator.migrate(1) - assert ActiveRecord::Base.connection.table_exists?("schema_migrations") + assert_predicate ActiveRecord::SchemaMigration, :table_exists? end def test_migrator_forward + schema_migration = ActiveRecord::Base.connection.schema_migration _, migrator = migrator_class(3) - migrator = migrator.new("/valid") + migrator = migrator.new("/valid", schema_migration) migrator.migrate(1) assert_equal(1, migrator.current_version) @@ -450,18 +467,20 @@ class MigratorTest < ActiveRecord::TestCase def test_only_loads_pending_migrations # migrate up to 1 - ActiveRecord::SchemaMigration.create!(version: "1") + @schema_migration.create!(version: "1") + schema_migration = ActiveRecord::Base.connection.schema_migration calls, migrator = migrator_class(3) - migrator = migrator.new("valid") + migrator = migrator.new("valid", schema_migration) migrator.migrate assert_equal [[:up, 2], [:up, 3]], calls end def test_get_all_versions + schema_migration = ActiveRecord::Base.connection.schema_migration _, migrator = migrator_class(3) - migrator = migrator.new("valid") + migrator = migrator.new("valid", schema_migration) migrator.migrate assert_equal([1, 2, 3], migrator.get_all_versions) diff --git a/activerecord/test/cases/multi_db_migrator_test.rb b/activerecord/test/cases/multi_db_migrator_test.rb new file mode 100644 index 0000000000..650b3af6f0 --- /dev/null +++ b/activerecord/test/cases/multi_db_migrator_test.rb @@ -0,0 +1,218 @@ +# frozen_string_literal: true + +require "cases/helper" +require "cases/migration/helper" + +class MultiDbMigratorTest < ActiveRecord::TestCase + self.use_transactional_tests = false + + # Use this class to sense if migrations have gone + # up or down. + class Sensor < ActiveRecord::Migration::Current + attr_reader :went_up, :went_down + + def initialize(name = self.class.name, version = nil) + super + @went_up = false + @went_down = false + end + + def up; @went_up = true; end + def down; @went_down = true; end + end + + def setup + super + @connection_a = ActiveRecord::Base.connection + @connection_b = ARUnit2Model.connection + + @connection_a.schema_migration.create_table + @connection_b.schema_migration.create_table + + @connection_a.schema_migration.delete_all rescue nil + @connection_b.schema_migration.delete_all rescue nil + + @path_a = MIGRATIONS_ROOT + "/valid" + @path_b = MIGRATIONS_ROOT + "/to_copy" + + @schema_migration_a = @connection_a.schema_migration + @migrations_a = ActiveRecord::MigrationContext.new(@path_a, @schema_migration_a).migrations + @schema_migration_b = @connection_b.schema_migration + @migrations_b = ActiveRecord::MigrationContext.new(@path_b, @schema_migration_b).migrations + + @migrations_a_list = [[1, "ValidPeopleHaveLastNames"], [2, "WeNeedReminders"], [3, "InnocentJointable"]] + @migrations_b_list = [[1, "PeopleHaveHobbies"], [2, "PeopleHaveDescriptions"]] + + @verbose_was = ActiveRecord::Migration.verbose + + ActiveRecord::Migration.message_count = 0 + ActiveRecord::Migration.class_eval do + undef :puts + def puts(*) + ActiveRecord::Migration.message_count += 1 + end + end + end + + teardown do + @connection_a.schema_migration.delete_all rescue nil + @connection_b.schema_migration.delete_all rescue nil + + ActiveRecord::Migration.verbose = @verbose_was + ActiveRecord::Migration.class_eval do + undef :puts + def puts(*) + super + end + end + end + + def test_finds_migrations + @migrations_a_list.each_with_index do |pair, i| + assert_equal @migrations_a[i].version, pair.first + assert_equal @migrations_a[i].name, pair.last + end + + @migrations_b_list.each_with_index do |pair, i| + assert_equal @migrations_b[i].version, pair.first + assert_equal @migrations_b[i].name, pair.last + end + end + + def test_migrations_status + @schema_migration_a.create(version: 2) + @schema_migration_a.create(version: 10) + + assert_equal [ + ["down", "001", "Valid people have last names"], + ["up", "002", "We need reminders"], + ["down", "003", "Innocent jointable"], + ["up", "010", "********** NO FILE **********"], + ], ActiveRecord::MigrationContext.new(@path_a, @schema_migration_a).migrations_status + + @schema_migration_b.create(version: 4) + + assert_equal [ + ["down", "001", "People have hobbies"], + ["down", "002", "People have descriptions"], + ["up", "004", "********** NO FILE **********"] + ], ActiveRecord::MigrationContext.new(@path_b, @schema_migration_b).migrations_status + end + + def test_get_all_versions + _, migrator_a = migrator_class(3) + migrator_a = migrator_a.new(@path_a, @schema_migration_a) + + migrator_a.migrate + assert_equal([1, 2, 3], migrator_a.get_all_versions) + + migrator_a.rollback + assert_equal([1, 2], migrator_a.get_all_versions) + + migrator_a.rollback + assert_equal([1], migrator_a.get_all_versions) + + migrator_a.rollback + assert_equal([], migrator_a.get_all_versions) + + _, migrator_b = migrator_class(2) + migrator_b = migrator_b.new(@path_b, @schema_migration_b) + + migrator_b.migrate + assert_equal([1, 2], migrator_b.get_all_versions) + + migrator_b.rollback + assert_equal([1], migrator_b.get_all_versions) + + migrator_b.rollback + assert_equal([], migrator_b.get_all_versions) + end + + def test_finds_pending_migrations + @schema_migration_a.create!(version: "1") + migration_list_a = [ActiveRecord::Migration.new("foo", 1), ActiveRecord::Migration.new("bar", 3)] + migrations_a = ActiveRecord::Migrator.new(:up, migration_list_a, @schema_migration_a).pending_migrations + + assert_equal 1, migrations_a.size + assert_equal migration_list_a.last, migrations_a.first + + @schema_migration_b.create!(version: "1") + migration_list_b = [ActiveRecord::Migration.new("foo", 1), ActiveRecord::Migration.new("bar", 3)] + migrations_b = ActiveRecord::Migrator.new(:up, migration_list_b, @schema_migration_b).pending_migrations + + assert_equal 1, migrations_b.size + assert_equal migration_list_b.last, migrations_b.first + end + + def test_migrator_db_has_no_schema_migrations_table + _, migrator = migrator_class(3) + migrator = migrator.new(@path_a, @schema_migration_a) + + @schema_migration_a.drop_table + assert_not @connection_a.table_exists?("schema_migrations") + migrator.migrate(1) + assert @connection_a.table_exists?("schema_migrations") + + _, migrator = migrator_class(3) + migrator = migrator.new(@path_b, @schema_migration_b) + + @schema_migration_b.drop_table + assert_not @connection_b.table_exists?("schema_migrations") + migrator.migrate(1) + assert @connection_b.table_exists?("schema_migrations") + end + + def test_migrator_forward + _, migrator = migrator_class(3) + migrator = migrator.new(@path_a, @schema_migration_a) + migrator.migrate(1) + assert_equal(1, migrator.current_version) + + migrator.forward(2) + assert_equal(3, migrator.current_version) + + migrator.forward + assert_equal(3, migrator.current_version) + + _, migrator_b = migrator_class(3) + migrator_b = migrator_b.new(@path_b, @schema_migration_b) + migrator_b.migrate(1) + assert_equal(1, migrator_b.current_version) + + migrator_b.forward(2) + assert_equal(3, migrator_b.current_version) + + migrator_b.forward + assert_equal(3, migrator_b.current_version) + end + + private + def m(name, version) + x = Sensor.new name, version + x.extend(Module.new { + define_method(:up) { yield(:up, x); super() } + define_method(:down) { yield(:down, x); super() } + }) if block_given? + end + + def sensors(count) + calls = [] + migrations = count.times.map { |i| + m(nil, i + 1) { |c, migration| + calls << [c, migration.version] + } + } + [calls, migrations] + end + + def migrator_class(count) + calls, migrations = sensors(count) + + migrator = Class.new(ActiveRecord::MigrationContext) { + define_method(:migrations) { |*| + migrations + } + } + [calls, migrator] + end +end diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb index bb1c1ea17d..b49e62bee6 100644 --- a/activerecord/test/cases/nested_attributes_test.rb +++ b/activerecord/test/cases/nested_attributes_test.rb @@ -851,7 +851,6 @@ module NestedAttributesOnACollectionAssociationTests end private - def association_setter @association_setter ||= "#{@association_name}_attributes=".to_sym end diff --git a/activerecord/test/cases/pooled_connections_test.rb b/activerecord/test/cases/pooled_connections_test.rb index 080aeb0989..d783b2945d 100644 --- a/activerecord/test/cases/pooled_connections_test.rb +++ b/activerecord/test/cases/pooled_connections_test.rb @@ -72,7 +72,6 @@ class PooledConnectionsTest < ActiveRecord::TestCase end private - def add_record(name) ActiveRecord::Base.connection_pool.with_connection { Project.create! name: name } end diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index eb32b690aa..53a4963909 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -335,11 +335,7 @@ class QueryCacheTest < ActiveRecord::TestCase def test_cache_does_not_wrap_results_in_arrays Task.cache do - if current_adapter?(:SQLite3Adapter, :Mysql2Adapter, :PostgreSQLAdapter, :OracleAdapter) - assert_equal 2, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") - else - assert_instance_of String, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") - end + assert_equal 2, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") end end @@ -541,7 +537,6 @@ class QueryCacheTest < ActiveRecord::TestCase end private - def with_temporary_connection_pool old_pool = ActiveRecord::Base.connection_handler.retrieve_connection_pool(ActiveRecord::Base.connection_specification_name) new_pool = ActiveRecord::ConnectionAdapters::ConnectionPool.new ActiveRecord::Base.connection_pool.spec diff --git a/activerecord/test/cases/relation/where_clause_test.rb b/activerecord/test/cases/relation/where_clause_test.rb index b26a1a1d80..35db3d1175 100644 --- a/activerecord/test/cases/relation/where_clause_test.rb +++ b/activerecord/test/cases/relation/where_clause_test.rb @@ -233,7 +233,6 @@ class ActiveRecord::Relation end private - def table Arel::Table.new("table") end diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb index 3f370e5ede..e0743de94b 100644 --- a/activerecord/test/cases/relation_test.rb +++ b/activerecord/test/cases/relation_test.rb @@ -405,7 +405,6 @@ module ActiveRecord end private - def skip_if_sqlite3_version_includes_quoting_bug if sqlite3_version_includes_quoting_bug? skip <<-ERROR.squish diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 4ec695c4c6..5df1e3ccf9 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -298,7 +298,7 @@ class RelationTest < ActiveRecord::TestCase end def test_reverse_order_with_function - topics = Topic.order(Arel.sql("length(title)")).reverse_order + topics = Topic.order("length(title)").reverse_order assert_equal topics(:second).title, topics.first.title end @@ -337,21 +337,21 @@ class RelationTest < ActiveRecord::TestCase def test_reverse_order_with_nulls_first_or_last assert_raises(ActiveRecord::IrreversibleOrderError) do - Topic.order(Arel.sql("title NULLS FIRST")).reverse_order + Topic.order("title NULLS FIRST").reverse_order end assert_raises(ActiveRecord::IrreversibleOrderError) do - Topic.order(Arel.sql("title NULLS FIRST")).reverse_order + Topic.order("title NULLS FIRST").reverse_order end assert_raises(ActiveRecord::IrreversibleOrderError) do - Topic.order(Arel.sql("title nulls last")).reverse_order + Topic.order("title nulls last").reverse_order end assert_raises(ActiveRecord::IrreversibleOrderError) do - Topic.order(Arel.sql("title NULLS FIRST, author_name")).reverse_order + Topic.order("title NULLS FIRST, author_name").reverse_order end assert_raises(ActiveRecord::IrreversibleOrderError) do - Topic.order(Arel.sql("author_name, title nulls last")).reverse_order + Topic.order("author_name, title nulls last").reverse_order end - end + end if current_adapter?(:PostgreSQLAdapter, :OracleAdapter) def test_default_reverse_order_on_table_without_primary_key assert_raises(ActiveRecord::IrreversibleOrderError) do @@ -1679,7 +1679,7 @@ class RelationTest < ActiveRecord::TestCase scope = Post.order("comments.body") assert_equal ["comments"], scope.references_values - scope = Post.order(Arel.sql("#{Comment.quoted_table_name}.#{Comment.quoted_primary_key}")) + scope = Post.order("#{Comment.quoted_table_name}.#{Comment.quoted_primary_key}") if current_adapter?(:OracleAdapter) assert_equal ["COMMENTS"], scope.references_values else @@ -1696,7 +1696,7 @@ class RelationTest < ActiveRecord::TestCase scope = Post.order("comments.body asc") assert_equal ["comments"], scope.references_values - scope = Post.order(Arel.sql("foo(comments.body)")) + scope = Post.order("foo(comments.body)") assert_equal [], scope.references_values end @@ -1704,7 +1704,7 @@ class RelationTest < ActiveRecord::TestCase scope = Post.reorder("comments.body") assert_equal %w(comments), scope.references_values - scope = Post.reorder(Arel.sql("#{Comment.quoted_table_name}.#{Comment.quoted_primary_key}")) + scope = Post.reorder("#{Comment.quoted_table_name}.#{Comment.quoted_primary_key}") if current_adapter?(:OracleAdapter) assert_equal ["COMMENTS"], scope.references_values else @@ -1721,7 +1721,7 @@ class RelationTest < ActiveRecord::TestCase scope = Post.reorder("comments.body asc") assert_equal %w(comments), scope.references_values - scope = Post.reorder(Arel.sql("foo(comments.body)")) + scope = Post.reorder("foo(comments.body)") assert_equal [], scope.references_values end @@ -1955,8 +1955,8 @@ class RelationTest < ActiveRecord::TestCase test "joins with order by custom attribute" do companies = Company.create!([{ name: "test1" }, { name: "test2" }]) companies.each { |company| company.contracts.create! } - assert_equal companies, Company.joins(:contracts).order(:metadata) - assert_equal companies.reverse, Company.joins(:contracts).order(metadata: :desc) + assert_equal companies, Company.joins(:contracts).order(:metadata, :count) + assert_equal companies.reverse, Company.joins(:contracts).order(metadata: :desc, count: :desc) end test "delegations do not leak to other classes" do diff --git a/activerecord/test/cases/schema_loading_test.rb b/activerecord/test/cases/schema_loading_test.rb index f539156466..5da2d9e08f 100644 --- a/activerecord/test/cases/schema_loading_test.rb +++ b/activerecord/test/cases/schema_loading_test.rb @@ -43,7 +43,6 @@ class SchemaLoadingTest < ActiveRecord::TestCase end private - def define_model Class.new(ActiveRecord::Base) do include SchemaLoadCounter diff --git a/activerecord/test/cases/tasks/database_tasks_test.rb b/activerecord/test/cases/tasks/database_tasks_test.rb index ffe94eee0f..6b6861465b 100644 --- a/activerecord/test/cases/tasks/database_tasks_test.rb +++ b/activerecord/test/cases/tasks/database_tasks_test.rb @@ -835,7 +835,6 @@ module ActiveRecord end private - def capture_migration_status capture(:stdout) do ActiveRecord::Tasks::DatabaseTasks.migrate_status diff --git a/activerecord/test/cases/tasks/mysql_rake_test.rb b/activerecord/test/cases/tasks/mysql_rake_test.rb index 552e623fd4..258132835f 100644 --- a/activerecord/test/cases/tasks/mysql_rake_test.rb +++ b/activerecord/test/cases/tasks/mysql_rake_test.rb @@ -100,7 +100,6 @@ if current_adapter?(:Mysql2Adapter) end private - def with_stubbed_connection_establish_connection ActiveRecord::Base.stub(:establish_connection, nil) do ActiveRecord::Base.stub(:connection, @connection) do @@ -180,7 +179,6 @@ if current_adapter?(:Mysql2Adapter) end private - def with_stubbed_connection_establish_connection ActiveRecord::Base.stub(:establish_connection, nil) do ActiveRecord::Base.stub(:connection, @connection) do @@ -233,7 +231,6 @@ if current_adapter?(:Mysql2Adapter) end private - def with_stubbed_connection_establish_connection ActiveRecord::Base.stub(:establish_connection, nil) do ActiveRecord::Base.stub(:connection, @connection) do diff --git a/activerecord/test/cases/tasks/postgresql_rake_test.rb b/activerecord/test/cases/tasks/postgresql_rake_test.rb index 065ba7734c..f9df650687 100644 --- a/activerecord/test/cases/tasks/postgresql_rake_test.rb +++ b/activerecord/test/cases/tasks/postgresql_rake_test.rb @@ -139,7 +139,6 @@ if current_adapter?(:PostgreSQLAdapter) end private - def with_stubbed_connection_establish_connection ActiveRecord::Base.stub(:connection, @connection) do ActiveRecord::Base.stub(:establish_connection, nil) do @@ -201,7 +200,6 @@ if current_adapter?(:PostgreSQLAdapter) end private - def with_stubbed_connection_establish_connection ActiveRecord::Base.stub(:connection, @connection) do ActiveRecord::Base.stub(:establish_connection, nil) do @@ -301,7 +299,6 @@ if current_adapter?(:PostgreSQLAdapter) end private - def with_stubbed_connection ActiveRecord::Base.stub(:connection, @connection) do yield diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb index 100bd6a925..19b89ab08c 100644 --- a/activerecord/test/cases/transaction_callbacks_test.rb +++ b/activerecord/test/cases/transaction_callbacks_test.rb @@ -460,7 +460,6 @@ class TransactionCallbacksTest < ActiveRecord::TestCase end private - def add_transaction_execution_blocks(record) record.after_commit_block(:create) { |r| r.history << :commit_on_create } record.after_commit_block(:update) { |r| r.history << :commit_on_update } diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb index 6795996cca..b5c1cac3d9 100644 --- a/activerecord/test/cases/transactions_test.rb +++ b/activerecord/test/cases/transactions_test.rb @@ -1077,7 +1077,6 @@ class TransactionTest < ActiveRecord::TestCase end private - %w(validation save destroy).each do |filter| define_method("add_cancelling_before_#{filter}_with_db_side_effect_to_topic") do |topic| meta = class << topic; self; end diff --git a/activerecord/test/cases/unsafe_raw_sql_test.rb b/activerecord/test/cases/unsafe_raw_sql_test.rb index d5d8f2a09a..87edb163f2 100644 --- a/activerecord/test/cases/unsafe_raw_sql_test.rb +++ b/activerecord/test/cases/unsafe_raw_sql_test.rb @@ -77,7 +77,7 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase assert_equal ids_expected, ids_disabled end - test "order: allows table and column name" do + test "order: allows table and column names" do ids_expected = Post.order(Arel.sql("title")).pluck(:id) ids_depr = with_unsafe_raw_sql_deprecated { Post.order("posts.title").pluck(:id) } @@ -87,6 +87,17 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase assert_equal ids_expected, ids_disabled end + test "order: allows quoted table and column names" do + ids_expected = Post.order(Arel.sql("title")).pluck(:id) + + quoted_title = Post.connection.quote_table_name("posts.title") + ids_depr = with_unsafe_raw_sql_deprecated { Post.order(quoted_title).pluck(:id) } + ids_disabled = with_unsafe_raw_sql_disabled { Post.order(quoted_title).pluck(:id) } + + assert_equal ids_expected, ids_depr + assert_equal ids_expected, ids_disabled + end + test "order: allows column name and direction in string" do ids_expected = Post.order(Arel.sql("title desc")).pluck(:id) @@ -116,10 +127,10 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase ["asc", "desc", ""].each do |direction| %w(first last).each do |position| - ids_expected = Post.order(Arel.sql("type #{direction} nulls #{position}")).pluck(:id) + ids_expected = Post.order(Arel.sql("type::text #{direction} nulls #{position}")).pluck(:id) - ids_depr = with_unsafe_raw_sql_deprecated { Post.order("type #{direction} nulls #{position}").pluck(:id) } - ids_disabled = with_unsafe_raw_sql_disabled { Post.order("type #{direction} nulls #{position}").pluck(:id) } + ids_depr = with_unsafe_raw_sql_deprecated { Post.order("type::text #{direction} nulls #{position}").pluck(:id) } + ids_disabled = with_unsafe_raw_sql_disabled { Post.order("type::text #{direction} nulls #{position}").pluck(:id) } assert_equal ids_expected, ids_depr assert_equal ids_expected, ids_disabled @@ -130,7 +141,7 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase test "order: disallows invalid column name" do with_unsafe_raw_sql_disabled do assert_raises(ActiveRecord::UnknownAttributeReference) do - Post.order("len(title) asc").pluck(:id) + Post.order("REPLACE(title, 'misc', 'zzzz') asc").pluck(:id) end end end @@ -146,7 +157,7 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase test "order: disallows invalid column with direction" do with_unsafe_raw_sql_disabled do assert_raises(ActiveRecord::UnknownAttributeReference) do - Post.order("len(title)" => :asc).pluck(:id) + Post.order("REPLACE(title, 'misc', 'zzzz')" => :asc).pluck(:id) end end end @@ -179,7 +190,7 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase test "order: disallows invalid Array arguments" do with_unsafe_raw_sql_disabled do assert_raises(ActiveRecord::UnknownAttributeReference) do - Post.order(["author_id", "length(title)"]).pluck(:id) + Post.order(["author_id", "REPLACE(title, 'misc', 'zzzz')"]).pluck(:id) end end end @@ -187,8 +198,8 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase test "order: allows valid Array arguments" do ids_expected = Post.order(Arel.sql("author_id, length(title)")).pluck(:id) - ids_depr = with_unsafe_raw_sql_deprecated { Post.order(["author_id", Arel.sql("length(title)")]).pluck(:id) } - ids_disabled = with_unsafe_raw_sql_disabled { Post.order(["author_id", Arel.sql("length(title)")]).pluck(:id) } + ids_depr = with_unsafe_raw_sql_deprecated { Post.order(["author_id", "length(title)"]).pluck(:id) } + ids_disabled = with_unsafe_raw_sql_disabled { Post.order(["author_id", "length(title)"]).pluck(:id) } assert_equal ids_expected, ids_depr assert_equal ids_expected, ids_disabled @@ -197,7 +208,7 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase test "order: logs deprecation warning for unrecognized column" do with_unsafe_raw_sql_deprecated do assert_deprecated(/Dangerous query method/) do - Post.order("length(title)") + Post.order("REPLACE(title, 'misc', 'zzzz')") end end end @@ -212,6 +223,16 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase assert_equal titles_expected, titles_disabled end + test "pluck: allows string column name with function and alias" do + titles_expected = Post.pluck(Arel.sql("UPPER(title)")) + + titles_depr = with_unsafe_raw_sql_deprecated { Post.pluck("UPPER(title) AS title") } + titles_disabled = with_unsafe_raw_sql_disabled { Post.pluck("UPPER(title) AS title") } + + assert_equal titles_expected, titles_depr + assert_equal titles_expected, titles_disabled + end + test "pluck: allows symbol column name" do titles_expected = Post.pluck(Arel.sql("title")) @@ -262,10 +283,21 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase assert_equal titles_expected, titles_disabled end + test "pluck: allows quoted table and column names" do + titles_expected = Post.pluck(Arel.sql("title")) + + quoted_title = Post.connection.quote_table_name("posts.title") + titles_depr = with_unsafe_raw_sql_deprecated { Post.pluck(quoted_title) } + titles_disabled = with_unsafe_raw_sql_disabled { Post.pluck(quoted_title) } + + assert_equal titles_expected, titles_depr + assert_equal titles_expected, titles_disabled + end + test "pluck: disallows invalid column name" do with_unsafe_raw_sql_disabled do assert_raises(ActiveRecord::UnknownAttributeReference) do - Post.pluck("length(title)") + Post.pluck("REPLACE(title, 'misc', 'zzzz')") end end end @@ -273,7 +305,7 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase test "pluck: disallows invalid column name amongst valid names" do with_unsafe_raw_sql_disabled do assert_raises(ActiveRecord::UnknownAttributeReference) do - Post.pluck(:title, "length(title)") + Post.pluck(:title, "REPLACE(title, 'misc', 'zzzz')") end end end @@ -281,7 +313,7 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase test "pluck: disallows invalid column names with includes" do with_unsafe_raw_sql_disabled do assert_raises(ActiveRecord::UnknownAttributeReference) do - Post.includes(:comments).pluck(:title, "length(title)") + Post.includes(:comments).pluck(:title, "REPLACE(title, 'misc', 'zzzz')") end end end @@ -296,24 +328,25 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase test "pluck: logs deprecation warning" do with_unsafe_raw_sql_deprecated do assert_deprecated(/Dangerous query method/) do - Post.includes(:comments).pluck(:title, "length(title)") + Post.includes(:comments).pluck(:title, "REPLACE(title, 'misc', 'zzzz')") end end end - def with_unsafe_raw_sql_disabled(&blk) - with_config(:disabled, &blk) - end + private + def with_unsafe_raw_sql_disabled(&block) + with_config(:disabled, &block) + end - def with_unsafe_raw_sql_deprecated(&blk) - with_config(:deprecated, &blk) - end + def with_unsafe_raw_sql_deprecated(&block) + with_config(:deprecated, &block) + end - def with_config(new_value, &blk) - old_value = ActiveRecord::Base.allow_unsafe_raw_sql - ActiveRecord::Base.allow_unsafe_raw_sql = new_value - blk.call - ensure - ActiveRecord::Base.allow_unsafe_raw_sql = old_value - end + def with_config(new_value, &block) + old_value = ActiveRecord::Base.allow_unsafe_raw_sql + ActiveRecord::Base.allow_unsafe_raw_sql = new_value + yield + ensure + ActiveRecord::Base.allow_unsafe_raw_sql = old_value + end end diff --git a/activerecord/test/cases/yaml_serialization_test.rb b/activerecord/test/cases/yaml_serialization_test.rb index 60ebdce178..7003afa33a 100644 --- a/activerecord/test/cases/yaml_serialization_test.rb +++ b/activerecord/test/cases/yaml_serialization_test.rb @@ -130,7 +130,6 @@ class YamlSerializationTest < ActiveRecord::TestCase end private - def yaml_fixture(file_name) path = File.expand_path( "../support/yaml_compatibility_fixtures/#{file_name}.yml", diff --git a/activerecord/test/models/club.rb b/activerecord/test/models/club.rb index bb49fb300c..890e427616 100644 --- a/activerecord/test/models/club.rb +++ b/activerecord/test/models/club.rb @@ -15,7 +15,6 @@ class Club < ActiveRecord::Base accepts_nested_attributes_for :membership private - def private_method "I'm sorry sir, this is a *private* club, not a *pirate* club" end diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb index a0f48d23f1..339b5c8ca8 100644 --- a/activerecord/test/models/company.rb +++ b/activerecord/test/models/company.rb @@ -25,7 +25,6 @@ class Company < AbstractCompany end private - def private_method "I am Jack's innermost fears and aspirations" end diff --git a/activerecord/test/models/company_in_module.rb b/activerecord/test/models/company_in_module.rb index 52b7e06a63..320b26b950 100644 --- a/activerecord/test/models/company_in_module.rb +++ b/activerecord/test/models/company_in_module.rb @@ -91,7 +91,6 @@ module MyApplication validate :check_empty_credit_limit private - def check_empty_credit_limit errors.add("credit_card", :blank) if credit_card.blank? end diff --git a/activerecord/test/models/person.rb b/activerecord/test/models/person.rb index c3d15a571a..0dfd29e45e 100644 --- a/activerecord/test/models/person.rb +++ b/activerecord/test/models/person.rb @@ -101,7 +101,6 @@ class RichPerson < ActiveRecord::Base before_validation :run_before_validation private - def run_before_create self.first_name = first_name.to_s + "run_before_create" end diff --git a/activerecord/test/models/topic.rb b/activerecord/test/models/topic.rb index 77101090f2..7a864c728c 100644 --- a/activerecord/test/models/topic.rb +++ b/activerecord/test/models/topic.rb @@ -93,7 +93,6 @@ class Topic < ActiveRecord::Base end private - def default_written_on self.written_on = Time.now unless attribute_present?("written_on") end diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index 41920b3719..eed18a7b89 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -261,6 +261,7 @@ ActiveRecord::Schema.define do t.references :developer, index: false t.references :company, index: false t.string :metadata + t.integer :count end create_table :customers, force: true do |t| diff --git a/activerecord/test/support/config.rb b/activerecord/test/support/config.rb index de0d90a18f..66ae57b382 100644 --- a/activerecord/test/support/config.rb +++ b/activerecord/test/support/config.rb @@ -12,7 +12,6 @@ module ARTest end private - def config_file Pathname.new(ENV["ARCONFIG"] || TEST_ROOT + "/config.yml") end |