aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG.md110
-rw-r--r--activerecord/lib/active_record/associations/association.rb2
-rw-r--r--activerecord/lib/active_record/associations/association_scope.rb16
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb14
-rw-r--r--activerecord/lib/active_record/associations/collection_proxy.rb39
-rw-r--r--activerecord/lib/active_record/associations/join_dependency.rb2
-rw-r--r--activerecord/lib/active_record/associations/join_dependency/join_association.rb27
-rw-r--r--activerecord/lib/active_record/attribute_methods/dirty.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb36
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/quoting.rb17
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb10
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb32
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb20
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb20
-rw-r--r--activerecord/lib/active_record/connection_adapters/connection_specification.rb9
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/schema_creation.rb8
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/schema_definitions.rb5
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb7
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb48
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb12
-rw-r--r--activerecord/lib/active_record/fixtures.rb3
-rw-r--r--activerecord/lib/active_record/gem_version.rb2
-rw-r--r--activerecord/lib/active_record/migration.rb49
-rw-r--r--activerecord/lib/active_record/null_relation.rb2
-rw-r--r--activerecord/lib/active_record/railties/databases.rake22
-rw-r--r--activerecord/lib/active_record/reflection.rb83
-rw-r--r--activerecord/lib/active_record/relation.rb4
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb17
-rw-r--r--activerecord/lib/active_record/relation/delegation.rb2
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb202
-rw-r--r--activerecord/lib/active_record/result.rb13
-rw-r--r--activerecord/lib/active_record/sanitization.rb3
-rw-r--r--activerecord/lib/active_record/schema_dumper.rb2
-rw-r--r--activerecord/lib/active_record/schema_migration.rb6
-rw-r--r--activerecord/lib/active_record/transactions.rb2
-rw-r--r--activerecord/lib/active_record/type/decimal_without_scale.rb4
-rw-r--r--activerecord/lib/active_record/type/serialized.rb2
-rw-r--r--activerecord/lib/rails/generators/active_record/migration.rb2
-rw-r--r--activerecord/test/cases/adapter_test.rb10
-rw-r--r--activerecord/test/cases/adapters/mysql2/connection_test.rb30
-rw-r--r--activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb11
-rw-r--r--activerecord/test/cases/adapters/postgresql/connection_test.rb4
-rw-r--r--activerecord/test/cases/adapters/postgresql/json_test.rb10
-rw-r--r--activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb11
-rw-r--r--activerecord/test/cases/adapters/postgresql/quoting_test.rb1
-rw-r--r--activerecord/test/cases/adapters/sqlite3/quoting_test.rb51
-rw-r--r--activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb16
-rw-r--r--activerecord/test/cases/ar_schema_test.rb217
-rw-r--r--activerecord/test/cases/associations/eager_singularization_test.rb257
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb11
-rw-r--r--activerecord/test/cases/associations/required_test.rb42
-rw-r--r--activerecord/test/cases/associations_test.rb5
-rw-r--r--activerecord/test/cases/attribute_methods_test.rb7
-rw-r--r--activerecord/test/cases/calculations_test.rb17
-rw-r--r--activerecord/test/cases/connection_adapters/connection_handler_test.rb60
-rw-r--r--activerecord/test/cases/connection_pool_test.rb5
-rw-r--r--activerecord/test/cases/date_time_test.rb2
-rw-r--r--activerecord/test/cases/defaults_test.rb12
-rw-r--r--activerecord/test/cases/dirty_test.rb21
-rw-r--r--activerecord/test/cases/finder_test.rb6
-rw-r--r--activerecord/test/cases/fixtures_test.rb98
-rw-r--r--activerecord/test/cases/migration/change_schema_test.rb2
-rw-r--r--activerecord/test/cases/migration/columns_test.rb10
-rw-r--r--activerecord/test/cases/migration/create_join_table_test.rb13
-rw-r--r--activerecord/test/cases/migration/pending_migrations_test.rb12
-rw-r--r--activerecord/test/cases/migration/references_foreign_key_test.rb16
-rw-r--r--activerecord/test/cases/migration/references_statements_test.rb7
-rw-r--r--activerecord/test/cases/migration_test.rb18
-rw-r--r--activerecord/test/cases/migrator_test.rb61
-rw-r--r--activerecord/test/cases/primary_keys_test.rb16
-rw-r--r--activerecord/test/cases/query_cache_test.rb12
-rw-r--r--activerecord/test/cases/quoting_test.rb85
-rw-r--r--activerecord/test/cases/relation/delegation_test.rb2
-rw-r--r--activerecord/test/cases/sanitize_test.rb10
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb15
-rw-r--r--activerecord/test/cases/scoping/default_scoping_test.rb2
-rw-r--r--activerecord/test/cases/scoping/named_scoping_test.rb2
-rw-r--r--activerecord/test/cases/transaction_callbacks_test.rb40
-rw-r--r--activerecord/test/cases/validations/uniqueness_validation_test.rb2
-rw-r--r--activerecord/test/schema/mysql2_specific_schema.rb5
-rw-r--r--activerecord/test/support/connection.rb5
86 files changed, 1328 insertions, 795 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 116363f2d9..96094a285f 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,111 @@
+* Deprecate `Migrator.schema_migrations_table_name`.
+
+ *Ryuta Kamizono*
+
+* Fix select with block doesn't return newly built records in has_many association.
+
+ Fixes #28348.
+
+ *Ryuta Kamizono*
+
+* Check whether `Rails.application` defined before calling it
+
+ In #27674 we changed the migration generator to generate migrations at the
+ path defined in `Rails.application.config.paths` however the code checked
+ for the presence of the `Rails` constant but not the `Rails.application`
+ method which caused problems when using Active Record and generators outside
+ of the context of a Rails application.
+
+ Fixes #28325.
+
+ *Andrew White*
+
+* Fix `deserialize` with JSON array.
+
+ Fixes #28285.
+
+ *Ryuta Kamizono*
+
+* Fix `rake db:schema:load` with subdirectories.
+
+ *Ryuta Kamizono*
+
+* Fix `rake db:migrate:status` with subdirectories.
+
+ *Ryuta Kamizono*
+
+* Don't share options between reference id and type columns
+
+ When using a polymorphic reference column in a migration, sharing options
+ between the two columns doesn't make sense since they are different types.
+ The `reference_id` column is usually an integer and the `reference_type`
+ column a string so options like `unsigned: true` will result in an invalid
+ table definition.
+
+ *Ryuta Kamizono*
+
+* Use `max_identifier_length` for `index_name_length` in PostgreSQL adapter.
+
+ *Ryuta Kamizono*
+
+* Deprecate `supports_migrations?` on connection adapters.
+
+ *Ryuta Kamizono*
+
+* Fix regression of #1969 with SELECT aliases in HAVING clause.
+
+ *Eugene Kenny*
+
+* Deprecate using `#quoted_id` in quoting.
+
+ *Ryuta Kamizono*
+
+* Fix `wait_timeout` to configurable for mysql2 adapter.
+
+ Fixes #26556.
+
+ *Ryuta Kamizono*
+
+
+## Rails 5.1.0.beta1 (February 23, 2017) ##
+
+* Correctly dump native timestamp types for MySQL.
+
+ The native timestamp type in MySQL is different from datetime type.
+ Internal representation of the timestamp type is UNIX time, This means
+ that timestamp columns are affected by time zone.
+
+ > SET time_zone = '+00:00';
+ Query OK, 0 rows affected (0.00 sec)
+
+ > INSERT INTO time_with_zone(ts,dt) VALUES (NOW(),NOW());
+ Query OK, 1 row affected (0.02 sec)
+
+ > SELECT * FROM time_with_zone;
+ +---------------------+---------------------+
+ | ts | dt |
+ +---------------------+---------------------+
+ | 2016-02-07 22:11:44 | 2016-02-07 22:11:44 |
+ +---------------------+---------------------+
+ 1 row in set (0.00 sec)
+
+ > SET time_zone = '-08:00';
+ Query OK, 0 rows affected (0.00 sec)
+
+ > SELECT * FROM time_with_zone;
+ +---------------------+---------------------+
+ | ts | dt |
+ +---------------------+---------------------+
+ | 2016-02-07 14:11:44 | 2016-02-07 22:11:44 |
+ +---------------------+---------------------+
+ 1 row in set (0.00 sec)
+
+ *Ryuta Kamizono*
+
+* All integer-like PKs are autoincrement unless they have an explicit default.
+
+ *Matthew Draper*
+
* Omit redundant `using: :btree` for schema dumping.
*Ryuta Kamizono*
@@ -81,7 +189,7 @@
*Ryuta Kamizono*
-* Add the touch option to ActiveRecord#increment! and decrement!.
+* Add the touch option to `#increment!` and `#decrement!`.
*Hiroaki Izu*
diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb
index 84d0493a60..1cb2b2d7c6 100644
--- a/activerecord/lib/active_record/associations/association.rb
+++ b/activerecord/lib/active_record/associations/association.rb
@@ -83,7 +83,7 @@ module ActiveRecord
end
def scope
- target_scope.merge(association_scope)
+ target_scope.merge!(association_scope)
end
# The scope for this association.
diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb
index badde9973f..120d75416c 100644
--- a/activerecord/lib/active_record/associations/association_scope.rb
+++ b/activerecord/lib/active_record/associations/association_scope.rb
@@ -25,7 +25,7 @@ module ActiveRecord
chain_head, chain_tail = get_chain(reflection, association, alias_tracker)
scope.extending! Array(reflection.options[:extend])
- add_constraints(scope, owner, klass, reflection, chain_head, chain_tail)
+ add_constraints(scope, owner, reflection, chain_head, chain_tail)
end
def join_type
@@ -60,8 +60,8 @@ module ActiveRecord
table.create_join(table, table.create_on(constraint), join_type)
end
- def last_chain_scope(scope, table, reflection, owner, association_klass)
- join_keys = reflection.join_keys(association_klass)
+ def last_chain_scope(scope, table, reflection, owner)
+ join_keys = reflection.join_keys
key = join_keys.key
foreign_key = join_keys.foreign_key
@@ -80,8 +80,8 @@ module ActiveRecord
value_transformation.call(value)
end
- def next_chain_scope(scope, table, reflection, association_klass, foreign_table, next_reflection)
- join_keys = reflection.join_keys(association_klass)
+ def next_chain_scope(scope, table, reflection, foreign_table, next_reflection)
+ join_keys = reflection.join_keys
key = join_keys.key
foreign_key = join_keys.foreign_key
@@ -120,10 +120,10 @@ module ActiveRecord
[runtime_reflection, previous_reflection]
end
- def add_constraints(scope, owner, association_klass, refl, chain_head, chain_tail)
+ def add_constraints(scope, owner, refl, chain_head, chain_tail)
owner_reflection = chain_tail
table = owner_reflection.alias_name
- scope = last_chain_scope(scope, table, owner_reflection, owner, association_klass)
+ scope = last_chain_scope(scope, table, owner_reflection, owner)
reflection = chain_head
while reflection
@@ -132,7 +132,7 @@ module ActiveRecord
unless reflection == chain_tail
foreign_table = next_reflection.alias_name
- scope = next_chain_scope(scope, table, reflection, association_klass, foreign_table, next_reflection)
+ scope = next_chain_scope(scope, table, reflection, foreign_table, next_reflection)
end
# Exclude the scope of the association itself, because that
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index 0437a79b84..77282e6463 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -30,13 +30,7 @@ module ActiveRecord
reload
end
- if null_scope?
- # Cache the proxy separately before the owner has an id
- # or else a post-save proxy will still lack the id
- @null_proxy ||= CollectionProxy.create(klass, self)
- else
- @proxy ||= CollectionProxy.create(klass, self)
- end
+ CollectionProxy.create(klass, self)
end
# Implements the writer method, e.g. foo.items= for Foo.has_many :items
@@ -315,9 +309,9 @@ module ActiveRecord
record
end
- def scope(opts = {})
- scope = super()
- scope.none! if opts.fetch(:nullify, true) && null_scope?
+ def scope
+ scope = super
+ scope.none! if null_scope?
scope
end
diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb
index 0d84805b4d..bc2f359c65 100644
--- a/activerecord/lib/active_record/associations/collection_proxy.rb
+++ b/activerecord/lib/active_record/associations/collection_proxy.rb
@@ -28,12 +28,9 @@ module ActiveRecord
# is computed directly through SQL and does not trigger by itself the
# instantiation of the actual post records.
class CollectionProxy < Relation
- delegate :exists?, :update_all, :arel, to: :scope
-
def initialize(klass, association) #:nodoc:
@association = association
super klass, klass.arel_table, klass.predicate_builder
- merge! association.scope(nullify: false)
end
def target
@@ -81,7 +78,7 @@ module ActiveRecord
# # #<Pet id: nil, name: "Choo-Choo">
# # ]
#
- # person.pets.select(:id, :name )
+ # person.pets.select(:id, :name)
# # => [
# # #<Pet id: 1, name: "Fancy-Fancy">,
# # #<Pet id: 2, name: "Spook">,
@@ -956,19 +953,10 @@ module ActiveRecord
@association
end
- # We don't want this object to be put on the scoping stack, because
- # that could create an infinite loop where we call an @association
- # method, which gets the current scope, which is this object, which
- # delegates to @association, and so on.
- def scoping
- @association.scope.scoping { yield }
- end
-
# Returns a <tt>Relation</tt> object for the records in this association
def scope
- @association.scope
+ @scope ||= @association.scope
end
- alias spawn scope
# Equivalent to <tt>Array#==</tt>. Returns +true+ if the two arrays
# contain the same number of elements and if each element is equal
@@ -1100,6 +1088,7 @@ module ActiveRecord
# person.pets(true) # fetches pets from the database
# # => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
def reload
+ @scope = nil
proxy_association.reload
self
end
@@ -1121,11 +1110,21 @@ module ActiveRecord
# person.pets # fetches pets from the database
# # => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
def reset
+ @scope = nil
proxy_association.reset
proxy_association.reset_scope
self
end
+ delegate_methods = [
+ QueryMethods,
+ SpawnMethods,
+ ].flat_map { |klass|
+ klass.public_instance_methods(false)
+ } - self.public_instance_methods(false) - [:select] + [:scoping]
+
+ delegate(*delegate_methods, to: :scope)
+
private
def find_nth_with_limit(index, limit)
@@ -1149,6 +1148,18 @@ module ActiveRecord
def exec_queries
load_target
end
+
+ def respond_to_missing?(method, _)
+ scope.respond_to?(method) || super
+ end
+
+ def method_missing(method, *args, &block)
+ if scope.respond_to?(method)
+ scope.public_send(method, *args, &block)
+ else
+ super
+ end
+ end
end
end
end
diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb
index 87e0847ec1..8995b1e352 100644
--- a/activerecord/lib/active_record/associations/join_dependency.rb
+++ b/activerecord/lib/active_record/associations/join_dependency.rb
@@ -171,7 +171,7 @@ module ActiveRecord
chain = child.reflection.chain
foreign_table = parent.table
foreign_klass = parent.base_klass
- child.join_constraints(foreign_table, foreign_klass, child, join_type, tables, chain)
+ child.join_constraints(foreign_table, foreign_klass, join_type, tables, chain)
end
def make_outer_joins(parent, child)
diff --git a/activerecord/lib/active_record/associations/join_dependency/join_association.rb b/activerecord/lib/active_record/associations/join_dependency/join_association.rb
index f5fcba1236..97cfec0302 100644
--- a/activerecord/lib/active_record/associations/join_dependency/join_association.rb
+++ b/activerecord/lib/active_record/associations/join_dependency/join_association.rb
@@ -23,7 +23,7 @@ module ActiveRecord
JoinInformation = Struct.new :joins, :binds
- def join_constraints(foreign_table, foreign_klass, node, join_type, tables, chain)
+ def join_constraints(foreign_table, foreign_klass, join_type, tables, chain)
joins = []
binds = []
tables = tables.reverse
@@ -34,35 +34,16 @@ module ActiveRecord
table = tables.shift
klass = reflection.klass
- join_keys = reflection.join_keys(klass)
+ join_keys = reflection.join_keys
key = join_keys.key
foreign_key = join_keys.foreign_key
constraint = build_constraint(klass, table, key, foreign_table, foreign_key)
predicate_builder = PredicateBuilder.new(TableMetadata.new(klass, table))
- scope_chain_items = reflection.scopes.map do |item|
- if item.is_a?(Relation)
- item
- else
- ActiveRecord::Relation.create(klass, table, predicate_builder)
- .instance_exec(node, &item)
- end
- end
+ scope_chain_items = reflection.join_scopes(table, predicate_builder)
+ klass_scope = reflection.klass_join_scope(table, predicate_builder)
- klass_scope =
- if klass.current_scope
- klass.current_scope.clone.tap { |scope|
- scope.joins_values = []
- }
- else
- relation = ActiveRecord::Relation.create(
- klass,
- table,
- predicate_builder,
- )
- klass.send(:build_default_scope, relation)
- end
scope_chain_items.concat [klass_scope].compact
rel = scope_chain_items.inject(scope_chain_items.shift) do |left, right|
diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb
index 31c1e687dc..6aa414ba6b 100644
--- a/activerecord/lib/active_record/attribute_methods/dirty.rb
+++ b/activerecord/lib/active_record/attribute_methods/dirty.rb
@@ -50,7 +50,7 @@ module ActiveRecord
super.tap do
@previous_mutation_tracker = nil
clear_mutation_trackers
- @changed_attributes = HashWithIndifferentAccess.new
+ @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
end
end
@@ -70,13 +70,13 @@ module ActiveRecord
def changes_applied
@previous_mutation_tracker = mutation_tracker
- @changed_attributes = HashWithIndifferentAccess.new
+ @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
clear_mutation_trackers
end
def clear_changes_information
@previous_mutation_tracker = nil
- @changed_attributes = HashWithIndifferentAccess.new
+ @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
forget_attribute_assignments
clear_mutation_trackers
end
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 ce4721c99d..3f2e86a98d 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -353,6 +353,16 @@ module ActiveRecord
@threads_blocking_new_connections = 0
@available = ConnectionLeasingQueue.new self
+
+ @lock_thread = false
+ end
+
+ def lock_thread=(lock_thread)
+ if lock_thread
+ @lock_thread = Thread.current
+ else
+ @lock_thread = nil
+ end
end
# Retrieve the connection associated with the current thread, or call
@@ -361,7 +371,7 @@ module ActiveRecord
# #connection can be called any number of times; the connection is
# held in a cache keyed by a thread.
def connection
- @thread_cached_conns[connection_cache_key(Thread.current)] ||= checkout
+ @thread_cached_conns[connection_cache_key(@lock_thread || Thread.current)] ||= checkout
end
# Returns true if there is an open connection being used for the current thread.
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 7eab7de5d3..e53ba4e666 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb
@@ -83,7 +83,9 @@ module ActiveRecord
# the same SQL query and repeatedly return the same result each time, silently
# undermining the randomness you were expecting.
def clear_query_cache
- @query_cache.clear
+ @lock.synchronize do
+ @query_cache.clear
+ end
end
def select_all(arel, name = nil, binds = [], preparable: nil)
@@ -99,21 +101,23 @@ module ActiveRecord
private
def cache_sql(sql, name, binds)
- result =
- if @query_cache[sql].key?(binds)
- ActiveSupport::Notifications.instrument(
- "sql.active_record",
- sql: sql,
- binds: binds,
- name: name,
- connection_id: object_id,
- cached: true,
- )
- @query_cache[sql][binds]
- else
- @query_cache[sql][binds] = yield
- end
- result.dup
+ @lock.synchronize do
+ result =
+ if @query_cache[sql].key?(binds)
+ ActiveSupport::Notifications.instrument(
+ "sql.active_record",
+ sql: sql,
+ binds: binds,
+ name: name,
+ connection_id: object_id,
+ cached: true,
+ )
+ @query_cache[sql][binds]
+ else
+ @query_cache[sql][binds] = yield
+ end
+ result.dup
+ end
end
# If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
index 7f4132accf..e5a24b2aca 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
@@ -7,8 +7,13 @@ module ActiveRecord
# Quotes the column value to help prevent
# {SQL injection attacks}[http://en.wikipedia.org/wiki/SQL_injection].
def quote(value)
- # records are quoted as their primary key
- return value.quoted_id if value.respond_to?(:quoted_id)
+ value = id_value_for_database(value) if value.is_a?(Base)
+
+ if value.respond_to?(:quoted_id)
+ ActiveSupport::Deprecation.warn \
+ "Using #quoted_id is deprecated and will be removed in Rails 5.2."
+ return value.quoted_id
+ end
_quote(value)
end
@@ -17,6 +22,8 @@ module ActiveRecord
# SQLite does not understand dates, so this method will convert a Date
# to a String.
def type_cast(value, column = nil)
+ value = id_value_for_database(value) if value.is_a?(Base)
+
if value.respond_to?(:quoted_id) && value.respond_to?(:id)
return value.id
end
@@ -151,6 +158,12 @@ module ActiveRecord
binds.map { |attr| type_cast(attr.value_for_database) }
end
+ def id_value_for_database(value)
+ if primary_key = value.class.primary_key
+ value.instance_variable_get(:@attributes)[primary_key].value_for_database
+ end
+ end
+
def types_which_need_no_typecasting
[nil, Numeric, String]
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
index 5eb7787226..4682afc188 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -116,16 +116,12 @@ module ActiveRecord
private
- def as_options(value, default = {})
- if value.is_a?(Hash)
- value
- else
- default
- end
+ def as_options(value)
+ value.is_a?(Hash) ? value : {}
end
def polymorphic_options
- as_options(polymorphic, options)
+ as_options(polymorphic)
end
def index_options
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 1ef2c4c860..1e826ff5ad 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -281,8 +281,8 @@ module ActiveRecord
yield td if block_given?
- if options[:force] && data_source_exists?(table_name)
- drop_table(table_name, options)
+ if options[:force]
+ drop_table(table_name, **options, if_exists: true)
end
result = execute schema_creation.accept td
@@ -342,18 +342,16 @@ module ActiveRecord
# part_id int NOT NULL,
# ) ENGINE=InnoDB DEFAULT CHARSET=utf8
#
- def create_join_table(table_1, table_2, options = {})
+ def create_join_table(table_1, table_2, column_options: {}, **options)
join_table_name = find_join_table_name(table_1, table_2, options)
- column_options = options.delete(:column_options) || {}
- column_options.reverse_merge!(null: false)
- type = column_options.delete(:type) || :integer
+ column_options.reverse_merge!(null: false, index: false)
- t1_column, t2_column = [table_1, table_2].map { |t| t.to_s.singularize.foreign_key }
+ t1_ref, t2_ref = [table_1, table_2].map { |t| t.to_s.singularize }
create_table(join_table_name, options.merge!(id: false)) do |td|
- td.send type, t1_column, column_options
- td.send type, t2_column, column_options
+ td.references t1_ref, column_options
+ td.references t2_ref, column_options
yield td if block_given?
end
end
@@ -865,6 +863,7 @@ module ActiveRecord
else
foreign_key_options = { to_table: reference_name }
end
+ foreign_key_options[:column] ||= "#{ref_name}_id"
remove_foreign_key(table_name, **foreign_key_options)
end
@@ -1000,12 +999,12 @@ module ActiveRecord
end
def dump_schema_information #:nodoc:
- versions = ActiveRecord::SchemaMigration.order("version").pluck(:version)
+ versions = ActiveRecord::SchemaMigration.all_versions
insert_versions_sql(versions)
end
def insert_versions_sql(versions) # :nodoc:
- sm_table = quote_table_name(ActiveRecord::Migrator.schema_migrations_table_name)
+ sm_table = quote_table_name(ActiveRecord::SchemaMigration.table_name)
if versions.is_a?(Array)
sql = "INSERT INTO #{sm_table} (version) VALUES\n"
@@ -1034,12 +1033,11 @@ module ActiveRecord
def assume_migrated_upto_version(version, migrations_paths)
migrations_paths = Array(migrations_paths)
version = version.to_i
- sm_table = quote_table_name(ActiveRecord::Migrator.schema_migrations_table_name)
+ sm_table = quote_table_name(ActiveRecord::SchemaMigration.table_name)
- migrated = select_values("SELECT version FROM #{sm_table}").map(&:to_i)
- paths = migrations_paths.map { |p| "#{p}/[0-9]*_*.rb" }
- versions = Dir[*paths].map do |filename|
- filename.split("/").last.split("_").first.to_i
+ migrated = ActiveRecord::SchemaMigration.all_versions.map(&:to_i)
+ versions = ActiveRecord::Migrator.migration_files(migrations_paths).map do |file|
+ ActiveRecord::Migrator.parse_migration_filename(file).first.to_i
end
unless migrated.include?(version)
@@ -1079,7 +1077,7 @@ module ActiveRecord
raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale is specified"
end
- elsif [:datetime, :time, :interval].include?(type) && precision ||= native[:precision]
+ elsif [:datetime, :timestamp, :time, :interval].include?(type) && precision ||= native[:precision]
if (0..6) === precision
column_type_sql << "(#{precision})"
else
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index 6b14a498df..ef1d9f81a9 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -107,6 +107,7 @@ module ActiveRecord
@schema_cache = SchemaCache.new self
@quoted_column_names, @quoted_table_names = {}, {}
@visitor = arel_visitor
+ @lock = Monitor.new
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
@prepared_statements = true
@@ -153,8 +154,8 @@ module ActiveRecord
Arel::Visitors::ToSql.new(self)
end
- def valid_type?(type)
- false
+ def valid_type?(type) # :nodoc:
+ !native_database_types[type].nil?
end
def schema_creation
@@ -231,10 +232,10 @@ module ActiveRecord
self.class::ADAPTER_NAME
end
- # Does this adapter support migrations?
- def supports_migrations?
- false
+ def supports_migrations? # :nodoc:
+ true
end
+ deprecate :supports_migrations?
def supports_primary_key? # :nodoc:
true
@@ -438,6 +439,9 @@ module ActiveRecord
# This is done under the hood by calling #active?. If the connection
# is no longer active, then this method will reconnect to the database.
def verify!(*ignored)
+ if ignored.size > 0
+ ActiveSupport::Deprecation.warn("Passing arguments to #verify method of the connection has no effect and has been deprecated. Please remove all arguments from the #verify method call.")
+ end
reconnect! unless active?
end
@@ -605,7 +609,11 @@ module ActiveRecord
binds: binds,
type_casted_binds: type_casted_binds,
statement_name: statement_name,
- connection_id: object_id) { yield }
+ connection_id: object_id) do
+ @lock.synchronize do
+ yield
+ end
+ end
rescue => e
raise translate_exception_class(e, sql)
end
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 286c98228c..55ec112c17 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -48,6 +48,7 @@ module ActiveRecord
float: { name: "float" },
decimal: { name: "decimal" },
datetime: { name: "datetime" },
+ timestamp: { name: "timestamp" },
time: { name: "time" },
date: { name: "date" },
binary: { name: "blob", limit: 65535 },
@@ -90,11 +91,6 @@ module ActiveRecord
/mariadb/i.match?(full_version)
end
- # Returns true, since this connection adapter supports migrations.
- def supports_migrations?
- true
- end
-
def supports_bulk_alter? #:nodoc:
true
end
@@ -598,10 +594,6 @@ module ActiveRecord
self.class.type_cast_config_to_boolean(@config.fetch(:strict, true))
end
- def valid_type?(type)
- !native_database_types[type].nil?
- end
-
def default_index_type?(index) # :nodoc:
index.using == :btree || super
end
@@ -659,7 +651,7 @@ module ActiveRecord
end
def extract_precision(sql_type)
- if /time/.match?(sql_type)
+ if /\A(?:date)?time(?:stamp)?\b/.match?(sql_type)
super || 0
else
super
@@ -736,11 +728,11 @@ module ActiveRecord
def change_column_sql(table_name, column_name, type, options = {})
column = column_for(table_name, column_name)
- unless options_include_default?(options)
+ unless options.key?(:default)
options[:default] = column.default
end
- unless options.has_key?(:null)
+ unless options.key?(:null)
options[:null] = column.null
end
@@ -820,9 +812,9 @@ module ActiveRecord
variables["sql_auto_is_null"] = 0
# Increase timeout so the server doesn't disconnect us.
- wait_timeout = @config[:wait_timeout]
+ wait_timeout = self.class.type_cast_config_to_integer(@config[:wait_timeout])
wait_timeout = 2147483 unless wait_timeout.is_a?(Integer)
- variables["wait_timeout"] = self.class.type_cast_config_to_integer(wait_timeout)
+ variables["wait_timeout"] = wait_timeout
defaults = [":default", :default].to_set
diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb
index dcf56997db..3e4ea28f63 100644
--- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb
+++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb
@@ -149,9 +149,18 @@ module ActiveRecord
# Expands each key in @configurations hash into fully resolved hash
def resolve_all
config = configurations.dup
+
+ if env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
+ env_config = config[env] if config[env].is_a?(Hash) && !(config[env].key?("adapter") || config[env].key?("url"))
+ end
+
+ config.reject! { |k, v| v.is_a?(Hash) && !(v.key?("adapter") || v.key?("url")) }
+ config.merge! env_config if env_config
+
config.each do |key, value|
config[key] = resolve(value) if value
end
+
config
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 e8358271ab..083cd6340f 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/schema_creation.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/schema_creation.rb
@@ -25,6 +25,14 @@ module ActiveRecord
end
def add_column_options!(sql, options)
+ # By default, TIMESTAMP columns are NOT NULL, cannot contain NULL values,
+ # and assigning NULL assigns the current timestamp. To permit a TIMESTAMP
+ # column to contain NULL, explicitly declare it with the NULL attribute.
+ # See http://dev.mysql.com/doc/refman/5.7/en/timestamp-initialization.html
+ if /\Atimestamp\b/.match?(options[:column].sql_type) && !options[:primary_key]
+ sql << " NULL" unless options[:null] == false || options_include_default?(options)
+ end
+
if charset = options[:charset]
sql << " CHARACTER SET #{charset}"
end
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/mysql/schema_definitions.rb
index 773bbcef4e..6d88c14d50 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/schema_definitions.rb
@@ -75,6 +75,11 @@ module ActiveRecord
super
end
+
+ private
+ def aliased_types(name, fallback)
+ fallback
+ end
end
class Table < ActiveRecord::ConnectionAdapters::Table
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb
index ad4a069d73..3e0afd9761 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb
@@ -30,7 +30,10 @@ module ActiveRecord
end
def schema_type(column)
- if column.sql_type == "tinyblob"
+ case column.sql_type
+ when /\Atimestamp\b/
+ :timestamp
+ when "tinyblob"
:blob
else
super
@@ -38,7 +41,7 @@ module ActiveRecord
end
def schema_precision(column)
- super unless /time/.match?(column.sql_type) && column.precision == 0
+ super unless /\A(?:date)?time(?:stamp)?\b/.match?(column.sql_type) && column.precision == 0
end
def schema_collation(column)
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb b/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb
index 24dcf852e1..9ad6a6c0d0 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb
@@ -2,6 +2,8 @@ module ActiveRecord
module ConnectionAdapters
module MySQL
class TypeMetadata < DelegateClass(SqlTypeMetadata) # :nodoc:
+ undef to_yaml if method_defined?(:to_yaml)
+
attr_reader :extra
def initialize(type_metadata, extra: "")
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 e1a75f8e5e..a73a8c1726 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
@@ -23,7 +23,7 @@ module ActiveRecord
when ::String
type_cast_array(@pg_decoder.decode(value), :deserialize)
when Data
- deserialize(value.values)
+ type_cast_array(value.values, :deserialize)
else
super
end
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 f7f3a1521b..a332375b78 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -419,7 +419,7 @@ module ActiveRecord
end
execute sql
- change_column_default(table_name, column_name, options[:default]) if options_include_default?(options)
+ change_column_default(table_name, column_name, options[:default]) if options.key?(:default)
change_column_null(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
end
@@ -546,10 +546,6 @@ module ActiveRecord
end
end
- def index_name_length
- 63
- end
-
# Maps logical Rails types to PostgreSQL-specific data types.
def type_to_sql(type, limit: nil, precision: nil, scale: nil, array: nil, **) # :nodoc:
sql = \
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb b/activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb
index 311988625f..f57179ae59 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb
@@ -1,6 +1,8 @@
module ActiveRecord
module ConnectionAdapters
class PostgreSQLTypeMetadata < DelegateClass(SqlTypeMetadata)
+ undef to_yaml if method_defined?(:to_yaml)
+
attr_reader :oid, :fmod, :array
def initialize(type_metadata, oid: nil, fmod: nil)
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index b6f595c86c..22c37abb78 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -215,7 +215,7 @@ module ActiveRecord
# @local_tz is initialized as nil to avoid warnings when connect tries to use it
@local_tz = nil
- @table_alias_length = nil
+ @max_identifier_length = nil
connect
add_pg_encoders
@@ -236,7 +236,9 @@ module ActiveRecord
# Clears the prepared statements cache.
def clear_cache!
- @statements.clear
+ @lock.synchronize do
+ @statements.clear
+ end
end
def truncate(table_name, name = nil)
@@ -279,11 +281,6 @@ module ActiveRecord
NATIVE_DATABASE_TYPES
end
- # Returns true, since this connection adapter supports migrations.
- def supports_migrations?
- true
- end
-
def set_standard_conforming_strings
execute("SET standard_conforming_strings = on", "SCHEMA")
end
@@ -361,8 +358,9 @@ module ActiveRecord
# Returns the configured supported identifier length supported by PostgreSQL
def table_alias_length
- @table_alias_length ||= query("SHOW max_identifier_length", "SCHEMA")[0][0].to_i
+ @max_identifier_length ||= select_value("SHOW max_identifier_length", "SCHEMA").to_i
end
+ alias index_name_length table_alias_length
# Set the authorized user for this session
def session_auth=(user)
@@ -374,10 +372,6 @@ module ActiveRecord
@use_insert_returning
end
- def valid_type?(type)
- !native_database_types[type].nil?
- end
-
def update_table_definition(table_name, base) #:nodoc:
PostgreSQL::Table.new(table_name, base)
end
@@ -637,8 +631,10 @@ module ActiveRecord
if in_transaction?
raise ActiveRecord::PreparedStatementCacheExpired.new(e.cause.message)
else
- # outside of transactions we can simply flush this query and retry
- @statements.delete sql_key(sql)
+ @lock.synchronize do
+ # outside of transactions we can simply flush this query and retry
+ @statements.delete sql_key(sql)
+ end
retry
end
end
@@ -674,19 +670,21 @@ module ActiveRecord
# Prepare the statement if it hasn't been prepared, return
# the statement key.
def prepare_statement(sql)
- sql_key = sql_key(sql)
- unless @statements.key? sql_key
- nextkey = @statements.next_key
- begin
- @connection.prepare nextkey, sql
- rescue => e
- raise translate_exception_class(e, sql)
+ @lock.synchronize do
+ sql_key = sql_key(sql)
+ unless @statements.key? sql_key
+ nextkey = @statements.next_key
+ begin
+ @connection.prepare nextkey, sql
+ rescue => e
+ raise translate_exception_class(e, sql)
+ end
+ # Clear the queue
+ @connection.get_last_result
+ @statements[sql_key] = nextkey
end
- # Clear the queue
- @connection.get_last_result
- @statements[sql_key] = nextkey
+ @statements[sql_key]
end
- @statements[sql_key]
end
# Connects to a PostgreSQL server and sets up the adapter depending on the
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index 1226383cad..d24bfc0c93 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -119,11 +119,6 @@ module ActiveRecord
true
end
- # Returns true, since this connection adapter supports migrations.
- def supports_migrations? #:nodoc:
- true
- end
-
def requires_reloading?
true
end
@@ -165,10 +160,6 @@ module ActiveRecord
true
end
- def valid_type?(type)
- true
- end
-
# Returns 62. SQLite supports index names up to 64
# characters. The rest is used by Rails internally to perform
# temporary rename operations
@@ -383,11 +374,10 @@ module ActiveRecord
def change_column(table_name, column_name, type, options = {}) #:nodoc:
alter_table(table_name) do |definition|
- include_default = options_include_default?(options)
definition[column_name].instance_eval do
self.type = type
self.limit = options[:limit] if options.include?(:limit)
- self.default = options[:default] if include_default
+ self.default = options[:default] if options.include?(:default)
self.null = options[:null] if options.include?(:null)
self.precision = options[:precision] if options.include?(:precision)
self.scale = options[:scale] if options.include?(:scale)
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 91d8054ef2..e79167d568 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -970,6 +970,7 @@ module ActiveRecord
@fixture_connections = enlist_fixture_connections
@fixture_connections.each do |connection|
connection.begin_transaction joinable: false
+ connection.pool.lock_thread = true
end
# When connections are established in the future, begin a transaction too
@@ -985,6 +986,7 @@ module ActiveRecord
if connection && !@fixture_connections.include?(connection)
connection.begin_transaction joinable: false
+ connection.pool.lock_thread = true
@fixture_connections << connection
end
end
@@ -1007,6 +1009,7 @@ module ActiveRecord
ActiveSupport::Notifications.unsubscribe(@connection_subscriber) if @connection_subscriber
@fixture_connections.each do |connection|
connection.rollback_transaction if connection.transaction_open?
+ connection.pool.lock_thread = false
end
@fixture_connections.clear
else
diff --git a/activerecord/lib/active_record/gem_version.rb b/activerecord/lib/active_record/gem_version.rb
index f33456a744..174f716152 100644
--- a/activerecord/lib/active_record/gem_version.rb
+++ b/activerecord/lib/active_record/gem_version.rb
@@ -8,7 +8,7 @@ module ActiveRecord
MAJOR = 5
MINOR = 1
TINY = 0
- PRE = "alpha"
+ PRE = "beta1"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb
index 40f6226315..4e1df1432c 100644
--- a/activerecord/lib/active_record/migration.rb
+++ b/activerecord/lib/active_record/migration.rb
@@ -548,12 +548,10 @@ module ActiveRecord
end
def call(env)
- if connection.supports_migrations?
- mtime = ActiveRecord::Migrator.last_migration.mtime.to_i
- if @last_check < mtime
- ActiveRecord::Migration.check_pending!(connection)
- @last_check = mtime
- end
+ mtime = ActiveRecord::Migrator.last_migration.mtime.to_i
+ if @last_check < mtime
+ ActiveRecord::Migration.check_pending!(connection)
+ @last_check = mtime
end
@app.call(env)
end
@@ -1027,10 +1025,11 @@ module ActiveRecord
def schema_migrations_table_name
SchemaMigration.table_name
end
+ deprecate :schema_migrations_table_name
def get_all_versions(connection = Base.connection)
- if connection.table_exists?(schema_migrations_table_name)
- SchemaMigration.all.map { |x| x.version.to_i }.sort
+ if SchemaMigration.table_exists?
+ SchemaMigration.all_versions.map(&:to_i)
else
[]
end
@@ -1058,10 +1057,6 @@ module ActiveRecord
Array(@migrations_paths)
end
- def match_to_migration_filename?(filename) # :nodoc:
- Migration::MigrationFilenameRegexp.match?(File.basename(filename))
- end
-
def parse_migration_filename(filename) # :nodoc:
File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
end
@@ -1069,9 +1064,7 @@ module ActiveRecord
def migrations(paths)
paths = Array(paths)
- files = Dir[*paths.map { |p| "#{p}/**/[0-9]*_*.rb" }]
-
- migrations = files.map do |file|
+ migrations = migration_files(paths).map do |file|
version, name, scope = parse_migration_filename(file)
raise IllegalMigrationNameError.new(file) unless version
version = version.to_i
@@ -1083,6 +1076,30 @@ module ActiveRecord
migrations.sort_by(&:version)
end
+ def migrations_status(paths)
+ paths = Array(paths)
+
+ db_list = ActiveRecord::SchemaMigration.normalized_versions
+
+ file_list = migration_files(paths).map do |file|
+ version, name, scope = parse_migration_filename(file)
+ raise IllegalMigrationNameError.new(file) unless version
+ version = ActiveRecord::SchemaMigration.normalize_migration_number(version)
+ status = db_list.delete(version) ? "up" : "down"
+ [status, version, (name + scope).humanize]
+ end.compact
+
+ db_list.map! do |version|
+ ["up", version, "********** NO FILE **********"]
+ end
+
+ (db_list + file_list).sort_by { |_, version, _| version }
+ end
+
+ def migration_files(paths)
+ Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
+ end
+
private
def move(direction, migrations_paths, steps)
@@ -1098,8 +1115,6 @@ module ActiveRecord
end
def initialize(direction, migrations, target_version = nil)
- raise StandardError.new("This database does not yet support migrations") unless Base.connection.supports_migrations?
-
@direction = direction
@target_version = target_version
@migrated_versions = nil
diff --git a/activerecord/lib/active_record/null_relation.rb b/activerecord/lib/active_record/null_relation.rb
index 2bb7ed6d5e..26966f9433 100644
--- a/activerecord/lib/active_record/null_relation.rb
+++ b/activerecord/lib/active_record/null_relation.rb
@@ -4,7 +4,7 @@ module ActiveRecord
[]
end
- def delete_all(_conditions = nil)
+ def delete_all
0
end
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index 246d330b76..1c7206aca4 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -110,28 +110,13 @@ db_namespace = namespace :db do
unless ActiveRecord::SchemaMigration.table_exists?
abort "Schema migrations table does not exist yet."
end
- db_list = ActiveRecord::SchemaMigration.normalized_versions
-
- file_list =
- ActiveRecord::Tasks::DatabaseTasks.migrations_paths.flat_map do |path|
- Dir.foreach(path).map do |file|
- next unless ActiveRecord::Migrator.match_to_migration_filename?(file)
-
- version, name, scope = ActiveRecord::Migrator.parse_migration_filename(file)
- version = ActiveRecord::SchemaMigration.normalize_migration_number(version)
- status = db_list.delete(version) ? "up" : "down"
- [status, version, (name + scope).humanize]
- end.compact
- end
- db_list.map! do |version|
- ["up", version, "********** NO FILE **********"]
- end
# output
puts "\ndatabase: #{ActiveRecord::Base.connection_config[:database]}\n\n"
puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
puts "-" * 50
- (db_list + file_list).sort_by { |_, version, _| version }.each do |status, version, name|
+ paths = ActiveRecord::Tasks::DatabaseTasks.migrations_paths
+ ActiveRecord::Migrator.migrations_status(paths).each do |status, version, name|
puts "#{status.center(8)} #{version.ljust(14)} #{name}"
end
puts
@@ -288,8 +273,7 @@ db_namespace = namespace :db do
current_config = ActiveRecord::Tasks::DatabaseTasks.current_config
ActiveRecord::Tasks::DatabaseTasks.structure_dump(current_config, filename)
- if ActiveRecord::Base.connection.supports_migrations? &&
- ActiveRecord::SchemaMigration.table_exists?
+ if ActiveRecord::SchemaMigration.table_exists?
File.open(filename, "a") do |f|
f.puts ActiveRecord::Base.connection.dump_schema_information
f.print "\n"
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 61a2279292..24ca8b0be4 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -172,8 +172,8 @@ module ActiveRecord
JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
- def join_keys(association_klass)
- JoinKeys.new(foreign_key, active_record_primary_key)
+ def join_keys
+ get_join_keys klass
end
# Returns a list of scopes that should be applied for this Reflection
@@ -187,6 +187,30 @@ module ActiveRecord
end
deprecate :scope_chain
+ def join_scopes(table, predicate_builder) # :nodoc:
+ if scope
+ [ActiveRecord::Relation.create(klass, table, predicate_builder)
+ .instance_exec(&scope)]
+ else
+ []
+ end
+ end
+
+ def klass_join_scope(table, predicate_builder) # :nodoc:
+ if klass.current_scope
+ klass.current_scope.clone.tap { |scope|
+ scope.joins_values = []
+ }
+ else
+ relation = ActiveRecord::Relation.create(
+ klass,
+ table,
+ predicate_builder,
+ )
+ klass.send(:build_default_scope, relation)
+ end
+ end
+
def constraints
chain.map(&:scopes).flatten
end
@@ -260,6 +284,20 @@ module ActiveRecord
def chain
collect_join_chain
end
+
+ def get_join_keys(association_klass)
+ JoinKeys.new(join_pk(association_klass), join_fk)
+ end
+
+ private
+
+ def join_pk(_)
+ foreign_key
+ end
+
+ def join_fk
+ active_record_primary_key
+ end
end
# Base class for AggregateReflection and AssociationReflection. Objects of
@@ -687,11 +725,6 @@ module ActiveRecord
end
end
- def join_keys(association_klass)
- key = polymorphic? ? association_primary_key(association_klass) : association_primary_key
- JoinKeys.new(key, foreign_key)
- end
-
def join_id_for(owner) # :nodoc:
owner[foreign_key]
end
@@ -701,6 +734,14 @@ module ActiveRecord
def calculate_constructable(macro, options)
!polymorphic?
end
+
+ def join_fk
+ foreign_key
+ end
+
+ def join_pk(klass)
+ polymorphic? ? association_primary_key(klass) : association_primary_key
+ end
end
class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
@@ -720,7 +761,7 @@ module ActiveRecord
class ThroughReflection < AbstractReflection #:nodoc:
attr_reader :delegate_reflection
delegate :foreign_key, :foreign_type, :association_foreign_key,
- :active_record_primary_key, :type, to: :source_reflection
+ :active_record_primary_key, :type, :get_join_keys, to: :source_reflection
def initialize(delegate_reflection)
@delegate_reflection = delegate_reflection
@@ -806,6 +847,10 @@ module ActiveRecord
source_reflection.scopes + super
end
+ def join_scopes(table, predicate_builder) # :nodoc:
+ source_reflection.join_scopes(table, predicate_builder) + super
+ end
+
def source_type_scope
through_reflection.klass.where(foreign_type => options[:source_type])
end
@@ -816,10 +861,6 @@ module ActiveRecord
through_reflection.has_scope?
end
- def join_keys(association_klass)
- source_reflection.join_keys(association_klass)
- end
-
# A through association is nested if there would be more than one join table
def nested?
source_reflection.through_reflection? || through_reflection.through_reflection?
@@ -954,6 +995,7 @@ module ActiveRecord
end
private
+
def actual_source_reflection # FIXME: this is a horrible name
source_reflection.send(:actual_source_reflection)
end
@@ -990,6 +1032,15 @@ module ActiveRecord
end
end
+ def join_scopes(table, predicate_builder) # :nodoc:
+ scopes = @previous_reflection.join_scopes(table, predicate_builder) + super
+ if @previous_reflection.options[:source_type]
+ scopes + [@previous_reflection.source_type_scope]
+ else
+ scopes
+ end
+ end
+
def klass
@reflection.klass
end
@@ -1006,10 +1057,6 @@ module ActiveRecord
@reflection.plural_name
end
- def join_keys(association_klass)
- @reflection.join_keys(association_klass)
- end
-
def type
@reflection.type
end
@@ -1023,6 +1070,10 @@ module ActiveRecord
source_type = @previous_reflection.options[:source_type]
lambda { |object| where(type => source_type) }
end
+
+ def get_join_keys(association_klass)
+ @reflection.get_join_keys(association_klass)
+ end
end
class RuntimeReflection < PolymorphicReflection # :nodoc:
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 61ee09bcc8..2d6b21bec5 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -261,10 +261,6 @@ module ActiveRecord
coder.represent_seq(nil, records)
end
- def as_json(options = nil) #:nodoc:
- records.as_json(options)
- end
-
# Returns size of the records.
def size
loaded? ? @records.length : count(:all)
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index 35c670f1a1..9cabd1af13 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -37,11 +37,8 @@ module ActiveRecord
# Note: not all valid {Relation#select}[rdoc-ref:QueryMethods#select] expressions are valid #count expressions. The specifics differ
# between databases. In invalid cases, an error from the database is thrown.
def count(column_name = nil)
- if block_given?
- to_a.count { |*block_args| yield(*block_args) }
- else
- calculate(:count, column_name)
- end
+ return super() if block_given?
+ calculate(:count, column_name)
end
# Calculates the average value on a given column. Returns +nil+ if there's
@@ -75,8 +72,8 @@ module ActiveRecord
# #calculate for examples with options.
#
# Person.sum(:age) # => 4562
- def sum(column_name = nil, &block)
- return super(&block) if block_given?
+ def sum(column_name = nil)
+ return super() if block_given?
calculate(:sum, column_name)
end
@@ -232,7 +229,7 @@ module ActiveRecord
query_builder = build_count_subquery(spawn, column_name, distinct)
else
# PostgreSQL doesn't like ORDER BY when there are no GROUP BY
- relation = unscope(:order)
+ relation = unscope(:order).distinct!(false)
column = aggregate_column(column_name)
@@ -282,7 +279,7 @@ module ActiveRecord
operation,
distinct).as(aggregate_alias)
]
- select_values += select_values unless having_clause.empty?
+ select_values += self.select_values unless having_clause.empty?
select_values.concat group_columns.map { |aliaz, field|
if field.respond_to?(:as)
@@ -292,7 +289,7 @@ module ActiveRecord
end
}
- relation = except(:group)
+ relation = except(:group).distinct!(false)
relation.group_values = group_fields
relation.select_values = select_values
diff --git a/activerecord/lib/active_record/relation/delegation.rb b/activerecord/lib/active_record/relation/delegation.rb
index d3ba724507..0612151584 100644
--- a/activerecord/lib/active_record/relation/delegation.rb
+++ b/activerecord/lib/active_record/relation/delegation.rb
@@ -38,7 +38,7 @@ module ActiveRecord
delegate :to_xml, :encode_with, :length, :collect, :map, :each, :all?, :include?, :to_ary, :join,
:[], :&, :|, :+, :-, :sample, :reverse, :compact, :in_groups, :in_groups_of,
- :to_sentence, :to_formatted_s,
+ :to_sentence, :to_formatted_s, :as_json,
:shuffle, :split, :index, to: :records
delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key,
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 4548944fe6..5d24f5f5ca 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -147,7 +147,7 @@ module ActiveRecord
def last(limit = nil)
return find_last(limit) if loaded? || limit_value
- result = limit(limit || 1)
+ result = limit(limit)
result.order!(arel_attribute(primary_key)) if order_values.empty? && primary_key
result = result.reverse_order!
@@ -430,140 +430,142 @@ module ActiveRecord
reflections.none?(&:collection?)
end
- private
+ def find_with_ids(*ids)
+ raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
- def find_with_ids(*ids)
- raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
+ expects_array = ids.first.kind_of?(Array)
+ return ids.first if expects_array && ids.first.empty?
- expects_array = ids.first.kind_of?(Array)
- return ids.first if expects_array && ids.first.empty?
+ ids = ids.flatten.compact.uniq
- ids = ids.flatten.compact.uniq
-
- case ids.size
- when 0
- raise RecordNotFound, "Couldn't find #{@klass.name} without an ID"
- when 1
- result = find_one(ids.first)
- expects_array ? [ result ] : result
- else
- find_some(ids)
- end
- rescue ::RangeError
- raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range ID"
+ case ids.size
+ when 0
+ raise RecordNotFound, "Couldn't find #{@klass.name} without an ID"
+ when 1
+ result = find_one(ids.first)
+ expects_array ? [ result ] : result
+ else
+ find_some(ids)
end
+ rescue ::RangeError
+ raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range ID"
+ end
- def find_one(id)
- if ActiveRecord::Base === id
- raise ArgumentError, <<-MSG.squish
- You are passing an instance of ActiveRecord::Base to `find`.
- Please pass the id of the object by calling `.id`.
- MSG
- end
-
- relation = where(primary_key => id)
- record = relation.take
-
- raise_record_not_found_exception!(id, 0, 1) unless record
-
- record
+ def find_one(id)
+ if ActiveRecord::Base === id
+ raise ArgumentError, <<-MSG.squish
+ You are passing an instance of ActiveRecord::Base to `find`.
+ Please pass the id of the object by calling `.id`.
+ MSG
end
- def find_some(ids)
- return find_some_ordered(ids) unless order_values.present?
+ relation = where(primary_key => id)
+ record = relation.take
- result = where(primary_key => ids).to_a
+ raise_record_not_found_exception!(id, 0, 1) unless record
- expected_size =
- if limit_value && ids.size > limit_value
- limit_value
- else
- ids.size
- end
+ record
+ end
- # 11 ids with limit 3, offset 9 should give 2 results.
- if offset_value && (ids.size - offset_value < expected_size)
- expected_size = ids.size - offset_value
- end
+ def find_some(ids)
+ return find_some_ordered(ids) unless order_values.present?
- if result.size == expected_size
- result
+ result = where(primary_key => ids).to_a
+
+ expected_size =
+ if limit_value && ids.size > limit_value
+ limit_value
else
- raise_record_not_found_exception!(ids, result.size, expected_size)
+ ids.size
end
+
+ # 11 ids with limit 3, offset 9 should give 2 results.
+ if offset_value && (ids.size - offset_value < expected_size)
+ expected_size = ids.size - offset_value
end
- def find_some_ordered(ids)
- ids = ids.slice(offset_value || 0, limit_value || ids.size) || []
+ if result.size == expected_size
+ result
+ else
+ raise_record_not_found_exception!(ids, result.size, expected_size)
+ end
+ end
- result = except(:limit, :offset).where(primary_key => ids).records
+ def find_some_ordered(ids)
+ ids = ids.slice(offset_value || 0, limit_value || ids.size) || []
- if result.size == ids.size
- pk_type = @klass.type_for_attribute(primary_key)
+ result = except(:limit, :offset).where(primary_key => ids).records
- records_by_id = result.index_by(&:id)
- ids.map { |id| records_by_id.fetch(pk_type.cast(id)) }
- else
- raise_record_not_found_exception!(ids, result.size, ids.size)
- end
- end
+ if result.size == ids.size
+ pk_type = @klass.type_for_attribute(primary_key)
- def find_take
- if loaded?
- records.first
- else
- @take ||= limit(1).records.first
- end
+ records_by_id = result.index_by(&:id)
+ ids.map { |id| records_by_id.fetch(pk_type.cast(id)) }
+ else
+ raise_record_not_found_exception!(ids, result.size, ids.size)
end
+ end
- def find_take_with_limit(limit)
- if loaded?
- records.take(limit)
- else
- limit(limit).to_a
- end
+ def find_take
+ if loaded?
+ records.first
+ else
+ @take ||= limit(1).records.first
end
+ end
- def find_nth(index)
- @offsets[offset_index + index] ||= find_nth_with_limit(index, 1).first
+ def find_take_with_limit(limit)
+ if loaded?
+ records.take(limit)
+ else
+ limit(limit).to_a
end
+ end
+
+ def find_nth(index)
+ @offsets[offset_index + index] ||= find_nth_with_limit(index, 1).first
+ end
- def find_nth_with_limit(index, limit)
- if loaded?
- records[index, limit] || []
+ def find_nth_with_limit(index, limit)
+ if loaded?
+ records[index, limit] || []
+ else
+ relation = if order_values.empty? && primary_key
+ order(arel_attribute(primary_key).asc)
else
- relation = if order_values.empty? && primary_key
- order(arel_attribute(primary_key).asc)
- else
- self
- end
+ self
+ end
+ if limit_value.nil? || index < limit_value
relation = relation.offset(offset_index + index) unless index.zero?
relation.limit(limit).to_a
+ else
+ []
end
end
+ end
- def find_nth_from_last(index)
- if loaded?
- records[-index]
+ def find_nth_from_last(index)
+ if loaded?
+ records[-index]
+ else
+ relation = if order_values.empty? && primary_key
+ order(arel_attribute(primary_key).asc)
else
- relation = if order_values.empty? && primary_key
- order(arel_attribute(primary_key).asc)
- else
- self
- end
-
- relation.to_a[-index]
- # TODO: can be made more performant on large result sets by
- # for instance, last(index)[-index] (which would require
- # refactoring the last(n) finder method to make test suite pass),
- # or by using a combination of reverse_order, limit, and offset,
- # e.g., reverse_order.offset(index-1).first
+ self
end
- end
- def find_last(limit)
- limit ? records.last(limit) : records.last
+ relation.to_a[-index]
+ # TODO: can be made more performant on large result sets by
+ # for instance, last(index)[-index] (which would require
+ # refactoring the last(n) finder method to make test suite pass),
+ # or by using a combination of reverse_order, limit, and offset,
+ # e.g., reverse_order.offset(index-1).first
end
+ end
+
+ def find_last(limit)
+ limit ? records.last(limit) : records.last
+ end
end
end
diff --git a/activerecord/lib/active_record/result.rb b/activerecord/lib/active_record/result.rb
index 9ed70a9c2b..26b1d48e9e 100644
--- a/activerecord/lib/active_record/result.rb
+++ b/activerecord/lib/active_record/result.rb
@@ -41,10 +41,15 @@ module ActiveRecord
@column_types = column_types
end
+ # Returns the number of elements in the rows array.
def length
@rows.length
end
+ # Calls the given block once for each element in row collection, passing
+ # row as parameter.
+ #
+ # Returns an +Enumerator+ if no block is given.
def each
if block_given?
hash_rows.each { |row| yield row }
@@ -53,6 +58,7 @@ module ActiveRecord
end
end
+ # Returns an array of hashes representing each row record.
def to_hash
hash_rows
end
@@ -60,11 +66,12 @@ module ActiveRecord
alias :map! :map
alias :collect! :map
- # Returns true if there are no records.
+ # Returns true if there are no records, otherwise false.
def empty?
rows.empty?
end
+ # Returns an array of hashes representing each row record.
def to_ary
hash_rows
end
@@ -73,11 +80,15 @@ module ActiveRecord
hash_rows[idx]
end
+ # Returns the first record from the rows collection.
+ # If the rows collection is empty, returns +nil+.
def first
return nil if @rows.empty?
Hash[@columns.zip(@rows.first)]
end
+ # Returns the last record from the rows collection.
+ # If the rows collection is empty, returns +nil+.
def last
return nil if @rows.empty?
Hash[@columns.zip(@rows.last)]
diff --git a/activerecord/lib/active_record/sanitization.rb b/activerecord/lib/active_record/sanitization.rb
index 427c0019c6..64bda1539c 100644
--- a/activerecord/lib/active_record/sanitization.rb
+++ b/activerecord/lib/active_record/sanitization.rb
@@ -1,4 +1,3 @@
-
module ActiveRecord
module Sanitization
extend ActiveSupport::Concern
@@ -207,9 +206,9 @@ module ActiveRecord
end
end
- # TODO: Deprecate this
def quoted_id # :nodoc:
self.class.connection.quote(@attributes[self.class.primary_key].value_for_database)
end
+ deprecate :quoted_id
end
end
diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb
index 15533f0151..2bbfd01698 100644
--- a/activerecord/lib/active_record/schema_dumper.rb
+++ b/activerecord/lib/active_record/schema_dumper.rb
@@ -85,7 +85,7 @@ HEADER
end
def tables(stream)
- sorted_tables = @connection.data_sources.sort - @connection.views
+ sorted_tables = @connection.tables.sort
sorted_tables.each do |table_name|
table(table_name, stream) unless ignored?(table_name)
diff --git a/activerecord/lib/active_record/schema_migration.rb b/activerecord/lib/active_record/schema_migration.rb
index 5efbcff96a..f59737afb0 100644
--- a/activerecord/lib/active_record/schema_migration.rb
+++ b/activerecord/lib/active_record/schema_migration.rb
@@ -39,7 +39,11 @@ module ActiveRecord
end
def normalized_versions
- pluck(:version).map { |v| normalize_migration_number v }
+ all_versions.map { |v| normalize_migration_number v }
+ end
+
+ def all_versions
+ order(:version).pluck(:version)
end
end
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb
index 08417aaa0f..690deee508 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -283,7 +283,7 @@ module ActiveRecord
fire_on = Array(options[:on])
assert_valid_transaction_action(fire_on)
options[:if] = Array(options[:if])
- options[:if] << "transaction_include_any_action?(#{fire_on})"
+ options[:if].unshift("transaction_include_any_action?(#{fire_on})")
end
end
diff --git a/activerecord/lib/active_record/type/decimal_without_scale.rb b/activerecord/lib/active_record/type/decimal_without_scale.rb
index 7ce33e9cd3..53a5e205da 100644
--- a/activerecord/lib/active_record/type/decimal_without_scale.rb
+++ b/activerecord/lib/active_record/type/decimal_without_scale.rb
@@ -4,6 +4,10 @@ module ActiveRecord
def type
:decimal
end
+
+ def type_cast_for_schema(value)
+ value.to_s.inspect
+ end
end
end
end
diff --git a/activerecord/lib/active_record/type/serialized.rb b/activerecord/lib/active_record/type/serialized.rb
index 6af05c1860..edbd20a6c1 100644
--- a/activerecord/lib/active_record/type/serialized.rb
+++ b/activerecord/lib/active_record/type/serialized.rb
@@ -1,6 +1,8 @@
module ActiveRecord
module Type
class Serialized < DelegateClass(ActiveModel::Type::Value) # :nodoc:
+ undef to_yaml if method_defined?(:to_yaml)
+
include ActiveModel::Type::Helpers::Mutable
attr_reader :subtype, :coder
diff --git a/activerecord/lib/rails/generators/active_record/migration.rb b/activerecord/lib/rails/generators/active_record/migration.rb
index 43075077b9..47c0981a49 100644
--- a/activerecord/lib/rails/generators/active_record/migration.rb
+++ b/activerecord/lib/rails/generators/active_record/migration.rb
@@ -22,7 +22,7 @@ module ActiveRecord
end
def db_migrate_path
- if defined?(Rails) && Rails.application
+ if defined?(Rails.application) && Rails.application
Rails.application.config.paths["db/migrate"].to_ary.first
else
"db/migrate"
diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb
index 0c9d1dff9d..070fca240f 100644
--- a/activerecord/test/cases/adapter_test.rb
+++ b/activerecord/test/cases/adapter_test.rb
@@ -30,6 +30,16 @@ module ActiveRecord
assert_nothing_raised { Book.destroy(0) }
end
+ def test_valid_column
+ @connection.native_database_types.each_key do |type|
+ assert @connection.valid_type?(type)
+ end
+ end
+
+ def test_invalid_column
+ assert_not @connection.valid_type?(:foobar)
+ end
+
def test_tables
tables = @connection.tables
assert_includes tables, "accounts"
diff --git a/activerecord/test/cases/adapters/mysql2/connection_test.rb b/activerecord/test/cases/adapters/mysql2/connection_test.rb
index 1f94472390..a2faf43b0d 100644
--- a/activerecord/test/cases/adapters/mysql2/connection_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/connection_test.rb
@@ -42,7 +42,7 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase
@connection.update("set @@wait_timeout=1")
sleep 2
assert !@connection.active?
-
+ ensure
# Repair all fixture connections so other tests won't break.
@fixture_connections.each(&:verify!)
end
@@ -63,6 +63,18 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase
assert @connection.active?
end
+ def test_verify_with_args_is_deprecated
+ assert_deprecated do
+ @connection.verify!(option: true)
+ end
+ assert_deprecated do
+ @connection.verify!([])
+ end
+ assert_deprecated do
+ @connection.verify!({})
+ end
+ end
+
def test_execute_after_disconnect
@connection.disconnect!
@@ -85,6 +97,22 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase
assert_equal false, @connection.active?
end
+ def test_wait_timeout_as_string
+ run_without_connection do |orig_connection|
+ ActiveRecord::Base.establish_connection(orig_connection.merge(wait_timeout: "60"))
+ result = ActiveRecord::Base.connection.select_value("SELECT @@SESSION.wait_timeout")
+ assert_equal 60, result
+ end
+ end
+
+ def test_wait_timeout_as_url
+ run_without_connection do |orig_connection|
+ ActiveRecord::Base.establish_connection(orig_connection.merge("url" => "mysql2:///?wait_timeout=60"))
+ result = ActiveRecord::Base.connection.select_value("SELECT @@SESSION.wait_timeout")
+ assert_equal 60, result
+ end
+ end
+
def test_mysql_connection_collation_is_configured
assert_equal "utf8_unicode_ci", @connection.show_variable("collation_connection")
assert_equal "utf8_general_ci", ARUnit2Model.connection.show_variable("collation_connection")
diff --git a/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb b/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb
index aab3dcb724..565130c38f 100644
--- a/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb
@@ -17,17 +17,6 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase
end
end
- def test_valid_column
- with_example_table do
- column = @conn.columns("ex").find { |col| col.name == "id" }
- assert @conn.valid_type?(column.type)
- end
- end
-
- def test_invalid_column
- assert_not @conn.valid_type?(:foobar)
- end
-
def test_columns_for_distinct_zero_orders
assert_equal "posts.id",
@conn.columns_for_distinct("posts.id", [])
diff --git a/activerecord/test/cases/adapters/postgresql/connection_test.rb b/activerecord/test/cases/adapters/postgresql/connection_test.rb
index 3cbd4ca212..c52d9e37cc 100644
--- a/activerecord/test/cases/adapters/postgresql/connection_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/connection_test.rb
@@ -105,7 +105,7 @@ module ActiveRecord
end
def test_table_alias_length_logs_name
- @connection.instance_variable_set("@table_alias_length", nil)
+ @connection.instance_variable_set("@max_identifier_length", nil)
@connection.table_alias_length
assert_equal "SCHEMA", @subscriber.logged[0][1]
end
@@ -177,7 +177,7 @@ module ActiveRecord
assert_not_equal original_connection_pid, new_connection_pid,
"umm -- looks like you didn't break the connection, because we're still " \
"successfully querying with the same connection pid."
-
+ ensure
# Repair all fixture connections so other tests won't break.
@fixture_connections.each(&:verify!)
end
diff --git a/activerecord/test/cases/adapters/postgresql/json_test.rb b/activerecord/test/cases/adapters/postgresql/json_test.rb
index 93558ac4d2..d4e627001c 100644
--- a/activerecord/test/cases/adapters/postgresql/json_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/json_test.rb
@@ -16,6 +16,7 @@ module PostgresqlJSONSharedTestCases
@connection.create_table("json_data_type") do |t|
t.public_send column_type, "payload", default: {} # t.json 'payload', default: {}
t.public_send column_type, "settings" # t.json 'settings'
+ t.public_send column_type, "objects", array: true # t.json 'objects', array: true
end
rescue ActiveRecord::StatementInvalid
skip "do not test on PostgreSQL without #{column_type} type."
@@ -75,6 +76,15 @@ module PostgresqlJSONSharedTestCases
assert_equal({ "string" => "foo", "symbol" => "bar" }, x.reload.payload)
end
+ def test_deserialize_with_array
+ x = JsonDataType.new(objects: ["foo" => "bar"])
+ assert_equal ["foo" => "bar"], x.objects
+ x.save!
+ assert_equal ["foo" => "bar"], x.objects
+ x.reload
+ assert_equal ["foo" => "bar"], x.objects
+ end
+
def test_type_cast_json
type = JsonDataType.type_for_attribute("payload")
diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
index 3054f0271f..003e6e62e7 100644
--- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
@@ -21,17 +21,6 @@ module ActiveRecord
end
end
- def test_valid_column
- with_example_table do
- column = @connection.columns("ex").find { |col| col.name == "id" }
- assert @connection.valid_type?(column.type)
- end
- end
-
- def test_invalid_column
- assert_not @connection.valid_type?(:foobar)
- end
-
def test_primary_key
with_example_table do
assert_equal "id", @connection.primary_key("ex")
diff --git a/activerecord/test/cases/adapters/postgresql/quoting_test.rb b/activerecord/test/cases/adapters/postgresql/quoting_test.rb
index 141baffa5b..a1e966b915 100644
--- a/activerecord/test/cases/adapters/postgresql/quoting_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/quoting_test.rb
@@ -1,5 +1,4 @@
require "cases/helper"
-require "ipaddr"
module ActiveRecord
module ConnectionAdapters
diff --git a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
index 9750840051..aefbb309e6 100644
--- a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
@@ -1,6 +1,5 @@
require "cases/helper"
require "bigdecimal"
-require "yaml"
require "securerandom"
class SQLite3QuotingTest < ActiveRecord::SQLite3TestCase
@@ -15,31 +14,6 @@ class SQLite3QuotingTest < ActiveRecord::SQLite3TestCase
assert_equal expected, @conn.type_cast(binary)
end
- def test_type_cast_symbol
- assert_equal "foo", @conn.type_cast(:foo)
- end
-
- def test_type_cast_date
- date = Date.today
- expected = @conn.quoted_date(date)
- assert_equal expected, @conn.type_cast(date)
- end
-
- def test_type_cast_time
- time = Time.now
- expected = @conn.quoted_date(time)
- assert_equal expected, @conn.type_cast(time)
- end
-
- def test_type_cast_numeric
- assert_equal 10, @conn.type_cast(10)
- assert_equal 2.2, @conn.type_cast(2.2)
- end
-
- def test_type_cast_nil
- assert_nil @conn.type_cast(nil)
- end
-
def test_type_cast_true
assert_equal "t", @conn.type_cast(true)
end
@@ -53,31 +27,6 @@ class SQLite3QuotingTest < ActiveRecord::SQLite3TestCase
assert_equal bd.to_f, @conn.type_cast(bd)
end
- def test_type_cast_unknown_should_raise_error
- obj = Class.new.new
- assert_raise(TypeError) { @conn.type_cast(obj) }
- end
-
- def test_type_cast_object_which_responds_to_quoted_id
- quoted_id_obj = Class.new {
- def quoted_id
- "'zomg'"
- end
-
- def id
- 10
- end
- }.new
- assert_equal 10, @conn.type_cast(quoted_id_obj)
-
- quoted_id_obj = Class.new {
- def quoted_id
- "'zomg'"
- end
- }.new
- assert_raise(TypeError) { @conn.type_cast(quoted_id_obj) }
- end
-
def test_quoting_binary_strings
value = "hello".encode("ascii-8bit")
type = ActiveRecord::Type::String.new
diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
index fc5b95f26e..2179d1294c 100644
--- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
@@ -49,22 +49,6 @@ module ActiveRecord
end
end
- def test_valid_column
- with_example_table do
- column = @conn.columns("ex").find { |col| col.name == "id" }
- assert @conn.valid_type?(column.type)
- end
- end
-
- # sqlite3 databases should be able to support any type and not just the
- # ones mentioned in the native_database_types.
- #
- # Therefore test_invalid column should always return true even if the
- # type is not valid.
- def test_invalid_column
- assert @conn.valid_type?(:foobar)
- end
-
def test_column_types
owner = Owner.create!(name: "hello".encode("ascii-8bit"))
owner.reload
diff --git a/activerecord/test/cases/ar_schema_test.rb b/activerecord/test/cases/ar_schema_test.rb
index 397ac599b9..5b608d8e83 100644
--- a/activerecord/test/cases/ar_schema_test.rb
+++ b/activerecord/test/cases/ar_schema_test.rb
@@ -1,146 +1,143 @@
require "cases/helper"
-if ActiveRecord::Base.connection.supports_migrations?
+class ActiveRecordSchemaTest < ActiveRecord::TestCase
+ self.use_transactional_tests = false
+
+ setup do
+ @original_verbose = ActiveRecord::Migration.verbose
+ ActiveRecord::Migration.verbose = false
+ @connection = ActiveRecord::Base.connection
+ ActiveRecord::SchemaMigration.drop_table
+ end
- class ActiveRecordSchemaTest < ActiveRecord::TestCase
- self.use_transactional_tests = false
+ teardown do
+ @connection.drop_table :fruits rescue nil
+ @connection.drop_table :nep_fruits rescue nil
+ @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
+ ActiveRecord::Migration.verbose = @original_verbose
+ end
- setup do
- @original_verbose = ActiveRecord::Migration.verbose
- ActiveRecord::Migration.verbose = false
- @connection = ActiveRecord::Base.connection
- ActiveRecord::SchemaMigration.drop_table
- 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
- teardown do
- @connection.drop_table :fruits rescue nil
- @connection.drop_table :nep_fruits rescue nil
- @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
- ActiveRecord::Migration.verbose = @original_verbose
+ ActiveRecord::SchemaMigration.create_table
+ assert_difference "ActiveRecord::SchemaMigration.count", 1 do
+ ActiveRecord::SchemaMigration.create version: 12
end
+ ensure
+ ActiveRecord::SchemaMigration.drop_table
+ ActiveRecord::Base.primary_key_prefix_type = old_primary_key_prefix_type
+ 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
-
- ActiveRecord::SchemaMigration.create_table
- assert_difference "ActiveRecord::SchemaMigration.count", 1 do
- ActiveRecord::SchemaMigration.create version: 12
+ def test_schema_define
+ ActiveRecord::Schema.define(version: 7) do
+ create_table :fruits do |t|
+ t.column :color, :string
+ t.column :fruit_size, :string # NOTE: "size" is reserved in Oracle
+ t.column :texture, :string
+ t.column :flavor, :string
end
- ensure
- ActiveRecord::SchemaMigration.drop_table
- ActiveRecord::Base.primary_key_prefix_type = old_primary_key_prefix_type
end
- def test_schema_define
- ActiveRecord::Schema.define(version: 7) do
- create_table :fruits do |t|
- t.column :color, :string
- t.column :fruit_size, :string # NOTE: "size" is reserved in Oracle
- t.column :texture, :string
- t.column :flavor, :string
- end
- end
-
- assert_nothing_raised { @connection.select_all "SELECT * FROM fruits" }
- assert_nothing_raised { @connection.select_all "SELECT * FROM schema_migrations" }
- assert_equal 7, ActiveRecord::Migrator::current_version
- end
+ assert_nothing_raised { @connection.select_all "SELECT * FROM fruits" }
+ assert_nothing_raised { @connection.select_all "SELECT * FROM schema_migrations" }
+ assert_equal 7, ActiveRecord::Migrator::current_version
+ end
- def test_schema_define_w_table_name_prefix
- table_name = ActiveRecord::SchemaMigration.table_name
- old_table_name_prefix = ActiveRecord::Base.table_name_prefix
- ActiveRecord::Base.table_name_prefix = "nep_"
- ActiveRecord::SchemaMigration.table_name = "nep_#{table_name}"
- ActiveRecord::Schema.define(version: 7) do
- create_table :fruits do |t|
- t.column :color, :string
- t.column :fruit_size, :string # NOTE: "size" is reserved in Oracle
- t.column :texture, :string
- t.column :flavor, :string
- end
+ def test_schema_define_w_table_name_prefix
+ table_name = ActiveRecord::SchemaMigration.table_name
+ old_table_name_prefix = ActiveRecord::Base.table_name_prefix
+ ActiveRecord::Base.table_name_prefix = "nep_"
+ ActiveRecord::SchemaMigration.table_name = "nep_#{table_name}"
+ ActiveRecord::Schema.define(version: 7) do
+ create_table :fruits do |t|
+ t.column :color, :string
+ t.column :fruit_size, :string # NOTE: "size" is reserved in Oracle
+ t.column :texture, :string
+ t.column :flavor, :string
end
- assert_equal 7, ActiveRecord::Migrator::current_version
- ensure
- ActiveRecord::Base.table_name_prefix = old_table_name_prefix
- ActiveRecord::SchemaMigration.table_name = table_name
end
+ assert_equal 7, ActiveRecord::Migrator::current_version
+ ensure
+ ActiveRecord::Base.table_name_prefix = old_table_name_prefix
+ ActiveRecord::SchemaMigration.table_name = table_name
+ end
- def test_schema_raises_an_error_for_invalid_column_type
- assert_raise NoMethodError do
- ActiveRecord::Schema.define(version: 8) do
- create_table :vegetables do |t|
- t.unknown :color
- end
+ def test_schema_raises_an_error_for_invalid_column_type
+ assert_raise NoMethodError do
+ ActiveRecord::Schema.define(version: 8) do
+ create_table :vegetables do |t|
+ t.unknown :color
end
end
end
+ end
- def test_schema_subclass
- Class.new(ActiveRecord::Schema).define(version: 9) do
- create_table :fruits
- end
- assert_nothing_raised { @connection.select_all "SELECT * FROM fruits" }
+ def test_schema_subclass
+ Class.new(ActiveRecord::Schema).define(version: 9) do
+ create_table :fruits
end
+ assert_nothing_raised { @connection.select_all "SELECT * FROM fruits" }
+ 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")
- 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")
+ end
- def test_schema_load_with_multiple_indexes_for_column_of_different_names
- ActiveRecord::Schema.define do
- create_table :multiple_indexes do |t|
- t.string "foo"
- t.index ["foo"], name: "multiple_indexes_foo_1"
- t.index ["foo"], name: "multiple_indexes_foo_2"
- end
+ def test_schema_load_with_multiple_indexes_for_column_of_different_names
+ ActiveRecord::Schema.define do
+ create_table :multiple_indexes do |t|
+ t.string "foo"
+ t.index ["foo"], name: "multiple_indexes_foo_1"
+ t.index ["foo"], name: "multiple_indexes_foo_2"
end
+ end
- indexes = @connection.indexes("multiple_indexes")
+ indexes = @connection.indexes("multiple_indexes")
- assert_equal 2, indexes.length
- assert_equal ["multiple_indexes_foo_1", "multiple_indexes_foo_2"], indexes.collect(&:name).sort
- end
+ assert_equal 2, indexes.length
+ assert_equal ["multiple_indexes_foo_1", "multiple_indexes_foo_2"], indexes.collect(&:name).sort
+ end
- def test_timestamps_without_null_set_null_to_false_on_create_table
- ActiveRecord::Schema.define do
- create_table :has_timestamps do |t|
- t.timestamps
- end
+ def test_timestamps_without_null_set_null_to_false_on_create_table
+ ActiveRecord::Schema.define do
+ create_table :has_timestamps do |t|
+ t.timestamps
end
-
- assert !@connection.columns(:has_timestamps).find { |c| c.name == "created_at" }.null
- assert !@connection.columns(:has_timestamps).find { |c| c.name == "updated_at" }.null
end
- def test_timestamps_without_null_set_null_to_false_on_change_table
- ActiveRecord::Schema.define do
- create_table :has_timestamps
+ assert !@connection.columns(:has_timestamps).find { |c| c.name == "created_at" }.null
+ assert !@connection.columns(:has_timestamps).find { |c| c.name == "updated_at" }.null
+ end
- change_table :has_timestamps do |t|
- t.timestamps default: Time.now
- end
- end
+ def test_timestamps_without_null_set_null_to_false_on_change_table
+ ActiveRecord::Schema.define do
+ create_table :has_timestamps
- assert !@connection.columns(:has_timestamps).find { |c| c.name == "created_at" }.null
- assert !@connection.columns(:has_timestamps).find { |c| c.name == "updated_at" }.null
+ change_table :has_timestamps do |t|
+ t.timestamps default: Time.now
+ end
end
- def test_timestamps_without_null_set_null_to_false_on_add_timestamps
- ActiveRecord::Schema.define do
- create_table :has_timestamps
- add_timestamps :has_timestamps, default: Time.now
- end
+ assert !@connection.columns(:has_timestamps).find { |c| c.name == "created_at" }.null
+ assert !@connection.columns(:has_timestamps).find { |c| c.name == "updated_at" }.null
+ end
- assert !@connection.columns(:has_timestamps).find { |c| c.name == "created_at" }.null
- assert !@connection.columns(:has_timestamps).find { |c| c.name == "updated_at" }.null
+ def test_timestamps_without_null_set_null_to_false_on_add_timestamps
+ ActiveRecord::Schema.define do
+ create_table :has_timestamps
+ add_timestamps :has_timestamps, default: Time.now
end
+
+ assert !@connection.columns(:has_timestamps).find { |c| c.name == "created_at" }.null
+ assert !@connection.columns(:has_timestamps).find { |c| c.name == "updated_at" }.null
end
end
diff --git a/activerecord/test/cases/associations/eager_singularization_test.rb b/activerecord/test/cases/associations/eager_singularization_test.rb
index 5d1c1c4b9b..16eff15026 100644
--- a/activerecord/test/cases/associations/eager_singularization_test.rb
+++ b/activerecord/test/cases/associations/eager_singularization_test.rb
@@ -1,147 +1,146 @@
require "cases/helper"
-if ActiveRecord::Base.connection.supports_migrations?
- class EagerSingularizationTest < ActiveRecord::TestCase
- class Virus < ActiveRecord::Base
- belongs_to :octopus
- end
-
- class Octopus < ActiveRecord::Base
- has_one :virus
- end
-
- class Pass < ActiveRecord::Base
- belongs_to :bus
- end
-
- class Bus < ActiveRecord::Base
- has_many :passes
- end
-
- class Mess < ActiveRecord::Base
- has_and_belongs_to_many :crises
- end
-
- class Crisis < ActiveRecord::Base
- has_and_belongs_to_many :messes
- has_many :analyses, dependent: :destroy
- has_many :successes, through: :analyses
- has_many :dresses, dependent: :destroy
- has_many :compresses, through: :dresses
- end
-
- class Analysis < ActiveRecord::Base
- belongs_to :crisis
- belongs_to :success
- end
-
- class Success < ActiveRecord::Base
- has_many :analyses, dependent: :destroy
- has_many :crises, through: :analyses
- end
-
- class Dress < ActiveRecord::Base
- belongs_to :crisis
- has_many :compresses
- end
-
- class Compress < ActiveRecord::Base
- belongs_to :dress
- end
-
- def setup
- connection.create_table :viri do |t|
- t.column :octopus_id, :integer
- t.column :species, :string
- end
- connection.create_table :octopi do |t|
- t.column :species, :string
- end
- connection.create_table :passes do |t|
- t.column :bus_id, :integer
- t.column :rides, :integer
- end
- connection.create_table :buses do |t|
- t.column :name, :string
- end
- connection.create_table :crises_messes, id: false do |t|
- t.column :crisis_id, :integer
- t.column :mess_id, :integer
- end
- connection.create_table :messes do |t|
- t.column :name, :string
- end
- connection.create_table :crises do |t|
- t.column :name, :string
- end
- connection.create_table :successes do |t|
- t.column :name, :string
- end
- connection.create_table :analyses do |t|
- t.column :crisis_id, :integer
- t.column :success_id, :integer
- end
- connection.create_table :dresses do |t|
- t.column :crisis_id, :integer
- end
- connection.create_table :compresses do |t|
- t.column :dress_id, :integer
- end
- end
-
- teardown do
- connection.drop_table :viri
- connection.drop_table :octopi
- connection.drop_table :passes
- connection.drop_table :buses
- connection.drop_table :crises_messes
- connection.drop_table :messes
- connection.drop_table :crises
- connection.drop_table :successes
- connection.drop_table :analyses
- connection.drop_table :dresses
- connection.drop_table :compresses
- end
+class EagerSingularizationTest < ActiveRecord::TestCase
+ class Virus < ActiveRecord::Base
+ belongs_to :octopus
+ end
- def connection
- ActiveRecord::Base.connection
+ class Octopus < ActiveRecord::Base
+ has_one :virus
+ end
+
+ class Pass < ActiveRecord::Base
+ belongs_to :bus
+ end
+
+ class Bus < ActiveRecord::Base
+ has_many :passes
+ end
+
+ class Mess < ActiveRecord::Base
+ has_and_belongs_to_many :crises
+ end
+
+ class Crisis < ActiveRecord::Base
+ has_and_belongs_to_many :messes
+ has_many :analyses, dependent: :destroy
+ has_many :successes, through: :analyses
+ has_many :dresses, dependent: :destroy
+ has_many :compresses, through: :dresses
+ end
+
+ class Analysis < ActiveRecord::Base
+ belongs_to :crisis
+ belongs_to :success
+ end
+
+ class Success < ActiveRecord::Base
+ has_many :analyses, dependent: :destroy
+ has_many :crises, through: :analyses
+ end
+
+ class Dress < ActiveRecord::Base
+ belongs_to :crisis
+ has_many :compresses
+ end
+
+ class Compress < ActiveRecord::Base
+ belongs_to :dress
+ end
+
+ def setup
+ connection.create_table :viri do |t|
+ t.column :octopus_id, :integer
+ t.column :species, :string
end
+ connection.create_table :octopi do |t|
+ t.column :species, :string
+ end
+ connection.create_table :passes do |t|
+ t.column :bus_id, :integer
+ t.column :rides, :integer
+ end
+ connection.create_table :buses do |t|
+ t.column :name, :string
+ end
+ connection.create_table :crises_messes, id: false do |t|
+ t.column :crisis_id, :integer
+ t.column :mess_id, :integer
+ end
+ connection.create_table :messes do |t|
+ t.column :name, :string
+ end
+ connection.create_table :crises do |t|
+ t.column :name, :string
+ end
+ connection.create_table :successes do |t|
+ t.column :name, :string
+ end
+ connection.create_table :analyses do |t|
+ t.column :crisis_id, :integer
+ t.column :success_id, :integer
+ end
+ connection.create_table :dresses do |t|
+ t.column :crisis_id, :integer
+ end
+ connection.create_table :compresses do |t|
+ t.column :dress_id, :integer
+ end
+ end
- def test_eager_no_extra_singularization_belongs_to
- assert_nothing_raised do
- Virus.all.merge!(includes: :octopus).to_a
- end
+ teardown do
+ connection.drop_table :viri
+ connection.drop_table :octopi
+ connection.drop_table :passes
+ connection.drop_table :buses
+ connection.drop_table :crises_messes
+ connection.drop_table :messes
+ connection.drop_table :crises
+ connection.drop_table :successes
+ connection.drop_table :analyses
+ connection.drop_table :dresses
+ connection.drop_table :compresses
+ end
+
+ def test_eager_no_extra_singularization_belongs_to
+ assert_nothing_raised do
+ Virus.all.merge!(includes: :octopus).to_a
end
+ end
- def test_eager_no_extra_singularization_has_one
- assert_nothing_raised do
- Octopus.all.merge!(includes: :virus).to_a
- end
+ def test_eager_no_extra_singularization_has_one
+ assert_nothing_raised do
+ Octopus.all.merge!(includes: :virus).to_a
end
+ end
- def test_eager_no_extra_singularization_has_many
- assert_nothing_raised do
- Bus.all.merge!(includes: :passes).to_a
- end
+ def test_eager_no_extra_singularization_has_many
+ assert_nothing_raised do
+ Bus.all.merge!(includes: :passes).to_a
end
+ end
- def test_eager_no_extra_singularization_has_and_belongs_to_many
- assert_nothing_raised do
- Crisis.all.merge!(includes: :messes).to_a
- Mess.all.merge!(includes: :crises).to_a
- end
+ def test_eager_no_extra_singularization_has_and_belongs_to_many
+ assert_nothing_raised do
+ Crisis.all.merge!(includes: :messes).to_a
+ Mess.all.merge!(includes: :crises).to_a
end
+ end
- def test_eager_no_extra_singularization_has_many_through_belongs_to
- assert_nothing_raised do
- Crisis.all.merge!(includes: :successes).to_a
- end
+ def test_eager_no_extra_singularization_has_many_through_belongs_to
+ assert_nothing_raised do
+ Crisis.all.merge!(includes: :successes).to_a
end
+ end
- def test_eager_no_extra_singularization_has_many_through_has_many
- assert_nothing_raised do
- Crisis.all.merge!(includes: :compresses).to_a
- end
+ def test_eager_no_extra_singularization_has_many_through_has_many
+ assert_nothing_raised do
+ Crisis.all.merge!(includes: :compresses).to_a
end
end
+
+ private
+ def connection
+ ActiveRecord::Base.connection
+ end
end
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index cbecfa84ff..14f515fa1c 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -611,21 +611,16 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_update_all_on_association_accessed_before_save
firm = Firm.new(name: "Firm")
- clients_proxy_id = firm.clients.object_id
firm.clients << Client.first
firm.save!
assert_equal firm.clients.count, firm.clients.update_all(description: "Great!")
- assert_not_equal clients_proxy_id, firm.clients.object_id
end
def test_update_all_on_association_accessed_before_save_with_explicit_foreign_key
- # We can use the same cached proxy object because the id is available for the scope
firm = Firm.new(name: "Firm", id: 100)
- clients_proxy_id = firm.clients.object_id
firm.clients << Client.first
firm.save!
assert_equal firm.clients.count, firm.clients.update_all(description: "Great!")
- assert_equal clients_proxy_id, firm.clients.object_id
end
def test_belongs_to_sanity
@@ -788,6 +783,12 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal [1], posts(:welcome).comments.select { |c| c.id == 1 }.map(&:id)
end
+ def test_select_with_block_and_dirty_target
+ assert_equal 2, posts(:welcome).comments.select { true }.size
+ posts(:welcome).comments.build
+ assert_equal 3, posts(:welcome).comments.select { true }.size
+ end
+
def test_select_without_foreign_key
assert_equal companies(:first_firm).accounts.first.credit_limit, companies(:first_firm).accounts.select(:credit_limit).first.credit_limit
end
diff --git a/activerecord/test/cases/associations/required_test.rb b/activerecord/test/cases/associations/required_test.rb
index f8b686721e..45e1803858 100644
--- a/activerecord/test/cases/associations/required_test.rb
+++ b/activerecord/test/cases/associations/required_test.rb
@@ -22,14 +22,21 @@ class RequiredAssociationsTest < ActiveRecord::TestCase
@connection.drop_table "children", if_exists: true
end
- test "belongs_to associations are not required by default" do
- model = subclass_of(Child) do
- belongs_to :parent, inverse_of: false,
- class_name: "RequiredAssociationsTest::Parent"
- end
+ test "belongs_to associations can be optional by default" do
+ begin
+ original_value = ActiveRecord::Base.belongs_to_required_by_default
+ ActiveRecord::Base.belongs_to_required_by_default = false
+
+ model = subclass_of(Child) do
+ belongs_to :parent, inverse_of: false,
+ class_name: "RequiredAssociationsTest::Parent"
+ end
- assert model.new.save
- assert model.new(parent: Parent.new).save
+ assert model.new.save
+ assert model.new(parent: Parent.new).save
+ ensure
+ ActiveRecord::Base.belongs_to_required_by_default = original_value
+ end
end
test "required belongs_to associations have presence validated" do
@@ -46,6 +53,27 @@ class RequiredAssociationsTest < ActiveRecord::TestCase
assert record.save
end
+ test "belongs_to associations can be required by default" do
+ begin
+ original_value = ActiveRecord::Base.belongs_to_required_by_default
+ ActiveRecord::Base.belongs_to_required_by_default = true
+
+ model = subclass_of(Child) do
+ belongs_to :parent, inverse_of: false,
+ class_name: "RequiredAssociationsTest::Parent"
+ end
+
+ record = model.new
+ assert_not record.save
+ assert_equal ["Parent must exist"], record.errors.full_messages
+
+ record.parent = Parent.new
+ assert record.save
+ ensure
+ ActiveRecord::Base.belongs_to_required_by_default = original_value
+ end
+ end
+
test "has_one associations are not required by default" do
model = subclass_of(Parent) do
has_one :child, inverse_of: false,
diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb
index a223b4338f..26056f6f63 100644
--- a/activerecord/test/cases/associations_test.rb
+++ b/activerecord/test/cases/associations_test.rb
@@ -220,11 +220,6 @@ class AssociationProxyTest < ActiveRecord::TestCase
assert_equal david.projects, david.projects.scope
end
- test "proxy object is cached" do
- david = developers(:david)
- assert david.projects.equal?(david.projects)
- end
-
test "inverses get set of subsets of the association" do
man = Man.create
man.interests.create
diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb
index 3dc0c0ce53..4d24a980dc 100644
--- a/activerecord/test/cases/attribute_methods_test.rb
+++ b/activerecord/test/cases/attribute_methods_test.rb
@@ -866,6 +866,13 @@ class AttributeMethodsTest < ActiveRecord::TestCase
assert subklass.method_defined?(:id), "subklass is missing id method"
end
+ test "define_attribute_method works with both symbol and string" do
+ klass = Class.new(ActiveRecord::Base)
+
+ assert_nothing_raised { klass.define_attribute_method(:foo) }
+ assert_nothing_raised { klass.define_attribute_method("bar") }
+ end
+
test "read_attribute with nil should not asplode" do
assert_nil Topic.new.read_attribute(nil)
end
diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb
index 1813534b62..3214d778d4 100644
--- a/activerecord/test/cases/calculations_test.rb
+++ b/activerecord/test/cases/calculations_test.rb
@@ -227,6 +227,20 @@ class CalculationsTest < ActiveRecord::TestCase
assert_match "credit_limit, firm_name", e.message
end
+ def test_apply_distinct_in_count
+ queries = assert_sql do
+ Account.distinct.count
+ Account.group(:firm_id).distinct.count
+ end
+
+ queries.each do |query|
+ # `table_alias_length` in `column_alias_for` would execute
+ # "SHOW max_identifier_length" statement in PostgreSQL adapter.
+ next if query == "SHOW max_identifier_length"
+ assert_match %r{\ASELECT(?! DISTINCT) COUNT\(DISTINCT\b}, query
+ end
+ end
+
def test_should_group_by_summed_field_having_condition
c = Account.group(:firm_id).having("sum(credit_limit) > 50").sum(:credit_limit)
assert_nil c[1]
@@ -235,7 +249,8 @@ class CalculationsTest < ActiveRecord::TestCase
end
def test_should_group_by_summed_field_having_condition_from_select
- c = Account.select("MIN(credit_limit) AS min_credit_limit").group(:firm_id).having("MIN(credit_limit) > 50").sum(:credit_limit)
+ skip unless current_adapter?(:Mysql2Adapter, :SQLite3Adapter)
+ c = Account.select("MIN(credit_limit) AS min_credit_limit").group(:firm_id).having("min_credit_limit > 50").sum(:credit_limit)
assert_nil c[1]
assert_equal 60, c[2]
assert_equal 53, c[9]
diff --git a/activerecord/test/cases/connection_adapters/connection_handler_test.rb b/activerecord/test/cases/connection_adapters/connection_handler_test.rb
index 4f2392042b..681399c8bb 100644
--- a/activerecord/test/cases/connection_adapters/connection_handler_test.rb
+++ b/activerecord/test/cases/connection_adapters/connection_handler_test.rb
@@ -20,6 +20,66 @@ module ActiveRecord
@handler.remove_connection("readonly")
end
+ def test_establish_connection_using_3_levels_config
+ previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
+
+ config = {
+ "default_env" => {
+ "readonly" => { "adapter" => "sqlite3", "database" => "db/readonly.sqlite3" },
+ "primary" => { "adapter" => "sqlite3", "database" => "db/primary.sqlite3" }
+ },
+ "another_env" => {
+ "readonly" => { "adapter" => "sqlite3", "database" => "db/bad-readonly.sqlite3" },
+ "primary" => { "adapter" => "sqlite3", "database" => "db/bad-primary.sqlite3" }
+ },
+ "common" => { "adapter" => "sqlite3", "database" => "db/common.sqlite3" }
+ }
+ @prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
+
+ @handler.establish_connection(:common)
+ @handler.establish_connection(:primary)
+ @handler.establish_connection(:readonly)
+
+ assert_not_nil pool = @handler.retrieve_connection_pool("readonly")
+ assert_equal "db/readonly.sqlite3", pool.spec.config[:database]
+
+ assert_not_nil pool = @handler.retrieve_connection_pool("primary")
+ assert_equal "db/primary.sqlite3", pool.spec.config[:database]
+
+ assert_not_nil pool = @handler.retrieve_connection_pool("common")
+ assert_equal "db/common.sqlite3", pool.spec.config[:database]
+ ensure
+ ActiveRecord::Base.configurations = @prev_configs
+ ENV["RAILS_ENV"] = previous_env
+ end
+
+ def test_establish_connection_using_two_level_configurations
+ config = { "development" => { "adapter" => "sqlite3", "database" => "db/primary.sqlite3" } }
+ @prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
+
+ @handler.establish_connection(:development)
+
+ assert_not_nil pool = @handler.retrieve_connection_pool("development")
+ assert_equal "db/primary.sqlite3", pool.spec.config[:database]
+ ensure
+ ActiveRecord::Base.configurations = @prev_configs
+ end
+
+ def test_establish_connection_using_top_level_key_in_two_level_config
+ config = {
+ "development" => { "adapter" => "sqlite3", "database" => "db/primary.sqlite3" },
+ "development_readonly" => { "adapter" => "sqlite3", "database" => "db/readonly.sqlite3" }
+ }
+ @prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
+
+ @handler.establish_connection(:development_readonly)
+
+ assert_not_nil pool = @handler.retrieve_connection_pool("development_readonly")
+ assert_equal "db/readonly.sqlite3", pool.spec.config[:database]
+ ensure
+ ActiveRecord::Base.configurations = @prev_configs
+ end
+
def test_retrieve_connection
assert @handler.retrieve_connection(@spec_name)
end
diff --git a/activerecord/test/cases/connection_pool_test.rb b/activerecord/test/cases/connection_pool_test.rb
index afd0ac2dd4..7e88c9cf7a 100644
--- a/activerecord/test/cases/connection_pool_test.rb
+++ b/activerecord/test/cases/connection_pool_test.rb
@@ -307,14 +307,17 @@ module ActiveRecord
end
end
- def test_automatic_reconnect=
+ def test_automatic_reconnect_restores_after_disconnect
pool = ConnectionPool.new ActiveRecord::Base.connection_pool.spec
assert pool.automatic_reconnect
assert pool.connection
pool.disconnect!
assert pool.connection
+ end
+ def test_automatic_reconnect_can_be_disabled
+ pool = ConnectionPool.new ActiveRecord::Base.connection_pool.spec
pool.disconnect!
pool.automatic_reconnect = false
diff --git a/activerecord/test/cases/date_time_test.rb b/activerecord/test/cases/date_time_test.rb
index 3bc08f80ec..ad7da9de70 100644
--- a/activerecord/test/cases/date_time_test.rb
+++ b/activerecord/test/cases/date_time_test.rb
@@ -52,7 +52,7 @@ class DateTimeTest < ActiveRecord::TestCase
end
def test_assign_in_local_timezone
- now = DateTime.now
+ now = DateTime.civil(2017, 3, 1, 12, 0, 0)
with_timezone_config default: :local do
task = Task.new starting: now
assert_equal now, task.starting
diff --git a/activerecord/test/cases/defaults_test.rb b/activerecord/test/cases/defaults_test.rb
index 6532efcf22..a6297673c9 100644
--- a/activerecord/test/cases/defaults_test.rb
+++ b/activerecord/test/cases/defaults_test.rb
@@ -100,11 +100,21 @@ if current_adapter?(:Mysql2Adapter)
include SchemaDumpingHelper
if ActiveRecord::Base.connection.version >= "5.6.0"
- test "schema dump includes default expression" do
+ test "schema dump datetime includes default expression" do
output = dump_table_schema("datetime_defaults")
assert_match %r/t\.datetime\s+"modified_datetime",\s+default: -> { "CURRENT_TIMESTAMP" }/, output
end
end
+
+ test "schema dump timestamp includes default expression" do
+ output = dump_table_schema("timestamp_defaults")
+ assert_match %r/t\.timestamp\s+"modified_timestamp",\s+default: -> { "CURRENT_TIMESTAMP" }/, output
+ end
+
+ test "schema dump timestamp without default expression" do
+ output = dump_table_schema("timestamp_defaults")
+ assert_match %r/t\.timestamp\s+"nullable_timestamp"$/, output
+ end
end
class DefaultsTestWithoutTransactionalFixtures < ActiveRecord::TestCase
diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb
index c0d6ddcea7..c13a962e3e 100644
--- a/activerecord/test/cases/dirty_test.rb
+++ b/activerecord/test/cases/dirty_test.rb
@@ -566,18 +566,17 @@ class DirtyTest < ActiveRecord::TestCase
travel_back
end
- if ActiveRecord::Base.connection.supports_migrations?
- class Testings < ActiveRecord::Base; end
- def test_field_named_field
- ActiveRecord::Base.connection.create_table :testings do |t|
- t.string :field
- end
- assert_nothing_raised do
- Testings.new.attributes
- end
- ensure
- ActiveRecord::Base.connection.drop_table :testings rescue nil
+ class Testings < ActiveRecord::Base; end
+ def test_field_named_field
+ ActiveRecord::Base.connection.create_table :testings do |t|
+ t.string :field
end
+ assert_nothing_raised do
+ Testings.new.attributes
+ end
+ ensure
+ ActiveRecord::Base.connection.drop_table :testings rescue nil
+ ActiveRecord::Base.clear_cache!
end
def test_datetime_attribute_can_be_updated_with_fractional_seconds
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index deec669935..89d8a8bdca 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -497,7 +497,7 @@ class FinderTest < ActiveRecord::TestCase
assert_nil Topic.offset(5).second_to_last
#test with limit
- # assert_nil Topic.limit(1).second # TODO: currently failing
+ assert_nil Topic.limit(1).second
assert_nil Topic.limit(1).second_to_last
end
@@ -526,9 +526,9 @@ class FinderTest < ActiveRecord::TestCase
assert_nil Topic.offset(5).third_to_last
# test with limit
- # assert_nil Topic.limit(1).third # TODO: currently failing
+ assert_nil Topic.limit(1).third
assert_nil Topic.limit(1).third_to_last
- # assert_nil Topic.limit(2).third # TODO: currently failing
+ assert_nil Topic.limit(2).third
assert_nil Topic.limit(2).third_to_last
end
diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb
index 61e596e208..51133e9495 100644
--- a/activerecord/test/cases/fixtures_test.rb
+++ b/activerecord/test/cases/fixtures_test.rb
@@ -104,64 +104,62 @@ class FixturesTest < ActiveRecord::TestCase
assert_nil(second_row["author_email_address"])
end
- if ActiveRecord::Base.connection.supports_migrations?
- def test_inserts_with_pre_and_suffix
- # Reset cache to make finds on the new table work
- ActiveRecord::FixtureSet.reset_cache
-
- ActiveRecord::Base.connection.create_table :prefix_other_topics_suffix do |t|
- t.column :title, :string
- t.column :author_name, :string
- t.column :author_email_address, :string
- t.column :written_on, :datetime
- t.column :bonus_time, :time
- t.column :last_read, :date
- t.column :content, :string
- t.column :approved, :boolean, default: true
- t.column :replies_count, :integer, default: 0
- t.column :parent_id, :integer
- t.column :type, :string, limit: 50
- end
+ def test_inserts_with_pre_and_suffix
+ # Reset cache to make finds on the new table work
+ ActiveRecord::FixtureSet.reset_cache
+
+ ActiveRecord::Base.connection.create_table :prefix_other_topics_suffix do |t|
+ t.column :title, :string
+ t.column :author_name, :string
+ t.column :author_email_address, :string
+ t.column :written_on, :datetime
+ t.column :bonus_time, :time
+ t.column :last_read, :date
+ t.column :content, :string
+ t.column :approved, :boolean, default: true
+ t.column :replies_count, :integer, default: 0
+ t.column :parent_id, :integer
+ t.column :type, :string, limit: 50
+ end
- # Store existing prefix/suffix
- old_prefix = ActiveRecord::Base.table_name_prefix
- old_suffix = ActiveRecord::Base.table_name_suffix
+ # Store existing prefix/suffix
+ old_prefix = ActiveRecord::Base.table_name_prefix
+ old_suffix = ActiveRecord::Base.table_name_suffix
- # Set a prefix/suffix we can test against
- ActiveRecord::Base.table_name_prefix = "prefix_"
- ActiveRecord::Base.table_name_suffix = "_suffix"
+ # Set a prefix/suffix we can test against
+ ActiveRecord::Base.table_name_prefix = "prefix_"
+ ActiveRecord::Base.table_name_suffix = "_suffix"
- other_topic_klass = Class.new(ActiveRecord::Base) do
- def self.name
- "OtherTopic"
- end
+ other_topic_klass = Class.new(ActiveRecord::Base) do
+ def self.name
+ "OtherTopic"
end
+ end
- topics = [create_fixtures("other_topics")].flatten.first
+ topics = [create_fixtures("other_topics")].flatten.first
- # This checks for a caching problem which causes a bug in the fixtures
- # class-level configuration helper.
- assert_not_nil topics, "Fixture data inserted, but fixture objects not returned from create"
+ # This checks for a caching problem which causes a bug in the fixtures
+ # class-level configuration helper.
+ assert_not_nil topics, "Fixture data inserted, but fixture objects not returned from create"
- first_row = ActiveRecord::Base.connection.select_one("SELECT * FROM prefix_other_topics_suffix WHERE author_name = 'David'")
- assert_not_nil first_row, "The prefix_other_topics_suffix table appears to be empty despite create_fixtures: the row with author_name = 'David' was not found"
- assert_equal("The First Topic", first_row["title"])
+ first_row = ActiveRecord::Base.connection.select_one("SELECT * FROM prefix_other_topics_suffix WHERE author_name = 'David'")
+ assert_not_nil first_row, "The prefix_other_topics_suffix table appears to be empty despite create_fixtures: the row with author_name = 'David' was not found"
+ assert_equal("The First Topic", first_row["title"])
- second_row = ActiveRecord::Base.connection.select_one("SELECT * FROM prefix_other_topics_suffix WHERE author_name = 'Mary'")
- assert_nil(second_row["author_email_address"])
+ second_row = ActiveRecord::Base.connection.select_one("SELECT * FROM prefix_other_topics_suffix WHERE author_name = 'Mary'")
+ assert_nil(second_row["author_email_address"])
- assert_equal :prefix_other_topics_suffix, topics.table_name.to_sym
- # This assertion should preferably be the last in the list, because calling
- # other_topic_klass.table_name sets a class-level instance variable
- assert_equal :prefix_other_topics_suffix, other_topic_klass.table_name.to_sym
+ assert_equal :prefix_other_topics_suffix, topics.table_name.to_sym
+ # This assertion should preferably be the last in the list, because calling
+ # other_topic_klass.table_name sets a class-level instance variable
+ assert_equal :prefix_other_topics_suffix, other_topic_klass.table_name.to_sym
- ensure
- # Restore prefix/suffix to its previous values
- ActiveRecord::Base.table_name_prefix = old_prefix
- ActiveRecord::Base.table_name_suffix = old_suffix
+ ensure
+ # Restore prefix/suffix to its previous values
+ ActiveRecord::Base.table_name_prefix = old_prefix
+ ActiveRecord::Base.table_name_suffix = old_suffix
- ActiveRecord::Base.connection.drop_table :prefix_other_topics_suffix rescue nil
- end
+ ActiveRecord::Base.connection.drop_table :prefix_other_topics_suffix rescue nil
end
def test_insert_with_datetime
@@ -640,6 +638,8 @@ class TransactionalFixturesOnConnectionNotification < ActiveRecord::TestCase
def test_transaction_created_on_connection_notification
connection = stub(transaction_open?: false)
connection.expects(:begin_transaction).with(joinable: false)
+ pool = connection.stubs(:pool).returns(ActiveRecord::ConnectionAdapters::ConnectionPool.new(ActiveRecord::Base.connection_pool.spec))
+ pool.stubs(:lock_thread=).with(false)
fire_connection_notification(connection)
end
@@ -647,12 +647,16 @@ class TransactionalFixturesOnConnectionNotification < ActiveRecord::TestCase
# Mocha is not thread-safe so define our own stub to test
connection = Class.new do
attr_accessor :rollback_transaction_called
+ attr_accessor :pool
def transaction_open?; true; end
def begin_transaction(*args); end
def rollback_transaction(*args)
@rollback_transaction_called = true
end
end.new
+ connection.pool = Class.new do
+ def lock_thread=(lock_thread); false; end
+ end.new
fire_connection_notification(connection)
teardown_fixtures
assert(connection.rollback_transaction_called, "Expected <mock connection>#rollback_transaction to be called but was not")
diff --git a/activerecord/test/cases/migration/change_schema_test.rb b/activerecord/test/cases/migration/change_schema_test.rb
index 48cfe89882..1d305fa11f 100644
--- a/activerecord/test/cases/migration/change_schema_test.rb
+++ b/activerecord/test/cases/migration/change_schema_test.rb
@@ -269,6 +269,8 @@ module ActiveRecord
if current_adapter?(:PostgreSQLAdapter)
assert_equal "timestamp without time zone", klass.columns_hash["foo"].sql_type
+ elsif current_adapter?(:Mysql2Adapter)
+ assert_equal "timestamp", klass.columns_hash["foo"].sql_type
else
assert_equal klass.connection.type_to_sql("datetime"), klass.columns_hash["foo"].sql_type
end
diff --git a/activerecord/test/cases/migration/columns_test.rb b/activerecord/test/cases/migration/columns_test.rb
index 55c06da411..2329888345 100644
--- a/activerecord/test/cases/migration/columns_test.rb
+++ b/activerecord/test/cases/migration/columns_test.rb
@@ -225,6 +225,16 @@ module ActiveRecord
assert_nil TestModel.new.contributor
end
+ def test_change_column_to_drop_default_with_null_false
+ add_column "test_models", "contributor", :boolean, default: true, null: false
+ assert TestModel.new.contributor?
+
+ change_column "test_models", "contributor", :boolean, default: nil, null: false
+ TestModel.reset_column_information
+ assert_not TestModel.new.contributor?
+ assert_nil TestModel.new.contributor
+ end
+
def test_change_column_with_new_default
add_column "test_models", "administrator", :boolean, default: true
assert TestModel.new.administrator?
diff --git a/activerecord/test/cases/migration/create_join_table_test.rb b/activerecord/test/cases/migration/create_join_table_test.rb
index 26b1bb4419..c4896f3d6e 100644
--- a/activerecord/test/cases/migration/create_join_table_test.rb
+++ b/activerecord/test/cases/migration/create_join_table_test.rb
@@ -12,7 +12,7 @@ module ActiveRecord
teardown do
%w(artists_musics musics_videos catalog).each do |table_name|
- connection.drop_table table_name if connection.table_exists?(table_name)
+ connection.drop_table table_name, if_exists: true
end
end
@@ -78,6 +78,17 @@ module ActiveRecord
assert_equal [%w(artist_id music_id)], connection.indexes(:artists_musics).map(&:columns)
end
+ def test_create_join_table_respects_reference_key_type
+ connection.create_join_table :artists, :musics do |t|
+ t.references :video
+ end
+
+ artist_id, music_id, video_id = connection.columns(:artists_musics).sort_by(&:name)
+
+ assert_equal video_id.sql_type, artist_id.sql_type
+ assert_equal video_id.sql_type, music_id.sql_type
+ end
+
def test_drop_join_table
connection.create_join_table :artists, :musics
connection.drop_join_table :artists, :musics
diff --git a/activerecord/test/cases/migration/pending_migrations_test.rb b/activerecord/test/cases/migration/pending_migrations_test.rb
index 61f5a061b0..6970fdcc87 100644
--- a/activerecord/test/cases/migration/pending_migrations_test.rb
+++ b/activerecord/test/cases/migration/pending_migrations_test.rb
@@ -21,8 +21,6 @@ module ActiveRecord
end
def test_errors_if_pending
- @connection.expect :supports_migrations?, true
-
ActiveRecord::Migrator.stub :needs_migration?, true do
assert_raise ActiveRecord::PendingMigrationError do
@pending.call(nil)
@@ -31,22 +29,12 @@ module ActiveRecord
end
def test_checks_if_supported
- @connection.expect :supports_migrations?, true
@app.expect :call, nil, [:foo]
ActiveRecord::Migrator.stub :needs_migration?, false do
@pending.call(:foo)
end
end
-
- def test_doesnt_check_if_unsupported
- @connection.expect :supports_migrations?, false
- @app.expect :call, nil, [:foo]
-
- ActiveRecord::Migrator.stub :needs_migration?, true do
- @pending.call(:foo)
- end
- end
end
end
end
diff --git a/activerecord/test/cases/migration/references_foreign_key_test.rb b/activerecord/test/cases/migration/references_foreign_key_test.rb
index 9418995ea0..f1ddac1ee2 100644
--- a/activerecord/test/cases/migration/references_foreign_key_test.rb
+++ b/activerecord/test/cases/migration/references_foreign_key_test.rb
@@ -203,6 +203,22 @@ if ActiveRecord::Base.connection.supports_foreign_keys?
assert_equal([["testings", "testing_parents", "parent1_id"],
["testings", "testing_parents", "parent2_id"]], fk_definitions)
end
+
+ test "multiple foreign keys can be removed to the selected one" do
+ @connection.create_table :testings do |t|
+ t.references :parent1, foreign_key: { to_table: :testing_parents }
+ t.references :parent2, foreign_key: { to_table: :testing_parents }
+ end
+
+ assert_difference "@connection.foreign_keys('testings').size", -1 do
+ @connection.remove_reference :testings, :parent1, foreign_key: { to_table: :testing_parents }
+ end
+
+ fks = @connection.foreign_keys("testings").sort_by(&:column)
+
+ fk_definitions = fks.map { |fk| [fk.from_table, fk.to_table, fk.column] }
+ assert_equal([["testings", "testing_parents", "parent2_id"]], fk_definitions)
+ end
end
end
end
diff --git a/activerecord/test/cases/migration/references_statements_test.rb b/activerecord/test/cases/migration/references_statements_test.rb
index df15d7cb45..06c44c8c52 100644
--- a/activerecord/test/cases/migration/references_statements_test.rb
+++ b/activerecord/test/cases/migration/references_statements_test.rb
@@ -50,6 +50,13 @@ module ActiveRecord
assert column_exists?(table_name, :taggable_type, :string, default: "Photo")
end
+ def test_does_not_share_options_with_reference_type_column
+ add_reference table_name, :taggable, type: :integer, limit: 2, polymorphic: true
+ assert column_exists?(table_name, :taggable_id, :integer, limit: 2)
+ assert column_exists?(table_name, :taggable_type, :string)
+ assert_not column_exists?(table_name, :taggable_type, :string, limit: 2)
+ end
+
def test_creates_named_index
add_reference table_name, :tag, index: { name: "index_taggings_on_tag_id" }
assert index_exists?(table_name, :tag_id, name: "index_taggings_on_tag_id")
diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
index de16ecf442..da7875187a 100644
--- a/activerecord/test/cases/migration_test.rb
+++ b/activerecord/test/cases/migration_test.rb
@@ -337,20 +337,20 @@ class MigrationTest < ActiveRecord::TestCase
end
def test_schema_migrations_table_name
- original_schema_migrations_table_name = ActiveRecord::Migrator.schema_migrations_table_name
+ original_schema_migrations_table_name = ActiveRecord::Base.schema_migrations_table_name
- assert_equal "schema_migrations", ActiveRecord::Migrator.schema_migrations_table_name
+ assert_equal "schema_migrations", ActiveRecord::SchemaMigration.table_name
ActiveRecord::Base.table_name_prefix = "prefix_"
ActiveRecord::Base.table_name_suffix = "_suffix"
Reminder.reset_table_name
- assert_equal "prefix_schema_migrations_suffix", ActiveRecord::Migrator.schema_migrations_table_name
+ assert_equal "prefix_schema_migrations_suffix", ActiveRecord::SchemaMigration.table_name
ActiveRecord::Base.schema_migrations_table_name = "changed"
Reminder.reset_table_name
- assert_equal "prefix_changed_suffix", ActiveRecord::Migrator.schema_migrations_table_name
+ assert_equal "prefix_changed_suffix", ActiveRecord::SchemaMigration.table_name
ActiveRecord::Base.table_name_prefix = ""
ActiveRecord::Base.table_name_suffix = ""
Reminder.reset_table_name
- assert_equal "changed", ActiveRecord::Migrator.schema_migrations_table_name
+ assert_equal "changed", ActiveRecord::SchemaMigration.table_name
ensure
ActiveRecord::Base.schema_migrations_table_name = original_schema_migrations_table_name
Reminder.reset_table_name
@@ -1142,4 +1142,12 @@ class CopyMigrationsTest < ActiveRecord::TestCase
def test_deprecate_migration_keys
assert_deprecated { ActiveRecord::Base.connection.migration_keys }
end
+
+ def test_deprecate_supports_migrations
+ assert_deprecated { ActiveRecord::Base.connection.supports_migrations? }
+ end
+
+ def test_deprecate_schema_migrations_table_name
+ assert_deprecated { ActiveRecord::Migrator.schema_migrations_table_name }
+ end
end
diff --git a/activerecord/test/cases/migrator_test.rb b/activerecord/test/cases/migrator_test.rb
index 20d70b75ac..aadbc375af 100644
--- a/activerecord/test/cases/migrator_test.rb
+++ b/activerecord/test/cases/migrator_test.rb
@@ -124,6 +124,67 @@ class MigratorTest < ActiveRecord::TestCase
assert_equal migration_list.last, migrations.first
end
+ def test_migrations_status
+ path = MIGRATIONS_ROOT + "/valid"
+
+ ActiveRecord::SchemaMigration.create(version: 2)
+ ActiveRecord::SchemaMigration.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::Migrator.migrations_status(path)
+ end
+
+ def test_migrations_status_in_subdirectories
+ path = MIGRATIONS_ROOT + "/valid_with_subdirectories"
+
+ ActiveRecord::SchemaMigration.create(version: 2)
+ ActiveRecord::SchemaMigration.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::Migrator.migrations_status(path)
+ end
+
+ def test_migrations_status_with_schema_define_in_subdirectories
+ path = MIGRATIONS_ROOT + "/valid_with_subdirectories"
+ prev_paths = ActiveRecord::Migrator.migrations_paths
+ ActiveRecord::Migrator.migrations_paths = path
+
+ ActiveRecord::Schema.define(version: 3) do
+ end
+
+ assert_equal [
+ ["up", "001", "Valid people have last names"],
+ ["up", "002", "We need reminders"],
+ ["up", "003", "Innocent jointable"],
+ ], ActiveRecord::Migrator.migrations_status(path)
+ 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"]
+
+ ActiveRecord::SchemaMigration.create(version: "20100101010101")
+ ActiveRecord::SchemaMigration.create(version: "20160528010101")
+
+ assert_equal [
+ ["down", "20090101010101", "People have hobbies"],
+ ["down", "20090101010202", "People have descriptions"],
+ ["up", "20100101010101", "Valid with timestamps people have last names"],
+ ["down", "20100201010101", "Valid with timestamps we need reminders"],
+ ["down", "20100301010101", "Valid with timestamps innocent jointable"],
+ ["up", "20160528010101", "********** NO FILE **********"],
+ ], ActiveRecord::Migrator.migrations_status(paths)
+ end
+
def test_migrator_interleaved_migrations
pass_one = [Sensor.new("One", 1)]
diff --git a/activerecord/test/cases/primary_keys_test.rb b/activerecord/test/cases/primary_keys_test.rb
index 98b9c91489..12386635f6 100644
--- a/activerecord/test/cases/primary_keys_test.rb
+++ b/activerecord/test/cases/primary_keys_test.rb
@@ -238,13 +238,13 @@ class PrimaryKeyWithAutoIncrementTest < ActiveRecord::TestCase
@connection.drop_table(:auto_increments, if_exists: true)
end
- def test_primary_key_with_auto_increment
- @connection.create_table(:auto_increments, id: :integer, auto_increment: true, force: true)
+ def test_primary_key_with_integer
+ @connection.create_table(:auto_increments, id: :integer, force: true)
assert_auto_incremented
end
- def test_primary_key_with_auto_increment_and_bigint
- @connection.create_table(:auto_increments, id: :bigint, auto_increment: true, force: true)
+ def test_primary_key_with_bigint
+ @connection.create_table(:auto_increments, id: :bigint, force: true)
assert_auto_incremented
end
@@ -291,6 +291,14 @@ class PrimaryKeyAnyTypeTest < ActiveRecord::TestCase
schema = dump_table_schema "barcodes"
assert_match %r{create_table "barcodes", primary_key: "code", id: :string, limit: 42}, schema
end
+
+ if current_adapter?(:Mysql2Adapter) && subsecond_precision_supported?
+ test "schema typed primary key column" do
+ @connection.create_table(:scheduled_logs, id: :timestamp, precision: 6, force: true)
+ schema = dump_table_schema("scheduled_logs")
+ assert_match %r/create_table "scheduled_logs", id: :timestamp, precision: 6/, schema
+ end
+ end
end
class CompositePrimaryKeyTest < ActiveRecord::TestCase
diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb
index d8cf235000..494663eb04 100644
--- a/activerecord/test/cases/query_cache_test.rb
+++ b/activerecord/test/cases/query_cache_test.rb
@@ -532,4 +532,16 @@ class QueryCacheExpiryTest < ActiveRecord::TestCase
end
end
end
+
+ test "threads use the same connection" do
+ @connection_1 = ActiveRecord::Base.connection.object_id
+
+ thread_a = Thread.new do
+ @connection_2 = ActiveRecord::Base.connection.object_id
+ end
+
+ thread_a.join
+
+ assert_equal @connection_1, @connection_2
+ end
end
diff --git a/activerecord/test/cases/quoting_test.rb b/activerecord/test/cases/quoting_test.rb
index 5ff5e3c735..f260d043e4 100644
--- a/activerecord/test/cases/quoting_test.rb
+++ b/activerecord/test/cases/quoting_test.rb
@@ -82,7 +82,7 @@ module ActiveRecord
end
def test_quote_with_quoted_id
- assert_equal 1, @quoter.quote(Struct.new(:quoted_id).new(1))
+ assert_deprecated { assert_equal 1, @quoter.quote(Struct.new(:quoted_id).new(1)) }
end
def test_quote_nil
@@ -150,6 +150,62 @@ module ActiveRecord
end
end
+ class TypeCastingTest < ActiveRecord::TestCase
+ def setup
+ @conn = ActiveRecord::Base.connection
+ end
+
+ def test_type_cast_symbol
+ assert_equal "foo", @conn.type_cast(:foo)
+ end
+
+ def test_type_cast_date
+ date = Date.today
+ expected = @conn.quoted_date(date)
+ assert_equal expected, @conn.type_cast(date)
+ end
+
+ def test_type_cast_time
+ time = Time.now
+ expected = @conn.quoted_date(time)
+ assert_equal expected, @conn.type_cast(time)
+ end
+
+ def test_type_cast_numeric
+ assert_equal 10, @conn.type_cast(10)
+ assert_equal 2.2, @conn.type_cast(2.2)
+ end
+
+ def test_type_cast_nil
+ assert_nil @conn.type_cast(nil)
+ end
+
+ def test_type_cast_unknown_should_raise_error
+ obj = Class.new.new
+ assert_raise(TypeError) { @conn.type_cast(obj) }
+ end
+
+ def test_type_cast_object_which_responds_to_quoted_id
+ quoted_id_obj = Class.new {
+ def quoted_id
+ "'zomg'"
+ end
+
+ def id
+ 10
+ end
+ }.new
+ assert_equal 10, @conn.type_cast(quoted_id_obj)
+
+ quoted_id_obj = Class.new {
+ def quoted_id
+ "'zomg'"
+ end
+ }.new
+ assert_raise(TypeError) { @conn.type_cast(quoted_id_obj) }
+ end
+ end
+
class QuoteBooleanTest < ActiveRecord::TestCase
def setup
@connection = ActiveRecord::Base.connection
@@ -165,5 +221,32 @@ module ActiveRecord
assert_predicate @connection.type_cast(false), :frozen?
end
end
+
+ if subsecond_precision_supported?
+ class QuoteARBaseTest < ActiveRecord::TestCase
+ class DatetimePrimaryKey < ActiveRecord::Base
+ end
+
+ def setup
+ @time = ::Time.utc(2017, 2, 14, 12, 34, 56, 789999)
+ @connection = ActiveRecord::Base.connection
+ @connection.create_table :datetime_primary_keys, id: :datetime, precision: 3, force: true
+ end
+
+ def teardown
+ @connection.drop_table :datetime_primary_keys, if_exists: true
+ end
+
+ def test_quote_ar_object
+ value = DatetimePrimaryKey.new(id: @time)
+ assert_equal "'2017-02-14 12:34:56.789000'", @connection.quote(value)
+ end
+
+ def test_type_cast_ar_object
+ value = DatetimePrimaryKey.new(id: @time)
+ assert_equal "2017-02-14 12:34:56.789000", @connection.type_cast(value)
+ end
+ end
+ end
end
end
diff --git a/activerecord/test/cases/relation/delegation_test.rb b/activerecord/test/cases/relation/delegation_test.rb
index 49d4aeafc9..8cb7b82015 100644
--- a/activerecord/test/cases/relation/delegation_test.rb
+++ b/activerecord/test/cases/relation/delegation_test.rb
@@ -33,7 +33,7 @@ module ActiveRecord
:map, :none?, :one?, :partition, :reject, :reverse,
:sample, :second, :sort, :sort_by, :third,
:to_ary, :to_set, :to_xml, :to_yaml, :join,
- :in_groups, :in_groups_of, :to_sentence, :to_formatted_s
+ :in_groups, :in_groups_of, :to_sentence, :to_formatted_s, :as_json
]
ARRAY_DELEGATES.each do |method|
diff --git a/activerecord/test/cases/sanitize_test.rb b/activerecord/test/cases/sanitize_test.rb
index 23bcb0af1e..72f09186e2 100644
--- a/activerecord/test/cases/sanitize_test.rb
+++ b/activerecord/test/cases/sanitize_test.rb
@@ -152,11 +152,15 @@ class SanitizeTest < ActiveRecord::TestCase
end
def test_bind_record
- o = Struct.new(:quoted_id).new(1)
- assert_equal "1", bind("?", o)
+ o = Class.new {
+ def quoted_id
+ 1
+ end
+ }.new
+ assert_deprecated { assert_equal "1", bind("?", o) }
os = [o] * 3
- assert_equal "1,1,1", bind("?", os)
+ assert_deprecated { assert_equal "1,1,1", bind("?", os) }
end
def test_named_bind_with_postgresql_type_casts
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index 9584318e86..fccba4738f 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -422,11 +422,12 @@ class SchemaDumperDefaultsTest < ActiveRecord::TestCase
setup do
@connection = ActiveRecord::Base.connection
- @connection.create_table :defaults, force: true do |t|
+ @connection.create_table :dump_defaults, force: true do |t|
t.string :string_with_default, default: "Hello!"
t.date :date_with_default, default: "2014-06-05"
t.datetime :datetime_with_default, default: "2014-06-05 07:17:04"
t.time :time_with_default, default: "07:17:04"
+ t.decimal :decimal_with_default, default: "1234567890.0123456789", precision: 20, scale: 10
end
if current_adapter?(:PostgreSQLAdapter)
@@ -438,17 +439,17 @@ class SchemaDumperDefaultsTest < ActiveRecord::TestCase
end
teardown do
- return unless @connection
- @connection.drop_table "defaults", if_exists: true
+ @connection.drop_table "dump_defaults", if_exists: true
end
def test_schema_dump_defaults_with_universally_supported_types
- output = dump_table_schema("defaults")
+ output = dump_table_schema("dump_defaults")
assert_match %r{t\.string\s+"string_with_default",.*?default: "Hello!"}, output
- assert_match %r{t\.date\s+"date_with_default",\s+default: '2014-06-05'}, output
- assert_match %r{t\.datetime\s+"datetime_with_default",\s+default: '2014-06-05 07:17:04'}, output
- assert_match %r{t\.time\s+"time_with_default",\s+default: '2000-01-01 07:17:04'}, output
+ assert_match %r{t\.date\s+"date_with_default",\s+default: "2014-06-05"}, output
+ assert_match %r{t\.datetime\s+"datetime_with_default",\s+default: "2014-06-05 07:17:04"}, output
+ assert_match %r{t\.time\s+"time_with_default",\s+default: "2000-01-01 07:17:04"}, output
+ assert_match %r{t\.decimal\s+"decimal_with_default",\s+precision: 20,\s+scale: 10,\s+default: "1234567890.0123456789"}, output
end
def test_schema_dump_with_float_column_infinity_default
diff --git a/activerecord/test/cases/scoping/default_scoping_test.rb b/activerecord/test/cases/scoping/default_scoping_test.rb
index 3a04f4bf7d..14fb2fbbfa 100644
--- a/activerecord/test/cases/scoping/default_scoping_test.rb
+++ b/activerecord/test/cases/scoping/default_scoping_test.rb
@@ -10,6 +10,8 @@ require "concurrent/atomic/cyclic_barrier"
class DefaultScopingTest < ActiveRecord::TestCase
fixtures :developers, :posts, :comments
+ self.use_transactional_tests = false
+
def test_default_scope
expected = Developer.all.merge!(order: "salary DESC").to_a.collect(&:salary)
received = DeveloperOrderedBySalary.all.collect(&:salary)
diff --git a/activerecord/test/cases/scoping/named_scoping_test.rb b/activerecord/test/cases/scoping/named_scoping_test.rb
index 995ff4dfc5..d261fd5321 100644
--- a/activerecord/test/cases/scoping/named_scoping_test.rb
+++ b/activerecord/test/cases/scoping/named_scoping_test.rb
@@ -161,7 +161,7 @@ class NamedScopingTest < ActiveRecord::TestCase
end
def test_first_and_last_should_allow_integers_for_limit
- assert_equal Topic.base.first(2), Topic.base.to_a.first(2)
+ assert_equal Topic.base.first(2), Topic.base.order("id").to_a.first(2)
assert_equal Topic.base.last(2), Topic.base.order("id").to_a.last(2)
end
diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb
index 391bbe8877..eaa4dd09a9 100644
--- a/activerecord/test/cases/transaction_callbacks_test.rb
+++ b/activerecord/test/cases/transaction_callbacks_test.rb
@@ -551,3 +551,43 @@ class TransactionEnrollmentCallbacksTest < ActiveRecord::TestCase
assert_equal [:rollback], @topic.history
end
end
+
+class CallbacksOnActionAndConditionTest < ActiveRecord::TestCase
+ self.use_transactional_tests = false
+
+ class TopicWithCallbacksOnActionAndCondition < ActiveRecord::Base
+ self.table_name = :topics
+
+ after_commit(on: [:create, :update], if: :run_callback?) { |record| record.history << :create_or_update }
+
+ def clear_history
+ @history = []
+ end
+
+ def history
+ @history ||= []
+ end
+
+ def run_callback?
+ self.history << :run_callback?
+ true
+ end
+
+ attr_accessor :save_before_commit_history, :update_title
+ end
+
+ def test_callback_on_action_with_condition
+ topic = TopicWithCallbacksOnActionAndCondition.new
+ topic.save
+ assert_equal [:run_callback?, :create_or_update], topic.history
+
+ topic.clear_history
+ topic.approved = true
+ topic.save
+ assert_equal [:run_callback?, :create_or_update], topic.history
+
+ topic.clear_history
+ topic.destroy
+ assert_equal [], topic.history
+ end
+end
diff --git a/activerecord/test/cases/validations/uniqueness_validation_test.rb b/activerecord/test/cases/validations/uniqueness_validation_test.rb
index 277280b42e..28605d2f8e 100644
--- a/activerecord/test/cases/validations/uniqueness_validation_test.rb
+++ b/activerecord/test/cases/validations/uniqueness_validation_test.rb
@@ -385,7 +385,7 @@ class UniquenessValidationTest < ActiveRecord::TestCase
def test_validate_uniqueness_with_limit_and_utf8
if current_adapter?(:SQLite3Adapter)
- # Event.title has limit 5, but does SQLite doesn't truncate.
+ # Event.title has limit 5, but SQLite doesn't truncate.
e1 = Event.create(title: "一二三四五六七八")
assert e1.valid?, "Could not create an event with a unique 8 characters title"
diff --git a/activerecord/test/schema/mysql2_specific_schema.rb b/activerecord/test/schema/mysql2_specific_schema.rb
index 9a203a7293..90a314c83c 100644
--- a/activerecord/test/schema/mysql2_specific_schema.rb
+++ b/activerecord/test/schema/mysql2_specific_schema.rb
@@ -6,6 +6,11 @@ ActiveRecord::Schema.define do
end
end
+ create_table :timestamp_defaults, force: true do |t|
+ t.timestamp :nullable_timestamp
+ t.timestamp :modified_timestamp, default: -> { "CURRENT_TIMESTAMP" }
+ end
+
create_table :binary_fields, force: true do |t|
t.binary :var_binary, limit: 255
t.binary :var_binary_large, limit: 4095
diff --git a/activerecord/test/support/connection.rb b/activerecord/test/support/connection.rb
index bc5af36a28..1a609e13c3 100644
--- a/activerecord/test/support/connection.rb
+++ b/activerecord/test/support/connection.rb
@@ -10,7 +10,10 @@ module ARTest
end
def self.connection_config
- config["connections"][connection_name]
+ config.fetch("connections").fetch(connection_name) do
+ puts "Connection #{connection_name.inspect} not found. Available connections: #{config['connections'].keys.join(', ')}"
+ exit 1
+ end
end
def self.connect