aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib
diff options
context:
space:
mode:
authorBen Woosley <ben.woosley@gmail.com>2013-09-03 21:46:33 -0700
committerBen Woosley <ben.woosley@gmail.com>2013-09-04 01:32:27 -0700
commit1a40be02113287d9a003f8224e91b9f623857f4b (patch)
treeee93651b60297fbdc30bc05d71a8ec3e5b48f0dc /activerecord/lib
parent5e41cb4a1e7e48a23f9387f2794d69e7fabf44c0 (diff)
downloadrails-1a40be02113287d9a003f8224e91b9f623857f4b.tar.gz
rails-1a40be02113287d9a003f8224e91b9f623857f4b.tar.bz2
rails-1a40be02113287d9a003f8224e91b9f623857f4b.zip
Deprecate the delegation of Array bang methods in ActiveRecord::Delegation
The primary means of returning results for Array bang methods is to modify the array in-place. When you call these methods on a relation, that array is created, modified, and then thrown away. Only the secondary return value is exposed to the caller. Removing this delegation is a straight-forward way to reduce user error by forcing callers to first explicitly call #to_a in order to expose the array to be acted on by the bang method.
Diffstat (limited to 'activerecord/lib')
-rw-r--r--activerecord/lib/active_record/relation/delegation.rb17
1 files changed, 14 insertions, 3 deletions
diff --git a/activerecord/lib/active_record/relation/delegation.rb b/activerecord/lib/active_record/relation/delegation.rb
index e28938f9d0..1e15bddcdf 100644
--- a/activerecord/lib/active_record/relation/delegation.rb
+++ b/activerecord/lib/active_record/relation/delegation.rb
@@ -1,4 +1,5 @@
require 'active_support/concern'
+require 'active_support/deprecation'
module ActiveRecord
module Delegation # :nodoc:
@@ -83,7 +84,7 @@ module ActiveRecord
if @klass.respond_to?(method)
self.class.delegate_to_scoped_klass(method)
scoping { @klass.send(method, *args, &block) }
- elsif Array.method_defined?(method)
+ elsif array_delegable?(method)
self.class.delegate method, :to => :to_a
to_a.send(method, *args, &block)
elsif arel.respond_to?(method)
@@ -108,17 +109,27 @@ module ActiveRecord
end
def respond_to?(method, include_private = false)
- super || Array.method_defined?(method) ||
+ super || array_delegable?(method) ||
@klass.respond_to?(method, include_private) ||
arel.respond_to?(method, include_private)
end
protected
+ def array_delegable?(method)
+ defined = Array.method_defined?(method)
+ if defined && method.to_s.ends_with?('!')
+ ActiveSupport::Deprecation.warn(
+ "Association will no longer delegate #{method} to #to_a as of Rails 4.2. You instead must first call #to_a on the association to expose the array to be acted on."
+ )
+ end
+ defined
+ end
+
def method_missing(method, *args, &block)
if @klass.respond_to?(method)
scoping { @klass.send(method, *args, &block) }
- elsif Array.method_defined?(method)
+ elsif array_delegable?(method)
to_a.send(method, *args, &block)
elsif arel.respond_to?(method)
arel.send(method, *args, &block)