aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/lib/active_record.rb3
-rw-r--r--activerecord/lib/active_record/associations/join_dependency.rb2
-rw-r--r--activerecord/lib/active_record/associations/join_dependency/join_association.rb8
-rw-r--r--activerecord/lib/active_record/attribute_methods/serialization.rb2
-rw-r--r--activerecord/lib/active_record/coders/yaml_column.rb5
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb10
-rw-r--r--activerecord/lib/active_record/migration.rb2
-rw-r--r--activerecord/lib/active_record/persistence.rb2
-rw-r--r--activerecord/lib/active_record/reflection.rb72
-rw-r--r--activerecord/lib/active_record/store.rb6
-rw-r--r--activerecord/test/cases/associations/eager_test.rb15
-rw-r--r--activerecord/test/cases/coders/yaml_column_test.rb24
-rw-r--r--activerecord/test/cases/migration/compatibility_test.rb5
-rw-r--r--activerecord/test/cases/migrator_test.rb3
-rw-r--r--activerecord/test/cases/reflection_test.rb20
-rw-r--r--activerecord/test/cases/serialized_attribute_test.rb14
16 files changed, 105 insertions, 88 deletions
diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb
index 250f48fad9..96b8545dfc 100644
--- a/activerecord/lib/active_record.rb
+++ b/activerecord/lib/active_record.rb
@@ -44,7 +44,6 @@ module ActiveRecord
autoload :Explain
autoload :Inheritance
autoload :Integration
- autoload :LegacyYamlAdapter
autoload :Migration
autoload :Migrator, "active_record/migration"
autoload :ModelSchema
@@ -85,6 +84,8 @@ module ActiveRecord
autoload :AttributeMethods
autoload :AutosaveAssociation
+ autoload :LegacyYamlAdapter
+
autoload :Relation
autoload :AssociationRelation
autoload :NullRelation
diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb
index a79eb03acc..87e0847ec1 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, child.reflection.scope_chain, chain)
+ child.join_constraints(foreign_table, foreign_klass, child, 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 a5705951f3..f5fcba1236 100644
--- a/activerecord/lib/active_record/associations/join_dependency/join_association.rb
+++ b/activerecord/lib/active_record/associations/join_dependency/join_association.rb
@@ -23,14 +23,11 @@ module ActiveRecord
JoinInformation = Struct.new :joins, :binds
- def join_constraints(foreign_table, foreign_klass, node, join_type, tables, scope_chain, chain)
+ def join_constraints(foreign_table, foreign_klass, node, join_type, tables, chain)
joins = []
binds = []
tables = tables.reverse
- scope_chain_index = 0
- scope_chain = scope_chain.reverse
-
# The chain starts with the target table, but we want to end with it here (makes
# more sense in this context), so we reverse
chain.reverse_each do |reflection|
@@ -44,7 +41,7 @@ module ActiveRecord
constraint = build_constraint(klass, table, key, foreign_table, foreign_key)
predicate_builder = PredicateBuilder.new(TableMetadata.new(klass, table))
- scope_chain_items = scope_chain[scope_chain_index].map do |item|
+ scope_chain_items = reflection.scopes.map do |item|
if item.is_a?(Relation)
item
else
@@ -52,7 +49,6 @@ module ActiveRecord
.instance_exec(node, &item)
end
end
- scope_chain_index += 1
klass_scope =
if klass.current_scope
diff --git a/activerecord/lib/active_record/attribute_methods/serialization.rb b/activerecord/lib/active_record/attribute_methods/serialization.rb
index 945192fe04..4d9aff76cc 100644
--- a/activerecord/lib/active_record/attribute_methods/serialization.rb
+++ b/activerecord/lib/active_record/attribute_methods/serialization.rb
@@ -54,7 +54,7 @@ module ActiveRecord
elsif [:load, :dump].all? { |x| class_name_or_coder.respond_to?(x) }
class_name_or_coder
else
- Coders::YAMLColumn.new(class_name_or_coder)
+ Coders::YAMLColumn.new(attr_name, class_name_or_coder)
end
decorate_attribute_type(attr_name, :serialize) do |type|
diff --git a/activerecord/lib/active_record/coders/yaml_column.rb b/activerecord/lib/active_record/coders/yaml_column.rb
index 4b06987f08..2136da43fe 100644
--- a/activerecord/lib/active_record/coders/yaml_column.rb
+++ b/activerecord/lib/active_record/coders/yaml_column.rb
@@ -5,7 +5,8 @@ module ActiveRecord
class YAMLColumn # :nodoc:
attr_accessor :object_class
- def initialize(object_class = Object)
+ def initialize(attr_name, object_class = Object)
+ @attr_name = attr_name
@object_class = object_class
check_arity_of_constructor
end
@@ -31,7 +32,7 @@ module ActiveRecord
def assert_valid_value(obj)
unless obj.nil? || obj.is_a?(object_class)
raise SerializationTypeMismatch,
- "Attribute was supposed to be a #{object_class}, but was a #{obj.class}. -- #{obj.inspect}"
+ "Attribute `#{@attr_name}` was supposed to be a #{object_class}, but was a #{obj.class}. -- #{obj.inspect}"
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 0ebd907cc0..315d70c33f 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -759,11 +759,11 @@ module ActiveRecord
query(<<-end_sql, "SCHEMA")
SELECT a.attname, format_type(a.atttypid, a.atttypmod),
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
- (SELECT c.collname FROM pg_collation c, pg_type t
- WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation),
- col_description(a.attrelid, a.attnum) AS comment
- FROM pg_attribute a LEFT JOIN pg_attrdef d
- ON a.attrelid = d.adrelid AND a.attnum = d.adnum
+ c.collname, col_description(a.attrelid, a.attnum) AS comment
+ FROM pg_attribute a
+ LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
+ LEFT JOIN pg_type t ON a.atttypid = t.oid
+ LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
WHERE a.attrelid = #{quote(quote_table_name(table_name))}::regclass
AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY a.attnum
diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb
index 339332a60d..40f6226315 100644
--- a/activerecord/lib/active_record/migration.rb
+++ b/activerecord/lib/active_record/migration.rb
@@ -525,7 +525,7 @@ module ActiveRecord
raise StandardError, "Directly inheriting from ActiveRecord::Migration is not supported. " \
"Please specify the Rails release the migration was written for:\n" \
"\n" \
- " class #{self.class.name} < ActiveRecord::Migration[4.2]"
+ " class #{subclass} < ActiveRecord::Migration[4.2]"
end
end
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index 4cd867faae..7ceb7d1a55 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -148,6 +148,8 @@ module ActiveRecord
#
# Attributes marked as readonly are silently ignored if the record is
# being updated.
+ #
+ # Unless an error is raised, returns true.
def save!(*args)
create_or_update(*args) || raise(RecordNotSaved.new("Failed to save the record", self))
end
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 2c8c4b6297..81ec4924b0 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -1,5 +1,6 @@
require "thread"
require "active_support/core_ext/string/filters"
+require "active_support/deprecation"
module ActiveRecord
# = Active Record Reflection
@@ -175,8 +176,19 @@ module ActiveRecord
JoinKeys.new(foreign_key, active_record_primary_key)
end
+ # Returns a list of scopes that should be applied for this Reflection
+ # object when querying the database.
+ def scopes
+ scope ? [scope] : []
+ end
+
+ def scope_chain
+ chain.map(&:scopes)
+ end
+ deprecate :scope_chain
+
def constraints
- scope_chain.flatten
+ chain.map(&:scopes).flatten
end
def counter_cache_column
@@ -461,12 +473,6 @@ module ActiveRecord
false
end
- # An array of arrays of scopes. Each item in the outside array corresponds to a reflection
- # in the #chain.
- def scope_chain
- scope ? [[scope]] : [[]]
- end
-
def has_scope?
scope
end
@@ -796,45 +802,12 @@ module ActiveRecord
through_reflection.clear_association_scope_cache
end
- # Consider the following example:
- #
- # class Person
- # has_many :articles
- # has_many :comment_tags, through: :articles
- # end
- #
- # class Article
- # has_many :comments
- # has_many :comment_tags, through: :comments, source: :tags
- # end
- #
- # class Comment
- # has_many :tags
- # end
- #
- # There may be scopes on Person.comment_tags, Article.comment_tags and/or Comment.tags,
- # but only Comment.tags will be represented in the #chain. So this method creates an array
- # of scopes corresponding to the chain.
- def scope_chain
- @scope_chain ||= begin
- scope_chain = source_reflection.scope_chain.map(&:dup)
-
- # Add to it the scope from this reflection (if any)
- scope_chain.first << scope if scope
-
- through_scope_chain = through_reflection.scope_chain.map(&:dup)
-
- if options[:source_type]
- type = foreign_type
- source_type = options[:source_type]
- through_scope_chain.first << lambda { |object|
- where(type => source_type)
- }
- end
+ def scopes
+ source_reflection.scopes + super
+ end
- # Recursively fill out the rest of the array from the through reflection
- scope_chain + through_scope_chain
- end
+ def source_type_scope
+ through_reflection.klass.where(foreign_type => options[:source_type])
end
def has_scope?
@@ -1008,6 +981,15 @@ module ActiveRecord
@previous_reflection = previous_reflection
end
+ def scopes
+ scopes = @previous_reflection.scopes
+ if @previous_reflection.options[:source_type]
+ scopes + [@previous_reflection.source_type_scope]
+ else
+ scopes
+ end
+ end
+
def klass
@reflection.klass
end
diff --git a/activerecord/lib/active_record/store.rb b/activerecord/lib/active_record/store.rb
index d4be20d999..006afe7495 100644
--- a/activerecord/lib/active_record/store.rb
+++ b/activerecord/lib/active_record/store.rb
@@ -78,7 +78,7 @@ module ActiveRecord
module ClassMethods
def store(store_attribute, options = {})
- serialize store_attribute, IndifferentCoder.new(options[:coder])
+ serialize store_attribute, IndifferentCoder.new(store_attribute, options[:coder])
store_accessor(store_attribute, options[:accessors]) if options.has_key? :accessors
end
@@ -177,12 +177,12 @@ module ActiveRecord
end
class IndifferentCoder # :nodoc:
- def initialize(coder_or_class_name)
+ def initialize(attr_name, coder_or_class_name)
@coder =
if coder_or_class_name.respond_to?(:load) && coder_or_class_name.respond_to?(:dump)
coder_or_class_name
else
- ActiveRecord::Coders::YAMLColumn.new(coder_or_class_name || Object)
+ ActiveRecord::Coders::YAMLColumn.new(attr_name, coder_or_class_name || Object)
end
end
diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb
index 7d054b874b..11f4aae5b3 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -739,18 +739,25 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
def test_eager_with_invalid_association_reference
- assert_raise(ActiveRecord::AssociationNotFoundError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
+ e = assert_raise(ActiveRecord::AssociationNotFoundError) {
Post.all.merge!(includes: :monkeys).find(6)
}
- assert_raise(ActiveRecord::AssociationNotFoundError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
+ assert_equal("Association named 'monkeys' was not found on Post; perhaps you misspelled it?", e.message)
+
+ e = assert_raise(ActiveRecord::AssociationNotFoundError) {
Post.all.merge!(includes: [ :monkeys ]).find(6)
}
- assert_raise(ActiveRecord::AssociationNotFoundError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
+ assert_equal("Association named 'monkeys' was not found on Post; perhaps you misspelled it?", e.message)
+
+ e = assert_raise(ActiveRecord::AssociationNotFoundError) {
Post.all.merge!(includes: [ "monkeys" ]).find(6)
}
- assert_raise(ActiveRecord::AssociationNotFoundError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys, :elephants") {
+ assert_equal("Association named 'monkeys' was not found on Post; perhaps you misspelled it?", e.message)
+
+ e = assert_raise(ActiveRecord::AssociationNotFoundError) {
Post.all.merge!(includes: [ :monkeys, :elephants ]).find(6)
}
+ assert_equal("Association named 'monkeys' was not found on Post; perhaps you misspelled it?", e.message)
end
def test_eager_has_many_through_with_order
diff --git a/activerecord/test/cases/coders/yaml_column_test.rb b/activerecord/test/cases/coders/yaml_column_test.rb
index b9c6224425..1e0b4580af 100644
--- a/activerecord/test/cases/coders/yaml_column_test.rb
+++ b/activerecord/test/cases/coders/yaml_column_test.rb
@@ -5,46 +5,48 @@ module ActiveRecord
module Coders
class YAMLColumnTest < ActiveRecord::TestCase
def test_initialize_takes_class
- coder = YAMLColumn.new(Object)
+ coder = YAMLColumn.new("attr_name", Object)
assert_equal Object, coder.object_class
end
def test_type_mismatch_on_different_classes_on_dump
- coder = YAMLColumn.new(Array)
- assert_raises(SerializationTypeMismatch) do
+ coder = YAMLColumn.new("attr_name", Array)
+ error = assert_raises(SerializationTypeMismatch) do
coder.dump("a")
end
+ assert_equal %{Attribute `attr_name` was supposed to be a Array, but was a String. -- "a"}, error.to_s
end
def test_type_mismatch_on_different_classes
- coder = YAMLColumn.new(Array)
- assert_raises(SerializationTypeMismatch) do
+ coder = YAMLColumn.new("attr_name", Array)
+ error = assert_raises(SerializationTypeMismatch) do
coder.load "--- foo"
end
+ assert_equal %{Attribute `attr_name` was supposed to be a Array, but was a String. -- "foo"}, error.to_s
end
def test_nil_is_ok
- coder = YAMLColumn.new
+ coder = YAMLColumn.new("attr_name")
assert_nil coder.load "--- "
end
def test_returns_new_with_different_class
- coder = YAMLColumn.new SerializationTypeMismatch
+ coder = YAMLColumn.new("attr_name", SerializationTypeMismatch)
assert_equal SerializationTypeMismatch, coder.load("--- ").class
end
def test_returns_string_unless_starts_with_dash
- coder = YAMLColumn.new
+ coder = YAMLColumn.new("attr_name")
assert_equal "foo", coder.load("foo")
end
def test_load_handles_other_classes
- coder = YAMLColumn.new
+ coder = YAMLColumn.new("attr_name")
assert_equal [], coder.load([])
end
def test_load_doesnt_swallow_yaml_exceptions
- coder = YAMLColumn.new
+ coder = YAMLColumn.new("attr_name")
bad_yaml = "--- {"
assert_raises(Psych::SyntaxError) do
coder.load(bad_yaml)
@@ -52,7 +54,7 @@ module ActiveRecord
end
def test_load_doesnt_handle_undefined_class_or_module
- coder = YAMLColumn.new
+ coder = YAMLColumn.new("attr_name")
missing_class_yaml = '--- !ruby/object:DoesNotExistAndShouldntEver {}\n'
assert_raises(ArgumentError) do
coder.load(missing_class_yaml)
diff --git a/activerecord/test/cases/migration/compatibility_test.rb b/activerecord/test/cases/migration/compatibility_test.rb
index e5a7412bc3..9296f3da90 100644
--- a/activerecord/test/cases/migration/compatibility_test.rb
+++ b/activerecord/test/cases/migration/compatibility_test.rb
@@ -103,9 +103,10 @@ module ActiveRecord
end
def test_legacy_migrations_raises_exception_when_inherited
- assert_raises(StandardError) do
- Class.new(ActiveRecord::Migration)
+ e = assert_raises(StandardError) do
+ class_eval("class LegacyMigration < ActiveRecord::Migration; end")
end
+ assert_match(/LegacyMigration < ActiveRecord::Migration\[4\.2\]/, e.message)
end
end
end
diff --git a/activerecord/test/cases/migrator_test.rb b/activerecord/test/cases/migrator_test.rb
index 224e8d1854..20d70b75ac 100644
--- a/activerecord/test/cases/migrator_test.rb
+++ b/activerecord/test/cases/migrator_test.rb
@@ -45,10 +45,11 @@ class MigratorTest < ActiveRecord::TestCase
end
def test_migrator_with_duplicate_names
- assert_raises(ActiveRecord::DuplicateMigrationNameError, "Multiple migrations have the name Chunky") do
+ e = assert_raises(ActiveRecord::DuplicateMigrationNameError) do
list = [ActiveRecord::Migration.new("Chunky"), ActiveRecord::Migration.new("Chunky")]
ActiveRecord::Migrator.new(:up, list)
end
+ assert_match(/Multiple migrations have the name Chunky/, e.message)
end
def test_migrator_with_duplicate_versions
diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb
index 2444eccab1..04ee67c177 100644
--- a/activerecord/test/cases/reflection_test.rb
+++ b/activerecord/test/cases/reflection_test.rb
@@ -258,7 +258,9 @@ class ReflectionTest < ActiveRecord::TestCase
[Post.reflect_on_association(:first_taggings).scope],
[Author.reflect_on_association(:misc_posts).scope]
]
- actual = Author.reflect_on_association(:misc_post_first_blue_tags).scope_chain
+ actual = assert_deprecated do
+ Author.reflect_on_association(:misc_post_first_blue_tags).scope_chain
+ end
assert_equal expected, actual
expected = [
@@ -270,7 +272,9 @@ class ReflectionTest < ActiveRecord::TestCase
[],
[]
]
- actual = Author.reflect_on_association(:misc_post_first_blue_tags_2).scope_chain
+ actual = assert_deprecated do
+ Author.reflect_on_association(:misc_post_first_blue_tags_2).scope_chain
+ end
assert_equal expected, actual
end
@@ -395,9 +399,15 @@ class ReflectionTest < ActiveRecord::TestCase
end
def test_through_reflection_scope_chain_does_not_modify_other_reflections
- orig_conds = Post.reflect_on_association(:first_blue_tags_2).scope_chain.inspect
- Author.reflect_on_association(:misc_post_first_blue_tags_2).scope_chain
- assert_equal orig_conds, Post.reflect_on_association(:first_blue_tags_2).scope_chain.inspect
+ orig_conds = assert_deprecated do
+ Post.reflect_on_association(:first_blue_tags_2).scope_chain
+ end.inspect
+ assert_deprecated do
+ Author.reflect_on_association(:misc_post_first_blue_tags_2).scope_chain
+ end
+ assert_equal orig_conds, assert_deprecated {
+ Post.reflect_on_association(:first_blue_tags_2).scope_chain
+ }.inspect
end
def test_symbol_for_class_name
diff --git a/activerecord/test/cases/serialized_attribute_test.rb b/activerecord/test/cases/serialized_attribute_test.rb
index a469da0a5b..24b83691f6 100644
--- a/activerecord/test/cases/serialized_attribute_test.rb
+++ b/activerecord/test/cases/serialized_attribute_test.rb
@@ -240,6 +240,20 @@ class SerializedAttributeTest < ActiveRecord::TestCase
assert_equal [], light.long_state
end
+ def test_unexpected_serialized_type
+ Topic.serialize :content, Hash
+ topic = Topic.create!(content: { zomg: true })
+
+ Topic.serialize :content, Array
+
+ topic.reload
+ error = assert_raise(ActiveRecord::SerializationTypeMismatch) do
+ topic.content
+ end
+ expected = "Attribute `content` was supposed to be a Array, but was a Hash. -- {:zomg=>true}"
+ assert_equal expected, error.to_s
+ end
+
def test_serialized_column_should_unserialize_after_update_column
t = Topic.create(content: "first")
assert_equal("first", t.content)