activerecord 5.2.0 → 5.2.8.1
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 +361 -0
- data/lib/active_record/association_relation.rb +3 -3
- data/lib/active_record/associations/alias_tracker.rb +1 -1
- data/lib/active_record/associations/association.rb +25 -10
- data/lib/active_record/associations/belongs_to_association.rb +14 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +4 -1
- data/lib/active_record/associations/builder/belongs_to.rb +11 -2
- data/lib/active_record/associations/builder/collection_association.rb +2 -2
- data/lib/active_record/associations/collection_association.rb +19 -15
- 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 +29 -12
- data/lib/active_record/associations/has_one_association.rb +8 -0
- data/lib/active_record/associations/has_one_through_association.rb +5 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +39 -24
- data/lib/active_record/associations/join_dependency/join_part.rb +7 -0
- data/lib/active_record/associations/join_dependency.rb +39 -64
- data/lib/active_record/associations/preloader.rb +1 -1
- data/lib/active_record/associations/singular_association.rb +4 -10
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +9 -9
- data/lib/active_record/attribute_methods/dirty.rb +15 -10
- data/lib/active_record/attribute_methods/read.rb +1 -1
- data/lib/active_record/autosave_association.rb +27 -8
- data/lib/active_record/callbacks.rb +4 -0
- data/lib/active_record/coders/yaml_column.rb +13 -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/quoting.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +7 -4
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +6 -15
- data/lib/active_record/connection_adapters/abstract/transaction.rb +23 -14
- data/lib/active_record/connection_adapters/abstract_adapter.rb +3 -1
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +18 -19
- 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/mysql/database_statements.rb +36 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +11 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -26
- 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 +5 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +3 -6
- data/lib/active_record/core.rb +12 -1
- data/lib/active_record/counter_cache.rb +17 -13
- data/lib/active_record/enum.rb +1 -0
- data/lib/active_record/errors.rb +18 -12
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/log_subscriber.rb +1 -1
- data/lib/active_record/migration/compatibility.rb +15 -15
- data/lib/active_record/migration.rb +1 -1
- data/lib/active_record/model_schema.rb +1 -1
- data/lib/active_record/persistence.rb +6 -5
- data/lib/active_record/query_cache.rb +4 -11
- data/lib/active_record/querying.rb +1 -1
- data/lib/active_record/railtie.rb +19 -3
- data/lib/active_record/reflection.rb +10 -14
- 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 +10 -8
- data/lib/active_record/relation/merger.rb +10 -11
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder.rb +20 -14
- data/lib/active_record/relation/query_attribute.rb +5 -3
- data/lib/active_record/relation/query_methods.rb +50 -22
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation.rb +39 -20
- 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/timestamp.rb +8 -1
- data/lib/active_record/transactions.rb +24 -21
- data/lib/active_record/type/serialized.rb +4 -0
- metadata +12 -13
@@ -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
|
|
@@ -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
|
@@ -373,13 +377,12 @@ module ActiveRecord
|
|
373
377
|
|
374
378
|
def construct_join_dependency
|
375
379
|
including = eager_load_values + includes_values
|
376
|
-
joins = joins_values.select { |join| join.is_a?(Arel::Nodes::Join) }
|
377
380
|
ActiveRecord::Associations::JoinDependency.new(
|
378
|
-
klass, table, including
|
381
|
+
klass, table, including
|
379
382
|
)
|
380
383
|
end
|
381
384
|
|
382
|
-
def apply_join_dependency(eager_loading:
|
385
|
+
def apply_join_dependency(eager_loading: group_values.empty?)
|
383
386
|
join_dependency = construct_join_dependency
|
384
387
|
relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
|
385
388
|
|
@@ -392,7 +395,6 @@ module ActiveRecord
|
|
392
395
|
end
|
393
396
|
|
394
397
|
if block_given?
|
395
|
-
relation._select!(join_dependency.aliases.columns)
|
396
398
|
yield relation, join_dependency
|
397
399
|
else
|
398
400
|
relation
|
@@ -419,7 +421,7 @@ module ActiveRecord
|
|
419
421
|
raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
|
420
422
|
|
421
423
|
expects_array = ids.first.kind_of?(Array)
|
422
|
-
return
|
424
|
+
return [] if expects_array && ids.first.empty?
|
423
425
|
|
424
426
|
ids = ids.flatten.compact.uniq
|
425
427
|
|
@@ -117,13 +117,11 @@ module ActiveRecord
|
|
117
117
|
if other.klass == relation.klass
|
118
118
|
relation.joins!(*other.joins_values)
|
119
119
|
else
|
120
|
-
alias_tracker = nil
|
121
120
|
joins_dependency = other.joins_values.map do |join|
|
122
121
|
case join
|
123
122
|
when Hash, Symbol, Array
|
124
|
-
alias_tracker ||= other.alias_tracker
|
125
123
|
ActiveRecord::Associations::JoinDependency.new(
|
126
|
-
other.klass, other.table, join
|
124
|
+
other.klass, other.table, join
|
127
125
|
)
|
128
126
|
else
|
129
127
|
join
|
@@ -140,13 +138,11 @@ module ActiveRecord
|
|
140
138
|
if other.klass == relation.klass
|
141
139
|
relation.left_outer_joins!(*other.left_outer_joins_values)
|
142
140
|
else
|
143
|
-
alias_tracker = nil
|
144
141
|
joins_dependency = other.left_outer_joins_values.map do |join|
|
145
142
|
case join
|
146
143
|
when Hash, Symbol, Array
|
147
|
-
alias_tracker ||= other.alias_tracker
|
148
144
|
ActiveRecord::Associations::JoinDependency.new(
|
149
|
-
other.klass, other.table, join
|
145
|
+
other.klass, other.table, join
|
150
146
|
)
|
151
147
|
else
|
152
148
|
join
|
@@ -160,10 +156,10 @@ module ActiveRecord
|
|
160
156
|
def merge_multi_values
|
161
157
|
if other.reordering_value
|
162
158
|
# override any order specified in the original relation
|
163
|
-
relation.reorder!
|
159
|
+
relation.reorder!(*other.order_values)
|
164
160
|
elsif other.order_values.any?
|
165
161
|
# merge in order_values from relation
|
166
|
-
relation.order!
|
162
|
+
relation.order!(*other.order_values)
|
167
163
|
end
|
168
164
|
|
169
165
|
extensions = other.extensions - relation.extensions
|
@@ -179,9 +175,7 @@ module ActiveRecord
|
|
179
175
|
end
|
180
176
|
|
181
177
|
def merge_clauses
|
182
|
-
|
183
|
-
relation.from_clause = other.from_clause
|
184
|
-
end
|
178
|
+
relation.from_clause = other.from_clause if replace_from_clause?
|
185
179
|
|
186
180
|
where_clause = relation.where_clause.merge(other.where_clause)
|
187
181
|
relation.where_clause = where_clause unless where_clause.empty?
|
@@ -189,6 +183,11 @@ module ActiveRecord
|
|
189
183
|
having_clause = relation.having_clause.merge(other.having_clause)
|
190
184
|
relation.having_clause = having_clause unless having_clause.empty?
|
191
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
|
192
191
|
end
|
193
192
|
end
|
194
193
|
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?
|
@@ -48,7 +48,12 @@ module ActiveRecord
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def build(attribute, value)
|
51
|
-
|
51
|
+
if table.type(attribute.name).force_equality?(value)
|
52
|
+
bind = build_bind_attribute(attribute.name, value)
|
53
|
+
attribute.eq(bind)
|
54
|
+
else
|
55
|
+
handler_for(value).call(attribute, value)
|
56
|
+
end
|
52
57
|
end
|
53
58
|
|
54
59
|
def build_bind_attribute(column_name, value)
|
@@ -88,20 +93,21 @@ module ActiveRecord
|
|
88
93
|
queries.reduce(&:or)
|
89
94
|
elsif table.aggregated_with?(key)
|
90
95
|
mapping = table.reflect_on_aggregation(key).mapping
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
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)
|
99
110
|
end
|
100
|
-
queries.reduce(&:or)
|
101
|
-
# FIXME: Deprecate this and provide a public API to force equality
|
102
|
-
elsif (value.is_a?(Range) || value.is_a?(Array)) &&
|
103
|
-
table.type(key.to_s).respond_to?(:subtype)
|
104
|
-
BasicObjectHandler.new(self).call(table.arel_attribute(key), value)
|
105
111
|
else
|
106
112
|
build(table.arel_attribute(key), value)
|
107
113
|
end
|
@@ -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
|
@@ -893,8 +890,8 @@ module ActiveRecord
|
|
893
890
|
self
|
894
891
|
end
|
895
892
|
|
896
|
-
def skip_query_cache! # :nodoc:
|
897
|
-
self.skip_query_cache_value =
|
893
|
+
def skip_query_cache!(value = true) # :nodoc:
|
894
|
+
self.skip_query_cache_value = value
|
898
895
|
self
|
899
896
|
end
|
900
897
|
|
@@ -903,11 +900,12 @@ module ActiveRecord
|
|
903
900
|
@arel ||= build_arel(aliases)
|
904
901
|
end
|
905
902
|
|
903
|
+
# Returns a relation value with a given name
|
904
|
+
def get_value(name) # :nodoc:
|
905
|
+
@values.fetch(name, DEFAULT_VALUES[name])
|
906
|
+
end
|
907
|
+
|
906
908
|
protected
|
907
|
-
# Returns a relation value with a given name
|
908
|
-
def get_value(name) # :nodoc:
|
909
|
-
@values.fetch(name, DEFAULT_VALUES[name])
|
910
|
-
end
|
911
909
|
|
912
910
|
# Sets the relation value with the given name
|
913
911
|
def set_value(name, value) # :nodoc:
|
@@ -1011,19 +1009,19 @@ module ActiveRecord
|
|
1011
1009
|
def build_join_query(manager, buckets, join_type, aliases)
|
1012
1010
|
buckets.default = []
|
1013
1011
|
|
1014
|
-
association_joins
|
1015
|
-
|
1016
|
-
join_nodes
|
1017
|
-
string_joins
|
1012
|
+
association_joins = buckets[:association_join]
|
1013
|
+
stashed_joins = buckets[:stashed_join]
|
1014
|
+
join_nodes = buckets[:join_node].uniq
|
1015
|
+
string_joins = buckets[:string_join].map(&:strip).uniq
|
1018
1016
|
|
1019
1017
|
join_list = join_nodes + convert_join_strings_to_ast(string_joins)
|
1020
1018
|
alias_tracker = alias_tracker(join_list, aliases)
|
1021
1019
|
|
1022
1020
|
join_dependency = ActiveRecord::Associations::JoinDependency.new(
|
1023
|
-
klass, table, association_joins
|
1021
|
+
klass, table, association_joins
|
1024
1022
|
)
|
1025
1023
|
|
1026
|
-
joins = join_dependency.join_constraints(
|
1024
|
+
joins = join_dependency.join_constraints(stashed_joins, join_type, alias_tracker)
|
1027
1025
|
joins.each { |join| manager.from(join) }
|
1028
1026
|
|
1029
1027
|
manager.join_sources.concat(join_list)
|
@@ -1049,17 +1047,37 @@ module ActiveRecord
|
|
1049
1047
|
end
|
1050
1048
|
|
1051
1049
|
def arel_columns(columns)
|
1052
|
-
columns.
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1050
|
+
columns.flat_map do |field|
|
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
|
+
field.call
|
1057
1060
|
else
|
1058
1061
|
field
|
1059
1062
|
end
|
1060
1063
|
end
|
1061
1064
|
end
|
1062
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
|
+
|
1063
1081
|
def reverse_sql_order(order_query)
|
1064
1082
|
if order_query.empty?
|
1065
1083
|
return [arel_attribute(primary_key).desc] if primary_key
|
@@ -1141,14 +1159,14 @@ module ActiveRecord
|
|
1141
1159
|
order_args.map! do |arg|
|
1142
1160
|
case arg
|
1143
1161
|
when Symbol
|
1144
|
-
|
1162
|
+
order_column(arg.to_s).asc
|
1145
1163
|
when Hash
|
1146
1164
|
arg.map { |field, dir|
|
1147
1165
|
case field
|
1148
1166
|
when Arel::Nodes::SqlLiteral
|
1149
1167
|
field.send(dir.downcase)
|
1150
1168
|
else
|
1151
|
-
|
1169
|
+
order_column(field.to_s).send(dir.downcase)
|
1152
1170
|
end
|
1153
1171
|
}
|
1154
1172
|
else
|
@@ -1157,6 +1175,16 @@ module ActiveRecord
|
|
1157
1175
|
end.flatten!
|
1158
1176
|
end
|
1159
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
|
+
|
1160
1188
|
# Checks to make sure that the arguments are not blank. Note that if some
|
1161
1189
|
# blank-like object were initially passed into the query method, then this
|
1162
1190
|
# method will not raise an error.
|
@@ -8,7 +8,7 @@ module ActiveRecord
|
|
8
8
|
module SpawnMethods
|
9
9
|
# This is overridden by Associations::CollectionProxy
|
10
10
|
def spawn #:nodoc:
|
11
|
-
clone
|
11
|
+
@delegate_to_klass ? klass.all : clone
|
12
12
|
end
|
13
13
|
|
14
14
|
# Merges in the conditions from <tt>other</tt>, if <tt>other</tt> is an ActiveRecord::Relation.
|
@@ -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
|
|
@@ -277,10 +277,10 @@ module ActiveRecord
|
|
277
277
|
# Please check unscoped if you want to remove all previous scopes (including
|
278
278
|
# the default_scope) during the execution of a block.
|
279
279
|
def scoping
|
280
|
-
previous, klass.current_scope = klass.current_scope(true), self
|
280
|
+
previous, klass.current_scope = klass.current_scope(true), self unless @delegate_to_klass
|
281
281
|
yield
|
282
282
|
ensure
|
283
|
-
klass.current_scope = previous
|
283
|
+
klass.current_scope = previous unless @delegate_to_klass
|
284
284
|
end
|
285
285
|
|
286
286
|
def _exec_scope(*args, &block) # :nodoc:
|
@@ -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).
|
@@ -436,17 +444,16 @@ module ActiveRecord
|
|
436
444
|
# # => SELECT "users".* FROM "users" WHERE "users"."name" = 'Oscar'
|
437
445
|
def to_sql
|
438
446
|
@to_sql ||= begin
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
end
|
447
|
+
if eager_loading?
|
448
|
+
apply_join_dependency do |relation, join_dependency|
|
449
|
+
relation = join_dependency.apply_column_aliases(relation)
|
450
|
+
relation.to_sql
|
451
|
+
end
|
452
|
+
else
|
453
|
+
conn = klass.connection
|
454
|
+
conn.unprepared_statement { conn.to_sql(arel) }
|
455
|
+
end
|
456
|
+
end
|
450
457
|
end
|
451
458
|
|
452
459
|
# Returns a hash of where conditions.
|
@@ -457,10 +464,8 @@ module ActiveRecord
|
|
457
464
|
where_clause.to_h(relation_table_name)
|
458
465
|
end
|
459
466
|
|
460
|
-
def scope_for_create
|
461
|
-
|
462
|
-
scope.merge!(attributes) if attributes
|
463
|
-
scope
|
467
|
+
def scope_for_create
|
468
|
+
where_values_hash.merge!(create_with_value.stringify_keys)
|
464
469
|
end
|
465
470
|
|
466
471
|
# Returns true if relation needs eager loading.
|
@@ -546,6 +551,7 @@ module ActiveRecord
|
|
546
551
|
if ActiveRecord::NullRelation === relation
|
547
552
|
[]
|
548
553
|
else
|
554
|
+
relation = join_dependency.apply_column_aliases(relation)
|
549
555
|
rows = connection.select_all(relation.arel, "SQL")
|
550
556
|
join_dependency.instantiate(rows, &block)
|
551
557
|
end.freeze
|
@@ -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
|
@@ -86,8 +86,8 @@ module ActiveRecord
|
|
86
86
|
# # Should return a scope, you can call 'super' here etc.
|
87
87
|
# end
|
88
88
|
# end
|
89
|
-
def default_scope(scope = nil) # :doc:
|
90
|
-
scope =
|
89
|
+
def default_scope(scope = nil, &block) # :doc:
|
90
|
+
scope = block if block_given?
|
91
91
|
|
92
92
|
if scope.is_a?(Relation) || !scope.respond_to?(:call)
|
93
93
|
raise ArgumentError,
|
@@ -87,8 +87,8 @@ module ActiveRecord
|
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
|
-
def self.create(connection,
|
91
|
-
relation = block.call Params.new
|
90
|
+
def self.create(connection, callable = nil, &block)
|
91
|
+
relation = (callable || block).call Params.new
|
92
92
|
query_builder, binds = connection.cacheable_query(self, relation.arel)
|
93
93
|
bind_map = BindMap.new(binds)
|
94
94
|
new(query_builder, bind_map, relation.klass)
|