diff options
author | Lauro Caetano <laurocaetano1@gmail.com> | 2013-12-13 22:11:39 -0200 |
---|---|---|
committer | Lauro Caetano <laurocaetano1@gmail.com> | 2013-12-17 13:43:10 -0200 |
commit | d4ee09cda135da9c36a5ddadd2d8c2d35c116be3 (patch) | |
tree | 469e6dcb73930059b59e911defaee4a98ca44f43 /activerecord/lib | |
parent | 5d77edf0cf1ed653ed3f7729d77eeb8de219d0b3 (diff) | |
download | rails-d4ee09cda135da9c36a5ddadd2d8c2d35c116be3.tar.gz rails-d4ee09cda135da9c36a5ddadd2d8c2d35c116be3.tar.bz2 rails-d4ee09cda135da9c36a5ddadd2d8c2d35c116be3.zip |
Create a blacklist to disallow mutator methods to be delegated to `Array`.
This change was necessary because the whitelist wouldn't work.
It would be painful for users trying to update their applications.
This blacklist intent to prevent odd bugs and confusion in code that call mutator
methods directely on the `Relation`.
Diffstat (limited to 'activerecord/lib')
-rw-r--r-- | activerecord/lib/active_record/relation/delegation.rb | 25 |
1 files changed, 14 insertions, 11 deletions
diff --git a/activerecord/lib/active_record/relation/delegation.rb b/activerecord/lib/active_record/relation/delegation.rb index 246c5db5bd..21beed332f 100644 --- a/activerecord/lib/active_record/relation/delegation.rb +++ b/activerecord/lib/active_record/relation/delegation.rb @@ -1,3 +1,4 @@ +require 'set' require 'active_support/concern' require 'active_support/deprecation' @@ -36,18 +37,13 @@ module ActiveRecord # may vary depending on the klass of a relation, so we create a subclass of Relation # for each different klass, and the delegations are compiled into that subclass only. - # TODO: This is not going to work. Brittle, painful. We'll switch to a blacklist - # to disallow mutator methods like map!, pop, and delete_if instead. - ARRAY_DELEGATES = [ - :+, :-, :|, :&, :[], - :all?, :collect, :detect, :each, :each_cons, :each_with_index, - :exclude?, :find_all, :flat_map, :group_by, :include?, :length, - :map, :none?, :one?, :partition, :reject, :reverse, - :sample, :second, :sort, :sort_by, :third, - :to_ary, :to_set, :to_xml, :to_yaml - ] + BLACKLISTED_ARRAY_METHODS = [ + :compact!, :flatten!, :reject!, :reverse!, :rotate!, :map!, + :shuffle!, :slice!, :sort!, :sort_by!, :delete_if, + :keep_if, :pop, :shift, :delete_at, :compact + ].to_set # :nodoc: - delegate(*ARRAY_DELEGATES, to: :to_a) + delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to_ary, to: :to_a delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key, :connection, :columns_hash, :to => :klass @@ -119,14 +115,21 @@ module ActiveRecord def respond_to?(method, include_private = false) super || @klass.respond_to?(method, include_private) || + array_delegable?(method) || arel.respond_to?(method, include_private) end protected + def array_delegable?(method) + Array.method_defined?(method) && BLACKLISTED_ARRAY_METHODS.exclude?(method) + end + def method_missing(method, *args, &block) if @klass.respond_to?(method) scoping { @klass.public_send(method, *args, &block) } + elsif array_delegable?(method) + to_a.public_send(method, *args, &block) elsif arel.respond_to?(method) arel.public_send(method, *args, &block) else |