activerecord 5.2.1 → 5.2.5
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 +228 -0
- data/lib/active_record/association_relation.rb +3 -3
- data/lib/active_record/associations/association.rb +8 -0
- data/lib/active_record/associations/builder/collection_association.rb +2 -2
- data/lib/active_record/associations/collection_association.rb +9 -8
- data/lib/active_record/associations/collection_proxy.rb +8 -34
- data/lib/active_record/associations/has_many_association.rb +9 -0
- data/lib/active_record/associations/has_many_through_association.rb +28 -11
- data/lib/active_record/associations/join_dependency/join_association.rb +28 -7
- data/lib/active_record/associations/preloader.rb +1 -1
- data/lib/active_record/attribute_methods/dirty.rb +13 -8
- data/lib/active_record/autosave_association.rb +25 -11
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/collection_cache_key.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +36 -11
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +19 -6
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +8 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +3 -3
- data/lib/active_record/connection_adapters/abstract_adapter.rb +3 -1
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +18 -8
- data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +7 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +10 -24
- data/lib/active_record/connection_adapters/postgresql/utils.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +9 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +4 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +3 -3
- data/lib/active_record/core.rb +2 -1
- data/lib/active_record/enum.rb +1 -0
- data/lib/active_record/errors.rb +18 -12
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/migration.rb +1 -1
- data/lib/active_record/migration/compatibility.rb +15 -15
- data/lib/active_record/model_schema.rb +1 -1
- data/lib/active_record/persistence.rb +5 -4
- data/lib/active_record/querying.rb +1 -1
- data/lib/active_record/railtie.rb +1 -3
- data/lib/active_record/reflection.rb +10 -14
- data/lib/active_record/relation.rb +26 -7
- data/lib/active_record/relation/calculations.rb +16 -12
- data/lib/active_record/relation/delegation.rb +30 -0
- data/lib/active_record/relation/finder_methods.rb +8 -4
- data/lib/active_record/relation/merger.rb +8 -5
- data/lib/active_record/relation/predicate_builder.rb +14 -9
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/query_attribute.rb +5 -3
- data/lib/active_record/relation/query_methods.rb +35 -10
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/scoping/default.rb +2 -2
- data/lib/active_record/scoping/named.rb +2 -0
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/tasks/database_tasks.rb +1 -1
- data/lib/active_record/transactions.rb +1 -1
- metadata +9 -10
@@ -375,7 +375,7 @@ module ActiveRecord
|
|
375
375
|
# default values when instantiating the Active Record object for this table.
|
376
376
|
def column_defaults
|
377
377
|
load_schema
|
378
|
-
@column_defaults ||= _default_attributes.to_hash
|
378
|
+
@column_defaults ||= _default_attributes.deep_dup.to_hash
|
379
379
|
end
|
380
380
|
|
381
381
|
def _default_attributes # :nodoc:
|
@@ -473,15 +473,16 @@ module ActiveRecord
|
|
473
473
|
verify_readonly_attribute(key.to_s)
|
474
474
|
end
|
475
475
|
|
476
|
+
id_in_database = self.id_in_database
|
477
|
+
attributes.each do |k, v|
|
478
|
+
write_attribute_without_type_cast(k, v)
|
479
|
+
end
|
480
|
+
|
476
481
|
affected_rows = self.class._update_record(
|
477
482
|
attributes,
|
478
483
|
self.class.primary_key => id_in_database
|
479
484
|
)
|
480
485
|
|
481
|
-
attributes.each do |k, v|
|
482
|
-
write_attribute_without_type_cast(k, v)
|
483
|
-
end
|
484
|
-
|
485
486
|
affected_rows == 1
|
486
487
|
end
|
487
488
|
|
@@ -40,7 +40,7 @@ module ActiveRecord
|
|
40
40
|
def find_by_sql(sql, binds = [], preparable: nil, &block)
|
41
41
|
result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable)
|
42
42
|
column_types = result_set.column_types.dup
|
43
|
-
|
43
|
+
attribute_types.each_key { |k| column_types.delete k }
|
44
44
|
message_bus = ActiveSupport::Notifications.instrumenter
|
45
45
|
|
46
46
|
payload = {
|
@@ -169,9 +169,7 @@ end_warning
|
|
169
169
|
end
|
170
170
|
|
171
171
|
initializer "active_record.set_executor_hooks" do
|
172
|
-
|
173
|
-
ActiveRecord::QueryCache.install_executor_hooks
|
174
|
-
end
|
172
|
+
ActiveRecord::QueryCache.install_executor_hooks
|
175
173
|
end
|
176
174
|
|
177
175
|
initializer "active_record.add_watchable_files" do |app|
|
@@ -174,28 +174,24 @@ module ActiveRecord
|
|
174
174
|
scope ? [scope] : []
|
175
175
|
end
|
176
176
|
|
177
|
-
def
|
178
|
-
key = join_keys.key
|
179
|
-
foreign_key = join_keys.foreign_key
|
180
|
-
|
181
|
-
constraint = table[key].eq(foreign_table[foreign_key])
|
182
|
-
|
183
|
-
if klass.finder_needs_type_condition?
|
184
|
-
table.create_and([constraint, klass.send(:type_condition, table)])
|
185
|
-
else
|
186
|
-
constraint
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
def join_scope(table, foreign_klass)
|
177
|
+
def join_scope(table, foreign_table, foreign_klass)
|
191
178
|
predicate_builder = predicate_builder(table)
|
192
179
|
scope_chain_items = join_scopes(table, predicate_builder)
|
193
180
|
klass_scope = klass_join_scope(table, predicate_builder)
|
194
181
|
|
182
|
+
key = join_keys.key
|
183
|
+
foreign_key = join_keys.foreign_key
|
184
|
+
|
185
|
+
klass_scope.where!(table[key].eq(foreign_table[foreign_key]))
|
186
|
+
|
195
187
|
if type
|
196
188
|
klass_scope.where!(type => foreign_klass.polymorphic_name)
|
197
189
|
end
|
198
190
|
|
191
|
+
if klass.finder_needs_type_condition?
|
192
|
+
klass_scope.where!(klass.send(:type_condition, table))
|
193
|
+
end
|
194
|
+
|
199
195
|
scope_chain_items.inject(klass_scope, &:merge!)
|
200
196
|
end
|
201
197
|
|
@@ -54,7 +54,7 @@ module ActiveRecord
|
|
54
54
|
# user = users.new { |user| user.name = 'Oscar' }
|
55
55
|
# user.name # => Oscar
|
56
56
|
def new(attributes = nil, &block)
|
57
|
-
scoping { klass.new(
|
57
|
+
scoping { klass.new(values_for_create(attributes), &block) }
|
58
58
|
end
|
59
59
|
|
60
60
|
alias build new
|
@@ -82,7 +82,7 @@ module ActiveRecord
|
|
82
82
|
if attributes.is_a?(Array)
|
83
83
|
attributes.collect { |attr| create(attr, &block) }
|
84
84
|
else
|
85
|
-
scoping { klass.create(
|
85
|
+
scoping { klass.create(values_for_create(attributes), &block) }
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
@@ -96,7 +96,7 @@ module ActiveRecord
|
|
96
96
|
if attributes.is_a?(Array)
|
97
97
|
attributes.collect { |attr| create!(attr, &block) }
|
98
98
|
else
|
99
|
-
scoping { klass.create!(
|
99
|
+
scoping { klass.create!(values_for_create(attributes), &block) }
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
@@ -337,6 +337,14 @@ module ActiveRecord
|
|
337
337
|
@klass.connection.update stmt, "#{@klass} Update All"
|
338
338
|
end
|
339
339
|
|
340
|
+
def update(id = :all, attributes) # :nodoc:
|
341
|
+
if id == :all
|
342
|
+
each { |record| record.update(attributes) }
|
343
|
+
else
|
344
|
+
klass.update(id, attributes)
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
340
348
|
# Destroys the records by instantiating each
|
341
349
|
# record and calling its {#destroy}[rdoc-ref:Persistence#destroy] method.
|
342
350
|
# Each object's callbacks are executed (including <tt>:dependent</tt> association options).
|
@@ -456,10 +464,8 @@ module ActiveRecord
|
|
456
464
|
where_clause.to_h(relation_table_name)
|
457
465
|
end
|
458
466
|
|
459
|
-
def scope_for_create
|
460
|
-
|
461
|
-
scope.merge!(attributes) if attributes
|
462
|
-
scope
|
467
|
+
def scope_for_create
|
468
|
+
where_values_hash.merge!(create_with_value.stringify_keys)
|
463
469
|
end
|
464
470
|
|
465
471
|
# Returns true if relation needs eager loading.
|
@@ -606,5 +612,18 @@ module ActiveRecord
|
|
606
612
|
# ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
|
607
613
|
string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map(&:downcase).uniq - ["raw_sql_"]
|
608
614
|
end
|
615
|
+
|
616
|
+
def values_for_create(attributes = nil)
|
617
|
+
result = attributes ? where_values_hash.merge!(attributes) : where_values_hash
|
618
|
+
|
619
|
+
# NOTE: if there are same keys in both create_with and result, create_with should be used.
|
620
|
+
# This is to make sure nested attributes don't get passed to the klass.new,
|
621
|
+
# while keeping the precedence of the duplicate keys in create_with.
|
622
|
+
create_with_value.stringify_keys.each do |k, v|
|
623
|
+
result[k] = v if result.key?(k)
|
624
|
+
end
|
625
|
+
|
626
|
+
result
|
627
|
+
end
|
609
628
|
end
|
610
629
|
end
|
@@ -133,11 +133,12 @@ module ActiveRecord
|
|
133
133
|
relation = apply_join_dependency
|
134
134
|
|
135
135
|
if operation.to_s.downcase == "count"
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
relation.order_values = []
|
136
|
+
unless distinct_value || distinct_select?(column_name || select_for_count)
|
137
|
+
relation.distinct!
|
138
|
+
relation.select_values = [ klass.primary_key || table[Arel.star] ]
|
140
139
|
end
|
140
|
+
# PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
|
141
|
+
relation.order_values = []
|
141
142
|
end
|
142
143
|
|
143
144
|
relation.calculate(operation, column_name)
|
@@ -190,11 +191,9 @@ module ActiveRecord
|
|
190
191
|
relation = apply_join_dependency
|
191
192
|
relation.pluck(*column_names)
|
192
193
|
else
|
193
|
-
enforce_raw_sql_whitelist(column_names)
|
194
|
+
klass.enforce_raw_sql_whitelist(column_names)
|
194
195
|
relation = spawn
|
195
|
-
relation.select_values = column_names
|
196
|
-
@klass.has_attribute?(cn) || @klass.attribute_alias?(cn) ? arel_attribute(cn) : cn
|
197
|
-
}
|
196
|
+
relation.select_values = column_names
|
198
197
|
result = skip_query_cache_if_necessary { klass.connection.select_all(relation.arel, nil) }
|
199
198
|
result.cast_values(klass.attribute_types)
|
200
199
|
end
|
@@ -209,7 +208,6 @@ module ActiveRecord
|
|
209
208
|
end
|
210
209
|
|
211
210
|
private
|
212
|
-
|
213
211
|
def has_include?(column_name)
|
214
212
|
eager_loading? || (includes_values.present? && column_name && column_name != :all)
|
215
213
|
end
|
@@ -224,10 +222,12 @@ module ActiveRecord
|
|
224
222
|
if operation == "count"
|
225
223
|
column_name ||= select_for_count
|
226
224
|
if column_name == :all
|
227
|
-
if distinct
|
225
|
+
if !distinct
|
226
|
+
distinct = distinct_select?(select_for_count) if group_values.empty?
|
227
|
+
elsif group_values.any? || select_values.empty? && order_values.empty?
|
228
228
|
column_name = primary_key
|
229
229
|
end
|
230
|
-
elsif column_name
|
230
|
+
elsif distinct_select?(column_name)
|
231
231
|
distinct = nil
|
232
232
|
end
|
233
233
|
end
|
@@ -239,6 +239,10 @@ module ActiveRecord
|
|
239
239
|
end
|
240
240
|
end
|
241
241
|
|
242
|
+
def distinct_select?(column_name)
|
243
|
+
column_name.is_a?(::String) && /\bDISTINCT[\s(]/i.match?(column_name)
|
244
|
+
end
|
245
|
+
|
242
246
|
def aggregate_column(column_name)
|
243
247
|
return column_name if Arel::Expressions === column_name
|
244
248
|
|
@@ -383,7 +387,7 @@ module ActiveRecord
|
|
383
387
|
case operation
|
384
388
|
when "count" then value.to_i
|
385
389
|
when "sum" then type.deserialize(value || 0)
|
386
|
-
when "average" then value.respond_to?(:to_d) ? value.to_d : value
|
390
|
+
when "average" then value && value.respond_to?(:to_d) ? value.to_d : value
|
387
391
|
else type.deserialize(value)
|
388
392
|
end
|
389
393
|
end
|
@@ -17,6 +17,7 @@ module ActiveRecord
|
|
17
17
|
delegate = Class.new(klass) {
|
18
18
|
include ClassSpecificRelation
|
19
19
|
}
|
20
|
+
include_relation_methods(delegate)
|
20
21
|
mangled_name = klass.name.gsub("::".freeze, "_".freeze)
|
21
22
|
const_set mangled_name, delegate
|
22
23
|
private_constant mangled_name
|
@@ -29,6 +30,35 @@ module ActiveRecord
|
|
29
30
|
child_class.initialize_relation_delegate_cache
|
30
31
|
super
|
31
32
|
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
def include_relation_methods(delegate)
|
36
|
+
superclass.include_relation_methods(delegate) unless base_class == self
|
37
|
+
delegate.include generated_relation_methods
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def generated_relation_methods
|
42
|
+
@generated_relation_methods ||= Module.new.tap do |mod|
|
43
|
+
mod_name = "GeneratedRelationMethods"
|
44
|
+
const_set mod_name, mod
|
45
|
+
private_constant mod_name
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def generate_relation_method(method)
|
50
|
+
if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method)
|
51
|
+
generated_relation_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
52
|
+
def #{method}(*args, &block)
|
53
|
+
scoping { klass.#{method}(*args, &block) }
|
54
|
+
end
|
55
|
+
RUBY
|
56
|
+
else
|
57
|
+
generated_relation_methods.send(:define_method, method) do |*args, &block|
|
58
|
+
scoping { klass.public_send(method, *args, &block) }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
32
62
|
end
|
33
63
|
|
34
64
|
extend ActiveSupport::Concern
|
@@ -319,7 +319,7 @@ module ActiveRecord
|
|
319
319
|
|
320
320
|
relation = construct_relation_for_exists(conditions)
|
321
321
|
|
322
|
-
skip_query_cache_if_necessary { connection.
|
322
|
+
skip_query_cache_if_necessary { connection.select_one(relation.arel, "#{name} Exists") } ? true : false
|
323
323
|
rescue ::RangeError
|
324
324
|
false
|
325
325
|
end
|
@@ -359,11 +359,15 @@ module ActiveRecord
|
|
359
359
|
end
|
360
360
|
|
361
361
|
def construct_relation_for_exists(conditions)
|
362
|
-
|
362
|
+
if distinct_value && offset_value
|
363
|
+
relation = except(:order).limit!(1)
|
364
|
+
else
|
365
|
+
relation = except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
|
366
|
+
end
|
363
367
|
|
364
368
|
case conditions
|
365
369
|
when Array, Hash
|
366
|
-
relation.where!(conditions)
|
370
|
+
relation.where!(conditions) unless conditions.empty?
|
367
371
|
else
|
368
372
|
relation.where!(primary_key => conditions) unless conditions == :none
|
369
373
|
end
|
@@ -417,7 +421,7 @@ module ActiveRecord
|
|
417
421
|
raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
|
418
422
|
|
419
423
|
expects_array = ids.first.kind_of?(Array)
|
420
|
-
return
|
424
|
+
return [] if expects_array && ids.first.empty?
|
421
425
|
|
422
426
|
ids = ids.flatten.compact.uniq
|
423
427
|
|
@@ -156,10 +156,10 @@ module ActiveRecord
|
|
156
156
|
def merge_multi_values
|
157
157
|
if other.reordering_value
|
158
158
|
# override any order specified in the original relation
|
159
|
-
relation.reorder!
|
159
|
+
relation.reorder!(*other.order_values)
|
160
160
|
elsif other.order_values.any?
|
161
161
|
# merge in order_values from relation
|
162
|
-
relation.order!
|
162
|
+
relation.order!(*other.order_values)
|
163
163
|
end
|
164
164
|
|
165
165
|
extensions = other.extensions - relation.extensions
|
@@ -175,9 +175,7 @@ module ActiveRecord
|
|
175
175
|
end
|
176
176
|
|
177
177
|
def merge_clauses
|
178
|
-
|
179
|
-
relation.from_clause = other.from_clause
|
180
|
-
end
|
178
|
+
relation.from_clause = other.from_clause if replace_from_clause?
|
181
179
|
|
182
180
|
where_clause = relation.where_clause.merge(other.where_clause)
|
183
181
|
relation.where_clause = where_clause unless where_clause.empty?
|
@@ -185,6 +183,11 @@ module ActiveRecord
|
|
185
183
|
having_clause = relation.having_clause.merge(other.having_clause)
|
186
184
|
relation.having_clause = having_clause unless having_clause.empty?
|
187
185
|
end
|
186
|
+
|
187
|
+
def replace_from_clause?
|
188
|
+
relation.from_clause.empty? && !other.from_clause.empty? &&
|
189
|
+
relation.klass.base_class == other.klass.base_class
|
190
|
+
end
|
188
191
|
end
|
189
192
|
end
|
190
193
|
end
|
@@ -93,16 +93,21 @@ module ActiveRecord
|
|
93
93
|
queries.reduce(&:or)
|
94
94
|
elsif table.aggregated_with?(key)
|
95
95
|
mapping = table.reflect_on_aggregation(key).mapping
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
96
|
+
values = value.nil? ? [nil] : Array.wrap(value)
|
97
|
+
if mapping.length == 1 || values.empty?
|
98
|
+
column_name, aggr_attr = mapping.first
|
99
|
+
values = values.map do |object|
|
100
|
+
object.respond_to?(aggr_attr) ? object.public_send(aggr_attr) : object
|
101
|
+
end
|
102
|
+
build(table.arel_attribute(column_name), values)
|
103
|
+
else
|
104
|
+
queries = values.map do |object|
|
105
|
+
mapping.map do |field_attr, aggregate_attr|
|
106
|
+
build(table.arel_attribute(field_attr), object.try!(aggregate_attr))
|
107
|
+
end.reduce(&:and)
|
108
|
+
end
|
109
|
+
queries.reduce(&:or)
|
104
110
|
end
|
105
|
-
queries.reduce(&:or)
|
106
111
|
else
|
107
112
|
build(table.arel_attribute(key), value)
|
108
113
|
end
|
@@ -19,10 +19,10 @@ module ActiveRecord
|
|
19
19
|
when 0 then NullPredicate
|
20
20
|
when 1 then predicate_builder.build(attribute, values.first)
|
21
21
|
else
|
22
|
-
|
22
|
+
values.map! do |v|
|
23
23
|
predicate_builder.build_bind_attribute(attribute.name, v)
|
24
24
|
end
|
25
|
-
attribute.in(
|
25
|
+
values.empty? ? NullPredicate : attribute.in(values)
|
26
26
|
end
|
27
27
|
|
28
28
|
unless nils.empty?
|
@@ -18,13 +18,15 @@ module ActiveRecord
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def nil?
|
21
|
-
|
22
|
-
|
21
|
+
unless value_before_type_cast.is_a?(StatementCache::Substitute)
|
22
|
+
value_before_type_cast.nil? ||
|
23
|
+
type.respond_to?(:subtype, true) && value_for_database.nil?
|
24
|
+
end
|
23
25
|
end
|
24
26
|
|
25
27
|
def boundable?
|
26
28
|
return @_boundable if defined?(@_boundable)
|
27
|
-
|
29
|
+
value_for_database unless value_before_type_cast.is_a?(StatementCache::Substitute)
|
28
30
|
@_boundable = true
|
29
31
|
rescue ::RangeError
|
30
32
|
@_boundable = false
|
@@ -232,9 +232,6 @@ module ActiveRecord
|
|
232
232
|
|
233
233
|
def _select!(*fields) # :nodoc:
|
234
234
|
fields.flatten!
|
235
|
-
fields.map! do |field|
|
236
|
-
klass.attribute_alias?(field) ? klass.attribute_alias(field).to_sym : field
|
237
|
-
end
|
238
235
|
self.select_values += fields
|
239
236
|
self
|
240
237
|
end
|
@@ -1051,11 +1048,14 @@ module ActiveRecord
|
|
1051
1048
|
|
1052
1049
|
def arel_columns(columns)
|
1053
1050
|
columns.flat_map do |field|
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1051
|
+
case field
|
1052
|
+
when Symbol
|
1053
|
+
arel_column(field.to_s) do |attr_name|
|
1054
|
+
connection.quote_table_name(attr_name)
|
1055
|
+
end
|
1056
|
+
when String
|
1057
|
+
arel_column(field, &:itself)
|
1058
|
+
when Proc
|
1059
1059
|
field.call
|
1060
1060
|
else
|
1061
1061
|
field
|
@@ -1063,6 +1063,21 @@ module ActiveRecord
|
|
1063
1063
|
end
|
1064
1064
|
end
|
1065
1065
|
|
1066
|
+
def arel_column(field)
|
1067
|
+
field = klass.attribute_alias(field) if klass.attribute_alias?(field)
|
1068
|
+
from = from_clause.name || from_clause.value
|
1069
|
+
|
1070
|
+
if klass.columns_hash.key?(field) && (!from || table_name_matches?(from))
|
1071
|
+
arel_attribute(field)
|
1072
|
+
else
|
1073
|
+
yield field
|
1074
|
+
end
|
1075
|
+
end
|
1076
|
+
|
1077
|
+
def table_name_matches?(from)
|
1078
|
+
/(?:\A|(?<!FROM)\s)(?:\b#{table.name}\b|#{connection.quote_table_name(table.name)})(?!\.)/i.match?(from.to_s)
|
1079
|
+
end
|
1080
|
+
|
1066
1081
|
def reverse_sql_order(order_query)
|
1067
1082
|
if order_query.empty?
|
1068
1083
|
return [arel_attribute(primary_key).desc] if primary_key
|
@@ -1144,14 +1159,14 @@ module ActiveRecord
|
|
1144
1159
|
order_args.map! do |arg|
|
1145
1160
|
case arg
|
1146
1161
|
when Symbol
|
1147
|
-
|
1162
|
+
order_column(arg.to_s).asc
|
1148
1163
|
when Hash
|
1149
1164
|
arg.map { |field, dir|
|
1150
1165
|
case field
|
1151
1166
|
when Arel::Nodes::SqlLiteral
|
1152
1167
|
field.send(dir.downcase)
|
1153
1168
|
else
|
1154
|
-
|
1169
|
+
order_column(field.to_s).send(dir.downcase)
|
1155
1170
|
end
|
1156
1171
|
}
|
1157
1172
|
else
|
@@ -1160,6 +1175,16 @@ module ActiveRecord
|
|
1160
1175
|
end.flatten!
|
1161
1176
|
end
|
1162
1177
|
|
1178
|
+
def order_column(field)
|
1179
|
+
arel_column(field) do |attr_name|
|
1180
|
+
if attr_name == "count" && !group_values.empty?
|
1181
|
+
arel_attribute(attr_name)
|
1182
|
+
else
|
1183
|
+
Arel.sql(connection.quote_table_name(attr_name))
|
1184
|
+
end
|
1185
|
+
end
|
1186
|
+
end
|
1187
|
+
|
1163
1188
|
# Checks to make sure that the arguments are not blank. Note that if some
|
1164
1189
|
# blank-like object were initially passed into the query method, then this
|
1165
1190
|
# method will not raise an error.
|