activerecord 4.0.4 → 4.1.16
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1632 -1797
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- data/examples/performance.rb +30 -18
- data/examples/simple.rb +4 -4
- data/lib/active_record/aggregations.rb +2 -1
- data/lib/active_record/association_relation.rb +4 -0
- data/lib/active_record/associations/alias_tracker.rb +49 -29
- data/lib/active_record/associations/association.rb +9 -17
- data/lib/active_record/associations/association_scope.rb +59 -49
- data/lib/active_record/associations/belongs_to_association.rb +34 -25
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +6 -1
- data/lib/active_record/associations/builder/association.rb +84 -54
- data/lib/active_record/associations/builder/belongs_to.rb +90 -58
- data/lib/active_record/associations/builder/collection_association.rb +47 -45
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +119 -25
- data/lib/active_record/associations/builder/has_many.rb +3 -3
- data/lib/active_record/associations/builder/has_one.rb +5 -7
- data/lib/active_record/associations/builder/singular_association.rb +6 -7
- data/lib/active_record/associations/collection_association.rb +121 -111
- data/lib/active_record/associations/collection_proxy.rb +73 -18
- data/lib/active_record/associations/has_many_association.rb +14 -11
- data/lib/active_record/associations/has_many_through_association.rb +33 -6
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +46 -104
- data/lib/active_record/associations/join_dependency/join_base.rb +6 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +18 -37
- data/lib/active_record/associations/join_dependency.rb +208 -168
- data/lib/active_record/associations/preloader/association.rb +69 -27
- data/lib/active_record/associations/preloader/collection_association.rb +2 -2
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/singular_association.rb +3 -3
- data/lib/active_record/associations/preloader/through_association.rb +58 -26
- data/lib/active_record/associations/preloader.rb +63 -49
- data/lib/active_record/associations/singular_association.rb +6 -5
- data/lib/active_record/associations/through_association.rb +30 -9
- data/lib/active_record/associations.rb +116 -42
- data/lib/active_record/attribute_assignment.rb +6 -3
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -1
- data/lib/active_record/attribute_methods/dirty.rb +35 -26
- data/lib/active_record/attribute_methods/primary_key.rb +8 -1
- data/lib/active_record/attribute_methods/read.rb +56 -29
- data/lib/active_record/attribute_methods/serialization.rb +44 -12
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +13 -1
- data/lib/active_record/attribute_methods/write.rb +59 -26
- data/lib/active_record/attribute_methods.rb +82 -43
- data/lib/active_record/autosave_association.rb +209 -194
- data/lib/active_record/base.rb +6 -2
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +5 -10
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +14 -24
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +13 -13
- data/lib/active_record/connection_adapters/abstract/quoting.rb +6 -3
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +90 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +9 -8
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +45 -70
- data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +28 -96
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +74 -66
- data/lib/active_record/connection_adapters/column.rb +1 -35
- data/lib/active_record/connection_adapters/connection_specification.rb +231 -43
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +10 -5
- data/lib/active_record/connection_adapters/mysql_adapter.rb +24 -17
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +22 -15
- data/lib/active_record/connection_adapters/postgresql/cast.rb +12 -4
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -44
- data/lib/active_record/connection_adapters/postgresql/oid.rb +38 -14
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +37 -12
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +20 -11
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +98 -52
- data/lib/active_record/connection_adapters/schema_cache.rb +8 -29
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +55 -60
- data/lib/active_record/connection_handling.rb +39 -5
- data/lib/active_record/core.rb +38 -54
- data/lib/active_record/counter_cache.rb +9 -10
- data/lib/active_record/dynamic_matchers.rb +6 -2
- data/lib/active_record/enum.rb +199 -0
- data/lib/active_record/errors.rb +22 -5
- data/lib/active_record/fixture_set/file.rb +2 -1
- data/lib/active_record/fixtures.rb +173 -76
- data/lib/active_record/gem_version.rb +15 -0
- data/lib/active_record/inheritance.rb +23 -9
- data/lib/active_record/integration.rb +54 -1
- data/lib/active_record/locking/optimistic.rb +7 -2
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +6 -13
- data/lib/active_record/migration/command_recorder.rb +8 -2
- data/lib/active_record/migration.rb +91 -56
- data/lib/active_record/model_schema.rb +7 -14
- data/lib/active_record/nested_attributes.rb +25 -13
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +26 -6
- data/lib/active_record/persistence.rb +23 -29
- data/lib/active_record/querying.rb +15 -12
- data/lib/active_record/railtie.rb +12 -61
- data/lib/active_record/railties/databases.rake +37 -56
- data/lib/active_record/readonly_attributes.rb +0 -6
- data/lib/active_record/reflection.rb +230 -79
- data/lib/active_record/relation/batches.rb +74 -24
- data/lib/active_record/relation/calculations.rb +52 -48
- data/lib/active_record/relation/delegation.rb +54 -39
- data/lib/active_record/relation/finder_methods.rb +210 -67
- data/lib/active_record/relation/merger.rb +15 -12
- data/lib/active_record/relation/predicate_builder/array_handler.rb +29 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder.rb +81 -40
- data/lib/active_record/relation/query_methods.rb +185 -108
- data/lib/active_record/relation/spawn_methods.rb +8 -5
- data/lib/active_record/relation.rb +79 -84
- data/lib/active_record/result.rb +45 -6
- data/lib/active_record/runtime_registry.rb +5 -0
- data/lib/active_record/sanitization.rb +4 -4
- data/lib/active_record/schema_dumper.rb +18 -6
- data/lib/active_record/schema_migration.rb +31 -18
- data/lib/active_record/scoping/default.rb +5 -18
- data/lib/active_record/scoping/named.rb +14 -29
- data/lib/active_record/scoping.rb +5 -0
- data/lib/active_record/store.rb +67 -18
- data/lib/active_record/tasks/database_tasks.rb +66 -26
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -10
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +6 -6
- data/lib/active_record/transactions.rb +10 -12
- data/lib/active_record/validations/presence.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +19 -9
- data/lib/active_record/version.rb +4 -7
- data/lib/active_record.rb +5 -7
- data/lib/rails/generators/active_record/migration/migration_generator.rb +4 -0
- data/lib/rails/generators/active_record/migration.rb +18 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +4 -0
- data/lib/rails/generators/active_record.rb +2 -8
- metadata +18 -30
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -65
- data/lib/active_record/associations/join_helper.rb +0 -45
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/tasks/firebird_database_tasks.rb +0 -56
- data/lib/active_record/tasks/oracle_database_tasks.rb +0 -45
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +0 -48
- data/lib/active_record/test_case.rb +0 -96
@@ -19,7 +19,17 @@ module ActiveRecord
|
|
19
19
|
#
|
20
20
|
# Person.group(:city).count
|
21
21
|
# # => { 'Rome' => 5, 'Paris' => 3 }
|
22
|
+
#
|
23
|
+
# If +count+ is used with +select+, it will count the selected columns:
|
24
|
+
#
|
25
|
+
# Person.select(:age).count
|
26
|
+
# # => counts the number of different age values
|
27
|
+
#
|
28
|
+
# Note: not all valid +select+ expressions are valid +count+ expressions. The specifics differ
|
29
|
+
# between databases. In invalid cases, an error from the databsae is thrown.
|
22
30
|
def count(column_name = nil, options = {})
|
31
|
+
# TODO: Remove options argument as soon we remove support to
|
32
|
+
# activerecord-deprecated_finders.
|
23
33
|
column_name, options = nil, column_name if column_name.is_a?(Hash)
|
24
34
|
calculate(:count, column_name, options)
|
25
35
|
end
|
@@ -27,8 +37,10 @@ module ActiveRecord
|
|
27
37
|
# Calculates the average value on a given column. Returns +nil+ if there's
|
28
38
|
# no row. See +calculate+ for examples with options.
|
29
39
|
#
|
30
|
-
# Person.average(
|
40
|
+
# Person.average(:age) # => 35.8
|
31
41
|
def average(column_name, options = {})
|
42
|
+
# TODO: Remove options argument as soon we remove support to
|
43
|
+
# activerecord-deprecated_finders.
|
32
44
|
calculate(:average, column_name, options)
|
33
45
|
end
|
34
46
|
|
@@ -36,8 +48,10 @@ module ActiveRecord
|
|
36
48
|
# with the same data type of the column, or +nil+ if there's no row. See
|
37
49
|
# +calculate+ for examples with options.
|
38
50
|
#
|
39
|
-
# Person.minimum(
|
51
|
+
# Person.minimum(:age) # => 7
|
40
52
|
def minimum(column_name, options = {})
|
53
|
+
# TODO: Remove options argument as soon we remove support to
|
54
|
+
# activerecord-deprecated_finders.
|
41
55
|
calculate(:minimum, column_name, options)
|
42
56
|
end
|
43
57
|
|
@@ -45,8 +59,10 @@ module ActiveRecord
|
|
45
59
|
# with the same data type of the column, or +nil+ if there's no row. See
|
46
60
|
# +calculate+ for examples with options.
|
47
61
|
#
|
48
|
-
# Person.maximum(
|
62
|
+
# Person.maximum(:age) # => 93
|
49
63
|
def maximum(column_name, options = {})
|
64
|
+
# TODO: Remove options argument as soon we remove support to
|
65
|
+
# activerecord-deprecated_finders.
|
50
66
|
calculate(:maximum, column_name, options)
|
51
67
|
end
|
52
68
|
|
@@ -54,17 +70,9 @@ module ActiveRecord
|
|
54
70
|
# with the same data type of the column, 0 if there's no row. See
|
55
71
|
# +calculate+ for examples with options.
|
56
72
|
#
|
57
|
-
# Person.sum(
|
73
|
+
# Person.sum(:age) # => 4562
|
58
74
|
def sum(*args)
|
59
|
-
|
60
|
-
ActiveSupport::Deprecation.warn(
|
61
|
-
"Calling #sum with a block is deprecated and will be removed in Rails 4.1. " \
|
62
|
-
"If you want to perform sum calculation over the array of elements, use `to_a.sum(&block)`."
|
63
|
-
)
|
64
|
-
self.to_a.sum(*args) {|*block_args| yield(*block_args)}
|
65
|
-
else
|
66
|
-
calculate(:sum, *args)
|
67
|
-
end
|
75
|
+
calculate(:sum, *args)
|
68
76
|
end
|
69
77
|
|
70
78
|
# This calculates aggregate values in the given column. Methods for count, sum, average,
|
@@ -99,19 +107,17 @@ module ActiveRecord
|
|
99
107
|
#
|
100
108
|
# Person.sum("2 * age")
|
101
109
|
def calculate(operation, column_name, options = {})
|
102
|
-
|
110
|
+
# TODO: Remove options argument as soon we remove support to
|
111
|
+
# activerecord-deprecated_finders.
|
112
|
+
if column_name.is_a?(Symbol) && attribute_alias?(column_name)
|
113
|
+
column_name = attribute_alias(column_name)
|
114
|
+
end
|
103
115
|
|
104
|
-
if
|
105
|
-
|
106
|
-
construct_relation_for_association_calculations.calculate(operation, column_name, options)
|
107
|
-
else
|
108
|
-
perform_calculation(operation, column_name, options)
|
109
|
-
end
|
116
|
+
if has_include?(column_name)
|
117
|
+
construct_relation_for_association_calculations.calculate(operation, column_name, options)
|
110
118
|
else
|
111
|
-
|
119
|
+
perform_calculation(operation, column_name, options)
|
112
120
|
end
|
113
|
-
rescue ThrowResult
|
114
|
-
0
|
115
121
|
end
|
116
122
|
|
117
123
|
# Use <tt>pluck</tt> as a shortcut to select one or more attributes without
|
@@ -149,10 +155,10 @@ module ActiveRecord
|
|
149
155
|
#
|
150
156
|
def pluck(*column_names)
|
151
157
|
column_names.map! do |column_name|
|
152
|
-
if column_name.is_a?(Symbol) &&
|
153
|
-
|
158
|
+
if column_name.is_a?(Symbol) && attribute_alias?(column_name)
|
159
|
+
attribute_alias(column_name)
|
154
160
|
else
|
155
|
-
column_name
|
161
|
+
column_name.to_s
|
156
162
|
end
|
157
163
|
end
|
158
164
|
|
@@ -160,22 +166,23 @@ module ActiveRecord
|
|
160
166
|
construct_relation_for_association_calculations.pluck(*column_names)
|
161
167
|
else
|
162
168
|
relation = spawn
|
163
|
-
relation.select_values = column_names
|
169
|
+
relation.select_values = column_names.map { |cn|
|
170
|
+
columns_hash.key?(cn) ? arel_table[cn] : cn
|
171
|
+
}
|
164
172
|
result = klass.connection.select_all(relation.arel, nil, bind_values)
|
165
173
|
columns = result.columns.map do |key|
|
166
174
|
klass.column_types.fetch(key) {
|
167
|
-
result.column_types.fetch(key) {
|
168
|
-
Class.new { def type_cast(v); v; end }.new
|
169
|
-
}
|
175
|
+
result.column_types.fetch(key) { result.identity_type }
|
170
176
|
}
|
171
177
|
end
|
172
178
|
|
173
|
-
result = result.map do |
|
174
|
-
values =
|
175
|
-
|
176
|
-
|
177
|
-
column.type_cast(value)
|
179
|
+
result = result.rows.map do |values|
|
180
|
+
values = result.columns.zip(values).map do |column_name, value|
|
181
|
+
single_attr_hash = { column_name => value }
|
182
|
+
klass.initialize_attributes(single_attr_hash).values.first
|
178
183
|
end
|
184
|
+
|
185
|
+
columns.zip(values).map { |column, value| column.type_cast value }
|
179
186
|
end
|
180
187
|
columns.one? ? result.map!(&:first) : result
|
181
188
|
end
|
@@ -192,30 +199,26 @@ module ActiveRecord
|
|
192
199
|
private
|
193
200
|
|
194
201
|
def has_include?(column_name)
|
195
|
-
eager_loading? || (includes_values.present? && (column_name || references_eager_loaded_tables?))
|
202
|
+
eager_loading? || (includes_values.present? && ((column_name && column_name != :all) || references_eager_loaded_tables?))
|
196
203
|
end
|
197
204
|
|
198
205
|
def perform_calculation(operation, column_name, options = {})
|
206
|
+
# TODO: Remove options argument as soon we remove support to
|
207
|
+
# activerecord-deprecated_finders.
|
199
208
|
operation = operation.to_s.downcase
|
200
209
|
|
201
210
|
# If #count is used with #distinct / #uniq it is considered distinct. (eg. relation.distinct.count)
|
202
211
|
distinct = self.distinct_value
|
203
|
-
if options.has_key?(:distinct)
|
204
|
-
ActiveSupport::Deprecation.warn "The :distinct option for `Relation#count` is deprecated. " \
|
205
|
-
"Please use `Relation#distinct` instead. (eg. `relation.distinct.count`)"
|
206
|
-
distinct = options[:distinct]
|
207
|
-
end
|
208
212
|
|
209
213
|
if operation == "count"
|
210
|
-
column_name ||=
|
214
|
+
column_name ||= select_for_count
|
211
215
|
|
212
216
|
unless arel.ast.grep(Arel::Nodes::OuterJoin).empty?
|
213
217
|
distinct = true
|
214
218
|
end
|
215
219
|
|
216
220
|
column_name = primary_key if column_name == :all && distinct
|
217
|
-
|
218
|
-
distinct = nil if column_name =~ /\s*DISTINCT\s+/i
|
221
|
+
distinct = nil if column_name =~ /\s*DISTINCT[\s(]+/i
|
219
222
|
end
|
220
223
|
|
221
224
|
if group_values.any?
|
@@ -239,7 +242,7 @@ module ActiveRecord
|
|
239
242
|
|
240
243
|
def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
|
241
244
|
# Postgresql doesn't like ORDER BY when there are no GROUP BY
|
242
|
-
relation =
|
245
|
+
relation = unscope(:order)
|
243
246
|
|
244
247
|
column_alias = column_name
|
245
248
|
|
@@ -273,7 +276,7 @@ module ActiveRecord
|
|
273
276
|
group_attrs = group_values
|
274
277
|
|
275
278
|
if group_attrs.first.respond_to?(:to_sym)
|
276
|
-
association = @klass.
|
279
|
+
association = @klass._reflect_on_association(group_attrs.first.to_sym)
|
277
280
|
associated = group_attrs.size == 1 && association && association.macro == :belongs_to # only count belongs_to associations
|
278
281
|
group_fields = Array(associated ? association.foreign_key : group_attrs)
|
279
282
|
else
|
@@ -381,8 +384,9 @@ module ActiveRecord
|
|
381
384
|
# TODO: refactor to allow non-string `select_values` (eg. Arel nodes).
|
382
385
|
def select_for_count
|
383
386
|
if select_values.present?
|
384
|
-
|
385
|
-
|
387
|
+
select_values.join(", ")
|
388
|
+
else
|
389
|
+
:all
|
386
390
|
end
|
387
391
|
end
|
388
392
|
|
@@ -1,8 +1,35 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
1
|
+
require 'set'
|
2
|
+
require 'active_support/concern'
|
3
|
+
require 'active_support/deprecation'
|
3
4
|
|
4
5
|
module ActiveRecord
|
5
6
|
module Delegation # :nodoc:
|
7
|
+
module DelegateCache
|
8
|
+
def relation_delegate_class(klass) # :nodoc:
|
9
|
+
@relation_delegate_cache[klass]
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize_relation_delegate_cache # :nodoc:
|
13
|
+
@relation_delegate_cache = cache = {}
|
14
|
+
[
|
15
|
+
ActiveRecord::Relation,
|
16
|
+
ActiveRecord::Associations::CollectionProxy,
|
17
|
+
ActiveRecord::AssociationRelation
|
18
|
+
].each do |klass|
|
19
|
+
delegate = Class.new(klass) {
|
20
|
+
include ClassSpecificRelation
|
21
|
+
}
|
22
|
+
const_set klass.name.gsub('::', '_'), delegate
|
23
|
+
cache[klass] = delegate
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def inherited(child_class)
|
28
|
+
child_class.initialize_relation_delegate_cache
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
6
33
|
extend ActiveSupport::Concern
|
7
34
|
|
8
35
|
# This module creates compiled delegation methods dynamically at runtime, which makes
|
@@ -10,7 +37,14 @@ module ActiveRecord
|
|
10
37
|
# may vary depending on the klass of a relation, so we create a subclass of Relation
|
11
38
|
# for each different klass, and the delegations are compiled into that subclass only.
|
12
39
|
|
13
|
-
|
40
|
+
BLACKLISTED_ARRAY_METHODS = [
|
41
|
+
:compact!, :flatten!, :reject!, :reverse!, :rotate!, :map!,
|
42
|
+
:shuffle!, :slice!, :sort!, :sort_by!, :delete_if,
|
43
|
+
:keep_if, :pop, :shift, :delete_at, :select!
|
44
|
+
].to_set # :nodoc:
|
45
|
+
|
46
|
+
delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to_ary, :join, to: :to_a
|
47
|
+
|
14
48
|
delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key,
|
15
49
|
:connection, :columns_hash, :to => :klass
|
16
50
|
|
@@ -38,7 +72,7 @@ module ActiveRecord
|
|
38
72
|
RUBY
|
39
73
|
else
|
40
74
|
define_method method do |*args, &block|
|
41
|
-
scoping { @klass.
|
75
|
+
scoping { @klass.public_send(method, *args, &block) }
|
42
76
|
end
|
43
77
|
end
|
44
78
|
end
|
@@ -57,13 +91,10 @@ module ActiveRecord
|
|
57
91
|
def method_missing(method, *args, &block)
|
58
92
|
if @klass.respond_to?(method)
|
59
93
|
self.class.delegate_to_scoped_klass(method)
|
60
|
-
scoping { @klass.
|
61
|
-
elsif Array.method_defined?(method)
|
62
|
-
self.class.delegate method, :to => :to_a
|
63
|
-
to_a.send(method, *args, &block)
|
94
|
+
scoping { @klass.public_send(method, *args, &block) }
|
64
95
|
elsif arel.respond_to?(method)
|
65
96
|
self.class.delegate method, :to => :arel
|
66
|
-
arel.
|
97
|
+
arel.public_send(method, *args, &block)
|
67
98
|
else
|
68
99
|
super
|
69
100
|
end
|
@@ -71,52 +102,36 @@ module ActiveRecord
|
|
71
102
|
end
|
72
103
|
|
73
104
|
module ClassMethods # :nodoc:
|
74
|
-
|
75
|
-
|
76
|
-
def new(klass, *args)
|
77
|
-
relation = relation_class_for(klass).allocate
|
78
|
-
relation.__send__(:initialize, klass, *args)
|
79
|
-
relation
|
80
|
-
end
|
81
|
-
|
82
|
-
# This doesn't have to be thread-safe. relation_class_for guarantees that this will only be
|
83
|
-
# called exactly once for a given const name.
|
84
|
-
def const_missing(name)
|
85
|
-
const_set(name, Class.new(self) { include ClassSpecificRelation })
|
105
|
+
def create(klass, *args)
|
106
|
+
relation_class_for(klass).new(klass, *args)
|
86
107
|
end
|
87
108
|
|
88
109
|
private
|
89
|
-
|
90
|
-
# make instantiation significantly slower.
|
110
|
+
|
91
111
|
def relation_class_for(klass)
|
92
|
-
|
93
|
-
my_cache = @@subclasses.compute_if_absent(self) { ThreadSafe::Cache.new }
|
94
|
-
# This hash is keyed by klass.name to avoid memory leaks in development mode
|
95
|
-
my_cache.compute_if_absent(klass_name) do
|
96
|
-
# Cache#compute_if_absent guarantees that the block will only executed once for the given klass_name
|
97
|
-
const_get("#{name.gsub('::', '_')}_#{klass_name.gsub('::', '_')}", false)
|
98
|
-
end
|
99
|
-
else
|
100
|
-
ActiveRecord::Relation
|
101
|
-
end
|
112
|
+
klass.relation_delegate_class(self)
|
102
113
|
end
|
103
114
|
end
|
104
115
|
|
105
116
|
def respond_to?(method, include_private = false)
|
106
|
-
super ||
|
107
|
-
|
117
|
+
super || @klass.respond_to?(method, include_private) ||
|
118
|
+
array_delegable?(method) ||
|
108
119
|
arel.respond_to?(method, include_private)
|
109
120
|
end
|
110
121
|
|
111
122
|
protected
|
112
123
|
|
124
|
+
def array_delegable?(method)
|
125
|
+
Array.method_defined?(method) && BLACKLISTED_ARRAY_METHODS.exclude?(method)
|
126
|
+
end
|
127
|
+
|
113
128
|
def method_missing(method, *args, &block)
|
114
129
|
if @klass.respond_to?(method)
|
115
|
-
scoping { @klass.
|
116
|
-
elsif
|
117
|
-
to_a.
|
130
|
+
scoping { @klass.public_send(method, *args, &block) }
|
131
|
+
elsif array_delegable?(method)
|
132
|
+
to_a.public_send(method, *args, &block)
|
118
133
|
elsif arel.respond_to?(method)
|
119
|
-
arel.
|
134
|
+
arel.public_send(method, *args, &block)
|
120
135
|
else
|
121
136
|
super
|
122
137
|
end
|