aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/lib/active_record/associations/alias_tracker.rb21
-rw-r--r--activerecord/lib/active_record/associations/association_scope.rb3
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb6
-rw-r--r--activerecord/lib/active_record/associations/join_dependency.rb11
-rw-r--r--activerecord/lib/active_record/associations/join_dependency/join_association.rb17
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/connection_specification.rb18
-rw-r--r--activerecord/lib/active_record/migration/compatibility.rb49
-rw-r--r--activerecord/lib/active_record/relation.rb5
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb5
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb35
-rw-r--r--activerecord/lib/active_record/relation/merger.rb2
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb24
-rw-r--r--activerecord/test/cases/adapters/sqlite3/json_test.rb29
-rw-r--r--activerecord/test/cases/associations/has_many_through_associations_test.rb4
-rw-r--r--activerecord/test/cases/connection_specification/resolver_test.rb2
-rw-r--r--activerecord/test/cases/finder_test.rb34
-rw-r--r--activerecord/test/cases/json_shared_test_cases.rb2
-rw-r--r--activerecord/test/cases/relations_test.rb26
-rw-r--r--activerecord/test/models/author.rb1
21 files changed, 176 insertions, 121 deletions
diff --git a/activerecord/lib/active_record/associations/alias_tracker.rb b/activerecord/lib/active_record/associations/alias_tracker.rb
index 096f016976..a8d8ee268a 100644
--- a/activerecord/lib/active_record/associations/alias_tracker.rb
+++ b/activerecord/lib/active_record/associations/alias_tracker.rb
@@ -6,22 +6,16 @@ module ActiveRecord
module Associations
# Keeps track of table aliases for ActiveRecord::Associations::JoinDependency
class AliasTracker # :nodoc:
- def self.create(connection, initial_table)
- aliases = Hash.new(0)
- aliases[initial_table] = 1
- new(connection, aliases)
- end
-
- def self.create_with_joins(connection, initial_table, joins)
+ def self.create(connection, initial_table, joins)
if joins.empty?
- create(connection, initial_table)
+ aliases = Hash.new(0)
else
aliases = Hash.new { |h, k|
h[k] = initial_count_for(connection, k, joins)
}
- aliases[initial_table] = 1
- new(connection, aliases)
end
+ aliases[initial_table] = 1
+ new(connection, aliases)
end
def self.initial_count_for(connection, name, table_joins)
@@ -36,6 +30,8 @@ module ActiveRecord
).size
elsif join.respond_to? :left
join.left.table_name == name ? 1 : 0
+ elsif join.is_a?(Hash)
+ join[name]
else
# this branch is reached by two tests:
#
@@ -79,10 +75,7 @@ module ActiveRecord
end
end
- # TODO Change this to private once we've dropped Ruby 2.2 support.
- # Workaround for Ruby 2.2 "private attribute?" warning.
- protected
- attr_reader :aliases
+ attr_reader :aliases
private
diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb
index 6118cef913..11967e0571 100644
--- a/activerecord/lib/active_record/associations/association_scope.rb
+++ b/activerecord/lib/active_record/associations/association_scope.rb
@@ -23,8 +23,7 @@ module ActiveRecord
reflection = association.reflection
scope = klass.unscoped
owner = association.owner
- alias_tracker = AliasTracker.create(klass.connection, scope.table.name)
- chain = get_chain(reflection, association, alias_tracker)
+ chain = get_chain(reflection, association, scope.alias_tracker)
scope.extending! reflection.extensions
add_constraints(scope, owner, chain)
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index ceedf150e3..ed215fb22c 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -181,8 +181,6 @@ module ActiveRecord
# are actually removed from the database, that depends precisely on
# +delete_records+. They are in any case removed from the collection.
def delete(*records)
- return if records.empty?
- records = find(records) if records.any? { |record| record.kind_of?(Integer) || record.kind_of?(String) }
delete_or_destroy(records, options[:dependent])
end
@@ -192,8 +190,6 @@ module ActiveRecord
# Note that this method removes records from the database ignoring the
# +:dependent+ option.
def destroy(*records)
- return if records.empty?
- records = find(records) if records.any? { |record| record.kind_of?(Integer) || record.kind_of?(String) }
delete_or_destroy(records, :destroy)
end
@@ -376,6 +372,8 @@ module ActiveRecord
end
def delete_or_destroy(records, method)
+ return if records.empty?
+ records = find(records) if records.any? { |record| record.kind_of?(Integer) || record.kind_of?(String) }
records = records.flatten
records.each { |record| raise_on_type_mismatch!(record) }
existing_records = records.reject(&:new_record?)
diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb
index 23741b2f6a..df4bf07999 100644
--- a/activerecord/lib/active_record/associations/join_dependency.rb
+++ b/activerecord/lib/active_record/associations/join_dependency.rb
@@ -43,8 +43,6 @@ module ActiveRecord
Column = Struct.new(:name, :alias)
end
- attr_reader :alias_tracker, :base_klass, :join_root
-
def self.make_tree(associations)
hash = {}
walk_tree associations, hash
@@ -90,8 +88,8 @@ module ActiveRecord
# associations # => [:appointments]
# joins # => []
#
- def initialize(base, table, associations, joins, eager_loading: true)
- @alias_tracker = AliasTracker.create_with_joins(base.connection, table.name, joins)
+ def initialize(base, table, associations, alias_tracker, eager_loading: true)
+ @alias_tracker = alias_tracker
@eager_loading = eager_loading
tree = self.class.make_tree associations
@join_root = JoinBase.new(base, table, build(tree, base))
@@ -158,6 +156,9 @@ module ActiveRecord
parents.values
end
+ protected
+ attr_reader :alias_tracker, :base_klass, :join_root
+
private
def make_constraints(parent, child, tables, join_type)
@@ -224,7 +225,7 @@ module ActiveRecord
raise EagerLoadPolymorphicError.new(reflection)
end
- JoinAssociation.new reflection, build(right, reflection.klass)
+ JoinAssociation.new(reflection, build(right, reflection.klass), alias_tracker)
end.compact
end
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 a526468bf6..a007d0cf5f 100644
--- a/activerecord/lib/active_record/associations/join_dependency/join_association.rb
+++ b/activerecord/lib/active_record/associations/join_dependency/join_association.rb
@@ -11,11 +11,12 @@ module ActiveRecord
attr_accessor :tables
- def initialize(reflection, children)
+ def initialize(reflection, children, alias_tracker)
super(reflection.klass, children)
- @reflection = reflection
- @tables = nil
+ @alias_tracker = alias_tracker
+ @reflection = reflection
+ @tables = nil
end
def match?(other)
@@ -38,11 +39,12 @@ module ActiveRecord
joins << table.create_join(table, table.create_on(constraint), join_type)
join_scope = reflection.join_scope(table, foreign_klass)
+ arel = join_scope.arel(alias_tracker.aliases)
- if join_scope.arel.constraints.any?
- joins.concat join_scope.arel.join_sources
+ if arel.constraints.any?
+ joins.concat arel.join_sources
right = joins.last.right
- right.expr = right.expr.and(join_scope.arel.constraints)
+ right.expr = right.expr.and(arel.constraints)
end
# The current table in this iteration becomes the foreign table in the next
@@ -55,6 +57,9 @@ module ActiveRecord
def table
tables.first
end
+
+ protected
+ attr_reader :alias_tracker
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index 8c889f98f5..6859feb2f3 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -478,6 +478,8 @@ module ActiveRecord
m.alias_type %r(number)i, "decimal"
m.alias_type %r(double)i, "float"
+ m.register_type %r(^json)i, Type::Json.new
+
m.register_type(%r(decimal)i) do |sql_type|
scale = extract_scale(sql_type)
precision = extract_precision(sql_type)
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 ae991d3d79..add6f8632b 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -563,7 +563,6 @@ module ActiveRecord
m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1)
m.register_type %r(^float)i, Type::Float.new(limit: 24)
m.register_type %r(^double)i, Type::Float.new(limit: 53)
- m.register_type %r(^json)i, Type::Json.new
register_integer_type m, %r(^bigint)i, limit: 8
register_integer_type m, %r(^int)i, limit: 4
diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb
index 29542f917e..508132accb 100644
--- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb
+++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb
@@ -183,13 +183,25 @@ module ActiveRecord
raise(AdapterNotSpecified, "database configuration does not specify adapter") unless spec.key?(:adapter)
+ # Require the adapter itself and give useful feedback about
+ # 1. Missing adapter gems and
+ # 2. Adapter gems' missing dependencies.
path_to_adapter = "active_record/connection_adapters/#{spec[:adapter]}_adapter"
begin
require path_to_adapter
- rescue Gem::LoadError => e
- raise Gem::LoadError, "Specified '#{spec[:adapter]}' for database adapter, but the gem is not loaded. Add `gem '#{e.name}'` to your Gemfile (and ensure its version is at the minimum required by ActiveRecord)."
rescue LoadError => e
- raise LoadError, "Could not load '#{path_to_adapter}'. Make sure that the adapter in config/database.yml is valid. If you use an adapter other than 'mysql2', 'postgresql' or 'sqlite3' add the necessary adapter gem to the Gemfile.", e.backtrace
+ # We couldn't require the adapter itself. Raise an exception that
+ # points out config typos and missing gems.
+ if e.path == path_to_adapter
+ # We can assume that a non-builtin adapter was specified, so it's
+ # either misspelled or missing from Gemfile.
+ raise e.class, "Could not load the '#{spec[:adapter]}' Active Record adapter. Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary adapter gem to your Gemfile.", e.backtrace
+
+ # Bubbled up from the adapter require. Prefix the exception message
+ # with some guidance about how to address it and reraise.
+ else
+ raise e.class, "Error loading the '#{spec[:adapter]}' Active Record adapter. Missing a gem it depends on? #{e.message}", e.backtrace
+ end
end
adapter_method = "#{spec[:adapter]}_connection"
diff --git a/activerecord/lib/active_record/migration/compatibility.rb b/activerecord/lib/active_record/migration/compatibility.rb
index 502cef2e20..2b247f7a7a 100644
--- a/activerecord/lib/active_record/migration/compatibility.rb
+++ b/activerecord/lib/active_record/migration/compatibility.rb
@@ -52,11 +52,8 @@ module ActiveRecord
end
if block_given?
- super(table_name, options) do |t|
- class << t
- prepend TableDefinition
- end
- yield t
+ super do |t|
+ yield compatible_table_definition(t)
end
else
super
@@ -65,11 +62,8 @@ module ActiveRecord
def change_table(table_name, options = {})
if block_given?
- super(table_name, options) do |t|
- class << t
- prepend TableDefinition
- end
- yield t
+ super do |t|
+ yield compatible_table_definition(t)
end
else
super
@@ -80,11 +74,8 @@ module ActiveRecord
column_options.reverse_merge!(type: :integer)
if block_given?
- super(table_1, table_2, column_options: column_options, **options) do |t|
- class << t
- prepend TableDefinition
- end
- yield t
+ super do |t|
+ yield compatible_table_definition(t)
end
else
super
@@ -103,6 +94,14 @@ module ActiveRecord
super(table_name, ref_name, type: :integer, **options)
end
alias :add_belongs_to :add_reference
+
+ private
+ def compatible_table_definition(t)
+ class << t
+ prepend TableDefinition
+ end
+ t
+ end
end
class V4_2 < V5_0
@@ -121,11 +120,8 @@ module ActiveRecord
def create_table(table_name, options = {})
if block_given?
- super(table_name, options) do |t|
- class << t
- prepend TableDefinition
- end
- yield t
+ super do |t|
+ yield compatible_table_definition(t)
end
else
super
@@ -134,11 +130,8 @@ module ActiveRecord
def change_table(table_name, options = {})
if block_given?
- super(table_name, options) do |t|
- class << t
- prepend TableDefinition
- end
- yield t
+ super do |t|
+ yield compatible_table_definition(t)
end
else
super
@@ -174,6 +167,12 @@ module ActiveRecord
end
private
+ def compatible_table_definition(t)
+ class << t
+ prepend TableDefinition
+ end
+ t
+ end
def index_name_for_remove(table_name, options = {})
index_name = index_name(table_name, options)
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 3517091a6e..997cfe4b5e 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -551,6 +551,11 @@ module ActiveRecord
limit_value || offset_value
end
+ def alias_tracker(joins = [], aliases = nil) # :nodoc:
+ joins += [aliases] if aliases
+ ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins)
+ end
+
protected
def load_records(records)
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index 0889d61c92..4ef0502893 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -130,7 +130,7 @@ module ActiveRecord
# end
def calculate(operation, column_name)
if has_include?(column_name)
- relation = construct_relation_for_association_calculations
+ relation = apply_join_dependency(construct_join_dependency)
relation.distinct! if operation.to_s.downcase == "count"
relation.calculate(operation, column_name)
@@ -180,7 +180,8 @@ module ActiveRecord
end
if has_include?(column_names.first)
- construct_relation_for_association_calculations.pluck(*column_names)
+ relation = apply_join_dependency(construct_join_dependency)
+ relation.pluck(*column_names)
else
relation = spawn
relation.select_values = column_names.map { |cn|
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index c92d5a52f4..707245bab2 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -310,12 +310,12 @@ module ActiveRecord
return false if !conditions || limit_value == 0
- relation = self unless eager_loading?
- relation ||= apply_join_dependency(self, construct_join_dependency(eager_loading: false))
-
- return false if ActiveRecord::NullRelation === relation
+ if eager_loading?
+ relation = apply_join_dependency(construct_join_dependency(eager_loading: false))
+ return relation.exists?(conditions)
+ end
- relation = construct_relation_for_exists(relation, conditions)
+ relation = construct_relation_for_exists(conditions)
skip_query_cache_if_necessary { connection.select_value(relation.arel, "#{name} Exists") } ? true : false
rescue ::RangeError
@@ -366,17 +366,16 @@ module ActiveRecord
# preexisting join in joins_values to categorizations (by way of
# the `has_many :through` for categories).
#
- join_dependency = construct_join_dependency(joins_values)
+ join_dependency = construct_join_dependency
- aliases = join_dependency.aliases
- relation = select aliases.columns
- relation = apply_join_dependency(relation, join_dependency)
+ relation = apply_join_dependency(join_dependency)
+ relation._select!(join_dependency.aliases.columns)
yield relation, join_dependency
end
- def construct_relation_for_exists(relation, conditions)
- relation = relation.except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
+ def construct_relation_for_exists(conditions)
+ relation = except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
case conditions
when Array, Hash
@@ -388,17 +387,15 @@ module ActiveRecord
relation
end
- def construct_join_dependency(joins = [], eager_loading: true)
+ def construct_join_dependency(eager_loading: true)
including = eager_load_values + includes_values
- ActiveRecord::Associations::JoinDependency.new(klass, table, including, joins, eager_loading: eager_loading)
- end
-
- def construct_relation_for_association_calculations
- apply_join_dependency(self, construct_join_dependency(joins_values))
+ ActiveRecord::Associations::JoinDependency.new(
+ klass, table, including, alias_tracker(joins_values), eager_loading: eager_loading
+ )
end
- def apply_join_dependency(relation, join_dependency)
- relation = relation.except(:includes, :eager_load, :preload).joins!(join_dependency)
+ def apply_join_dependency(join_dependency)
+ relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
if using_limitable_reflections?(join_dependency.reflections)
relation
diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb
index 03824ffff9..ebc72d28fd 100644
--- a/activerecord/lib/active_record/relation/merger.rb
+++ b/activerecord/lib/active_record/relation/merger.rb
@@ -122,7 +122,7 @@ module ActiveRecord
end
join_dependency = ActiveRecord::Associations::JoinDependency.new(
- other.klass, other.table, joins_dependency, []
+ other.klass, other.table, joins_dependency, other.alias_tracker
)
relation.joins! rest
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index c88603fde2..578d8a6eb7 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -441,7 +441,7 @@ module ActiveRecord
# => SELECT "users".* FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
#
def left_outer_joins(*args)
- check_if_method_has_arguments!(:left_outer_joins, args)
+ check_if_method_has_arguments!(__callee__, args)
args.compact!
args.flatten!
@@ -898,8 +898,8 @@ module ActiveRecord
end
# Returns the Arel object associated with the relation.
- def arel # :nodoc:
- @arel ||= build_arel
+ def arel(aliases = nil) # :nodoc:
+ @arel ||= build_arel(aliases)
end
protected
@@ -921,11 +921,11 @@ module ActiveRecord
raise ImmutableRelation if defined?(@arel) && @arel
end
- def build_arel
+ def build_arel(aliases)
arel = Arel::SelectManager.new(table)
- build_joins(arel, joins_values.flatten) unless joins_values.empty?
- build_left_outer_joins(arel, left_outer_joins_values.flatten) unless left_outer_joins_values.empty?
+ build_joins(arel, joins_values.flatten, aliases) unless joins_values.empty?
+ build_left_outer_joins(arel, left_outer_joins_values.flatten, aliases) unless left_outer_joins_values.empty?
arel.where(where_clause.ast) unless where_clause.empty?
arel.having(having_clause.ast) unless having_clause.empty?
@@ -970,7 +970,7 @@ module ActiveRecord
end
end
- def build_left_outer_joins(manager, outer_joins)
+ def build_left_outer_joins(manager, outer_joins, aliases)
buckets = outer_joins.group_by do |join|
case join
when Hash, Symbol, Array
@@ -980,10 +980,10 @@ module ActiveRecord
end
end
- build_join_query(manager, buckets, Arel::Nodes::OuterJoin)
+ build_join_query(manager, buckets, Arel::Nodes::OuterJoin, aliases)
end
- def build_joins(manager, joins)
+ def build_joins(manager, joins, aliases)
buckets = joins.group_by do |join|
case join
when String
@@ -999,10 +999,10 @@ module ActiveRecord
end
end
- build_join_query(manager, buckets, Arel::Nodes::InnerJoin)
+ build_join_query(manager, buckets, Arel::Nodes::InnerJoin, aliases)
end
- def build_join_query(manager, buckets, join_type)
+ def build_join_query(manager, buckets, join_type, aliases)
buckets.default = []
association_joins = buckets[:association_join]
@@ -1013,7 +1013,7 @@ module ActiveRecord
join_list = join_nodes + convert_join_strings_to_ast(manager, string_joins)
join_dependency = ActiveRecord::Associations::JoinDependency.new(
- klass, table, association_joins, join_list
+ klass, table, association_joins, alias_tracker(join_list, aliases)
)
joins = join_dependency.join_constraints(stashed_association_joins, join_type)
diff --git a/activerecord/test/cases/adapters/sqlite3/json_test.rb b/activerecord/test/cases/adapters/sqlite3/json_test.rb
new file mode 100644
index 0000000000..568a524058
--- /dev/null
+++ b/activerecord/test/cases/adapters/sqlite3/json_test.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require "cases/helper"
+require "cases/json_shared_test_cases"
+
+class SQLite3JSONTest < ActiveRecord::SQLite3TestCase
+ include JSONSharedTestCases
+
+ def setup
+ super
+ @connection.create_table("json_data_type") do |t|
+ t.column "payload", :json, default: {}
+ t.column "settings", :json
+ end
+ end
+
+ def test_default
+ @connection.add_column "json_data_type", "permissions", column_type, default: { "users": "read", "posts": ["read", "write"] }
+ klass.reset_column_information
+
+ assert_equal({ "users" => "read", "posts" => ["read", "write"] }, klass.column_defaults["permissions"])
+ assert_equal({ "users" => "read", "posts" => ["read", "write"] }, klass.new.permissions)
+ end
+
+ private
+ def column_type
+ :json
+ end
+end
diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb
index 521b388cee..c6a4ac356f 100644
--- a/activerecord/test/cases/associations/has_many_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb
@@ -1250,6 +1250,10 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
TenantMembership.current_member = nil
end
+ def test_has_many_trough_with_scope_that_has_joined_same_table_with_parent_relation
+ assert_equal authors(:david), Author.joins(:comments_for_first_author).take
+ end
+
def test_has_many_through_with_unscope_should_affect_to_through_scope
assert_equal [comments(:eager_other_comment1)], authors(:mary).unordered_comments
end
diff --git a/activerecord/test/cases/connection_specification/resolver_test.rb b/activerecord/test/cases/connection_specification/resolver_test.rb
index 3fa0ca8366..5b80f16a44 100644
--- a/activerecord/test/cases/connection_specification/resolver_test.rb
+++ b/activerecord/test/cases/connection_specification/resolver_test.rb
@@ -19,7 +19,7 @@ module ActiveRecord
spec "ridiculous://foo?encoding=utf8"
end
- assert_match "Could not load 'active_record/connection_adapters/ridiculous_adapter'", error.message
+ assert_match "Could not load the 'ridiculous' Active Record adapter. Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary adapter gem to your Gemfile.", error.message
end
# The abstract adapter is used simply to bypass the bit of code that
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index 55496147c1..d8bc917e7f 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -9,6 +9,7 @@ require "models/company"
require "models/tagging"
require "models/topic"
require "models/reply"
+require "models/rating"
require "models/entrant"
require "models/project"
require "models/developer"
@@ -156,6 +157,32 @@ class FinderTest < ActiveRecord::TestCase
assert_raise(NoMethodError) { Topic.exists?([1, 2]) }
end
+ def test_exists_with_scope
+ davids = Author.where(name: "David")
+ assert_equal true, davids.exists?
+ assert_equal true, davids.exists?(authors(:david).id)
+ assert_equal false, davids.exists?(authors(:mary).id)
+ assert_equal false, davids.exists?("42")
+ assert_equal false, davids.exists?(42)
+ assert_equal false, davids.exists?(davids.new.id)
+
+ fake = Author.where(name: "fake author")
+ assert_equal false, fake.exists?
+ assert_equal false, fake.exists?(authors(:david).id)
+ end
+
+ def test_exists_uses_existing_scope
+ post = authors(:david).posts.first
+ authors = Author.includes(:posts).where(name: "David", posts: { id: post.id })
+ assert_equal true, authors.exists?(authors(:david).id)
+ end
+
+ def test_any_with_scope_on_hash_includes
+ post = authors(:david).posts.first
+ categories = Categorization.includes(author: :posts).where(posts: { id: post.id })
+ assert_equal true, categories.exists?
+ end
+
def test_exists_with_polymorphic_relation
post = Post.create!(title: "Post", body: "default", taggings: [Tagging.new(comment: "tagging comment")])
relation = Post.tagged_with_comment("tagging comment")
@@ -244,6 +271,13 @@ class FinderTest < ActiveRecord::TestCase
assert_equal true, author.unique_categorized_posts.includes(:special_comments).order("comments.tags_count DESC").limit(1).exists?
end
+ def test_exists_should_reference_correct_aliases_while_joining_tables_of_has_many_through_association
+ assert_nothing_raised do
+ developer = developers(:david)
+ developer.ratings.includes(comment: :post).where(posts: { id: 1 }).exists?
+ end
+ end
+
def test_exists_with_empty_table_and_no_args_given
Topic.delete_all
assert_equal false, Topic.exists?
diff --git a/activerecord/test/cases/json_shared_test_cases.rb b/activerecord/test/cases/json_shared_test_cases.rb
index 56ec8c8a82..a71485982c 100644
--- a/activerecord/test/cases/json_shared_test_cases.rb
+++ b/activerecord/test/cases/json_shared_test_cases.rb
@@ -30,6 +30,7 @@ module JSONSharedTestCases
end
def test_change_table_supports_json
+ skip unless @connection.supports_json?
@connection.change_table("json_data_type") do |t|
t.public_send column_type, "users"
end
@@ -40,6 +41,7 @@ module JSONSharedTestCases
end
def test_schema_dumping
+ skip unless @connection.supports_json?
output = dump_table_schema("json_data_type")
assert_match(/t\.#{column_type}\s+"settings"/, output)
end
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index e1788be351..72433d1e8e 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -845,32 +845,6 @@ class RelationTest < ActiveRecord::TestCase
}
end
- def test_exists
- davids = Author.where(name: "David")
- assert davids.exists?
- assert davids.exists?(authors(:david).id)
- assert ! davids.exists?(authors(:mary).id)
- assert ! davids.exists?("42")
- assert ! davids.exists?(42)
- assert ! davids.exists?(davids.new.id)
-
- fake = Author.where(name: "fake author")
- assert ! fake.exists?
- assert ! fake.exists?(authors(:david).id)
- end
-
- def test_exists_uses_existing_scope
- post = authors(:david).posts.first
- authors = Author.includes(:posts).where(name: "David", posts: { id: post.id })
- assert authors.exists?(authors(:david).id)
- end
-
- def test_any_with_scope_on_hash_includes
- post = authors(:david).posts.first
- categories = Categorization.includes(author: :posts).where(posts: { id: post.id })
- assert categories.exists?
- end
-
def test_last
authors = Author.all
assert_equal authors(:bob), authors.last
diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb
index 3371fcbfcc..e9eba9be2e 100644
--- a/activerecord/test/models/author.rb
+++ b/activerecord/test/models/author.rb
@@ -22,6 +22,7 @@ class Author < ActiveRecord::Base
has_many :comments_containing_the_letter_e, through: :posts, source: :comments
has_many :comments_with_order_and_conditions, -> { order("comments.body").where("comments.body like 'Thank%'") }, through: :posts, source: :comments
has_many :comments_with_include, -> { includes(:post).where(posts: { type: "Post" }) }, through: :posts, source: :comments
+ has_many :comments_for_first_author, -> { for_first_author }, through: :posts, source: :comments
has_many :first_posts
has_many :comments_on_first_posts, -> { order("posts.id desc, comments.id asc") }, through: :first_posts, source: :comments