aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/lib/active_record/associations/association.rb10
-rw-r--r--activerecord/lib/active_record/associations/association_scope.rb2
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb3
-rw-r--r--activerecord/lib/active_record/associations/collection_proxy.rb33
-rw-r--r--activerecord/lib/active_record/reflection.rb4
-rw-r--r--activerecord/lib/active_record/relation/delegation.rb2
-rw-r--r--activerecord/lib/active_record/scoping/named.rb11
-rw-r--r--activerecord/test/cases/associations/extension_test.rb6
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb10
-rw-r--r--activerecord/test/cases/associations_test.rb5
-rw-r--r--activerecord/test/models/comment.rb10
-rw-r--r--activerecord/test/models/post.rb2
12 files changed, 64 insertions, 34 deletions
diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb
index 6b13e6936f..ee2e79889f 100644
--- a/activerecord/lib/active_record/associations/association.rb
+++ b/activerecord/lib/active_record/associations/association.rb
@@ -133,6 +133,16 @@ module ActiveRecord
AssociationRelation.create(klass, klass.arel_table, klass.predicate_builder, self).merge!(klass.all)
end
+ def extensions
+ extensions = klass.default_extensions | reflection.extensions
+
+ if scope = reflection.scope
+ extensions |= klass.unscoped.instance_exec(owner, &scope).extensions
+ end
+
+ extensions
+ end
+
# Loads the \target if needed and returns it.
#
# This method is abstract in the sense that it relies on +find_target+,
diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb
index 120d75416c..1593b94f0c 100644
--- a/activerecord/lib/active_record/associations/association_scope.rb
+++ b/activerecord/lib/active_record/associations/association_scope.rb
@@ -24,7 +24,7 @@ module ActiveRecord
alias_tracker = AliasTracker.create connection, association.klass.table_name, klass.type_caster
chain_head, chain_tail = get_chain(reflection, association, alias_tracker)
- scope.extending! Array(reflection.options[:extend])
+ scope.extending! reflection.extensions
add_constraints(scope, owner, reflection, chain_head, chain_tail)
end
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index 62c944fce3..edc53e2517 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -30,7 +30,8 @@ module ActiveRecord
reload
end
- CollectionProxy.create(klass, self)
+ @proxy ||= CollectionProxy.create(klass, self)
+ @proxy.reset_scope
end
# Implements the writer method, e.g. foo.items= for Foo.has_many :items
diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb
index 74a4d515c2..8cdb508c43 100644
--- a/activerecord/lib/active_record/associations/collection_proxy.rb
+++ b/activerecord/lib/active_record/associations/collection_proxy.rb
@@ -31,6 +31,9 @@ module ActiveRecord
def initialize(klass, association) #:nodoc:
@association = association
super klass, klass.arel_table, klass.predicate_builder
+
+ extensions = association.extensions
+ extend(*extensions) if extensions.any?
end
def target
@@ -1084,9 +1087,8 @@ 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
+ reset_scope
end
# Unloads the association. Returns +self+.
@@ -1106,9 +1108,13 @@ 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
+ reset_scope
+ end
+
+ def reset_scope # :nodoc:
+ @scope = nil
self
end
@@ -1121,19 +1127,6 @@ module ActiveRecord
delegate(*delegate_methods, to: :scope)
- module DelegateExtending # :nodoc:
- private
- def method_missing(method, *args, &block)
- extending_values = association_scope.extending_values
- if extending_values.any? && (extending_values - self.class.included_modules).any?
- self.class.include(*extending_values)
- public_send(method, *args, &block)
- else
- super
- end
- end
- end
-
private
def find_nth_with_limit(index, limit)
@@ -1154,17 +1147,9 @@ module ActiveRecord
@association.find_from_target?
end
- def association_scope
- @association.association_scope
- end
-
def exec_queries
load_target
end
-
- def respond_to_missing?(method, _)
- association_scope.respond_to?(method) || super
- end
end
end
end
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index d6154c9a38..429f9a257a 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -579,6 +579,10 @@ module ActiveRecord
seed + [self]
end
+ def extensions
+ Array(options[:extend])
+ end
+
protected
def actual_source_reflection # FIXME: this is a horrible name
diff --git a/activerecord/lib/active_record/relation/delegation.rb b/activerecord/lib/active_record/relation/delegation.rb
index 4f739a0415..dada0fddf8 100644
--- a/activerecord/lib/active_record/relation/delegation.rb
+++ b/activerecord/lib/active_record/relation/delegation.rb
@@ -25,8 +25,6 @@ module ActiveRecord
def inherited(child_class)
child_class.initialize_relation_delegate_cache
- delegate = child_class.relation_delegate_class(ActiveRecord::Associations::CollectionProxy)
- delegate.include ActiveRecord::Associations::CollectionProxy::DelegateExtending
super
end
end
diff --git a/activerecord/lib/active_record/scoping/named.rb b/activerecord/lib/active_record/scoping/named.rb
index 029156189d..a61fdd6454 100644
--- a/activerecord/lib/active_record/scoping/named.rb
+++ b/activerecord/lib/active_record/scoping/named.rb
@@ -30,12 +30,15 @@ module ActiveRecord
end
def default_scoped # :nodoc:
- scope = build_default_scope
+ scope = relation
+ build_default_scope(scope) || scope
+ end
- if scope
- relation.spawn.merge!(scope)
+ def default_extensions # :nodoc:
+ if scope = current_scope || build_default_scope
+ scope.extensions
else
- relation
+ []
end
end
diff --git a/activerecord/test/cases/associations/extension_test.rb b/activerecord/test/cases/associations/extension_test.rb
index 87d842f21d..f707a170f5 100644
--- a/activerecord/test/cases/associations/extension_test.rb
+++ b/activerecord/test/cases/associations/extension_test.rb
@@ -78,6 +78,12 @@ class AssociationsExtensionsTest < ActiveRecord::TestCase
assert_equal post.association(:comments), post.comments.where("1=1").the_association
end
+ def test_association_with_default_scope
+ assert_raises OopsError do
+ posts(:welcome).comments.destroy_all
+ end
+ end
+
private
def extend!(model)
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index 6a479a344c..a794eba691 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -2251,7 +2251,15 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
test "association with extend option with multiple extensions" do
post = posts(:welcome)
assert_equal "lifo", post.comments_with_extend_2.author
- assert_equal "hello", post.comments_with_extend_2.greeting
+ assert_equal "hullo", post.comments_with_extend_2.greeting
+ end
+
+ test "extend option affects per association" do
+ post = posts(:welcome)
+ assert_equal "lifo", post.comments_with_extend.author
+ assert_equal "lifo", post.comments_with_extend_2.author
+ assert_equal "hello", post.comments_with_extend.greeting
+ assert_equal "hullo", post.comments_with_extend_2.greeting
end
test "delete record with complex joins" do
diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb
index 4ab690bfc6..ff31c82794 100644
--- a/activerecord/test/cases/associations_test.rb
+++ b/activerecord/test/cases/associations_test.rb
@@ -220,6 +220,11 @@ class AssociationProxyTest < ActiveRecord::TestCase
assert_equal david.projects, david.projects.scope
end
+ test "proxy object is cached" do
+ david = developers(:david)
+ assert_same david.projects, david.projects
+ end
+
test "inverses get set of subsets of the association" do
man = Man.create
man.interests.create
diff --git a/activerecord/test/models/comment.rb b/activerecord/test/models/comment.rb
index 76b484e616..8cba788598 100644
--- a/activerecord/test/models/comment.rb
+++ b/activerecord/test/models/comment.rb
@@ -19,6 +19,16 @@ class Comment < ActiveRecord::Base
has_many :children, class_name: "Comment", foreign_key: :parent_id
belongs_to :parent, class_name: "Comment", counter_cache: :children_count
+ class ::OopsError < RuntimeError; end
+
+ module OopsExtension
+ def destroy_all(*)
+ raise OopsError
+ end
+ end
+
+ default_scope { extending OopsExtension }
+
# Should not be called if extending modules that having the method exists on an association.
def self.greeting
raise
diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb
index a2028b3eb9..4c913b3b72 100644
--- a/activerecord/test/models/post.rb
+++ b/activerecord/test/models/post.rb
@@ -13,7 +13,7 @@ class Post < ActiveRecord::Base
module NamedExtension2
def greeting
- "hello"
+ "hullo"
end
end