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.

Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +361 -0
  3. data/lib/active_record/association_relation.rb +3 -3
  4. data/lib/active_record/associations/alias_tracker.rb +1 -1
  5. data/lib/active_record/associations/association.rb +25 -10
  6. data/lib/active_record/associations/belongs_to_association.rb +14 -5
  7. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +4 -1
  8. data/lib/active_record/associations/builder/belongs_to.rb +11 -2
  9. data/lib/active_record/associations/builder/collection_association.rb +2 -2
  10. data/lib/active_record/associations/collection_association.rb +19 -15
  11. data/lib/active_record/associations/collection_proxy.rb +8 -34
  12. data/lib/active_record/associations/has_many_association.rb +9 -0
  13. data/lib/active_record/associations/has_many_through_association.rb +29 -12
  14. data/lib/active_record/associations/has_one_association.rb +8 -0
  15. data/lib/active_record/associations/has_one_through_association.rb +5 -1
  16. data/lib/active_record/associations/join_dependency/join_association.rb +39 -24
  17. data/lib/active_record/associations/join_dependency/join_part.rb +7 -0
  18. data/lib/active_record/associations/join_dependency.rb +39 -64
  19. data/lib/active_record/associations/preloader.rb +1 -1
  20. data/lib/active_record/associations/singular_association.rb +4 -10
  21. data/lib/active_record/associations/through_association.rb +1 -1
  22. data/lib/active_record/associations.rb +9 -9
  23. data/lib/active_record/attribute_methods/dirty.rb +15 -10
  24. data/lib/active_record/attribute_methods/read.rb +1 -1
  25. data/lib/active_record/autosave_association.rb +27 -8
  26. data/lib/active_record/callbacks.rb +4 -0
  27. data/lib/active_record/coders/yaml_column.rb +13 -1
  28. data/lib/active_record/collection_cache_key.rb +2 -2
  29. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +36 -11
  30. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
  31. data/lib/active_record/connection_adapters/abstract/database_statements.rb +19 -6
  32. data/lib/active_record/connection_adapters/abstract/query_cache.rb +8 -3
  33. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -0
  34. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +7 -4
  35. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +6 -15
  36. data/lib/active_record/connection_adapters/abstract/transaction.rb +23 -14
  37. data/lib/active_record/connection_adapters/abstract_adapter.rb +3 -1
  38. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +18 -19
  39. data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
  40. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +11 -2
  41. data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -0
  42. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +2 -2
  43. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +11 -1
  44. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  45. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -0
  46. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +36 -0
  47. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -26
  48. data/lib/active_record/connection_adapters/postgresql/utils.rb +1 -1
  49. data/lib/active_record/connection_adapters/postgresql_adapter.rb +9 -1
  50. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +5 -0
  51. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +5 -1
  52. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +3 -6
  53. data/lib/active_record/core.rb +12 -1
  54. data/lib/active_record/counter_cache.rb +17 -13
  55. data/lib/active_record/enum.rb +1 -0
  56. data/lib/active_record/errors.rb +18 -12
  57. data/lib/active_record/gem_version.rb +2 -2
  58. data/lib/active_record/log_subscriber.rb +1 -1
  59. data/lib/active_record/migration/compatibility.rb +15 -15
  60. data/lib/active_record/migration.rb +1 -1
  61. data/lib/active_record/model_schema.rb +1 -1
  62. data/lib/active_record/persistence.rb +6 -5
  63. data/lib/active_record/query_cache.rb +4 -11
  64. data/lib/active_record/querying.rb +1 -1
  65. data/lib/active_record/railtie.rb +19 -3
  66. data/lib/active_record/reflection.rb +10 -14
  67. data/lib/active_record/relation/calculations.rb +16 -12
  68. data/lib/active_record/relation/delegation.rb +30 -0
  69. data/lib/active_record/relation/finder_methods.rb +10 -8
  70. data/lib/active_record/relation/merger.rb +10 -11
  71. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  72. data/lib/active_record/relation/predicate_builder.rb +20 -14
  73. data/lib/active_record/relation/query_attribute.rb +5 -3
  74. data/lib/active_record/relation/query_methods.rb +50 -22
  75. data/lib/active_record/relation/spawn_methods.rb +1 -1
  76. data/lib/active_record/relation.rb +39 -20
  77. data/lib/active_record/scoping/default.rb +2 -2
  78. data/lib/active_record/scoping/named.rb +2 -0
  79. data/lib/active_record/statement_cache.rb +2 -2
  80. data/lib/active_record/tasks/database_tasks.rb +1 -1
  81. data/lib/active_record/timestamp.rb +8 -1
  82. data/lib/active_record/transactions.rb +24 -21
  83. data/lib/active_record/type/serialized.rb +4 -0
  84. metadata +12 -13
@@ -174,28 +174,24 @@ module ActiveRecord
174
174
  scope ? [scope] : []
175
175
  end
176
176
 
177
- def build_join_constraint(table, foreign_table)
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
- relation.distinct!
137
- # PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
138
- if (column_name == :all || column_name.nil?) && select_values.empty?
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.map { |cn|
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 && (group_values.any? || select_values.empty? && order_values.empty?)
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 =~ /\s*DISTINCT[\s(]+/i
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.select_value(relation.arel, "#{name} Exists") } ? true : false
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
- relation = except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
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, alias_tracker(joins)
381
+ klass, table, including
379
382
  )
380
383
  end
381
384
 
382
- def apply_join_dependency(eager_loading: true)
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 ids.first if expects_array && ids.first.empty?
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, alias_tracker
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, alias_tracker
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! other.order_values
159
+ relation.reorder!(*other.order_values)
164
160
  elsif other.order_values.any?
165
161
  # merge in order_values from relation
166
- relation.order! other.order_values
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
- if relation.from_clause.empty? && !other.from_clause.empty?
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
- bind_values = values.map do |v|
22
+ values.map! do |v|
23
23
  predicate_builder.build_bind_attribute(attribute.name, v)
24
24
  end
25
- attribute.in(bind_values)
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
- handler_for(value).call(attribute, value)
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
- queries = Array.wrap(value).map do |object|
92
- mapping.map do |field_attr, aggregate_attr|
93
- if mapping.size == 1 && !object.respond_to?(aggregate_attr)
94
- build(table.arel_attribute(field_attr), object)
95
- else
96
- build(table.arel_attribute(field_attr), object.send(aggregate_attr))
97
- end
98
- end.reduce(&:and)
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
- !value_before_type_cast.is_a?(StatementCache::Substitute) &&
22
- (value_before_type_cast.nil? || value_for_database.nil?)
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
- nil?
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 = true
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 = buckets[:association_join]
1015
- stashed_association_joins = buckets[:stashed_join]
1016
- join_nodes = buckets[:join_node].uniq
1017
- string_joins = buckets[:string_join].map(&:strip).uniq
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, alias_tracker
1021
+ klass, table, association_joins
1024
1022
  )
1025
1023
 
1026
- joins = join_dependency.join_constraints(stashed_association_joins, join_type)
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.map do |field|
1053
- if (Symbol === field || String === field) && (klass.has_attribute?(field) || klass.attribute_alias?(field)) && !from_clause.value
1054
- arel_attribute(field)
1055
- elsif Symbol === field
1056
- connection.quote_table_name(field.to_s)
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
- arel_attribute(arg).asc
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
- arel_attribute(field).send(dir.downcase)
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(scope_for_create(attributes), &block) }
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(scope_for_create(attributes), &block) }
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!(scope_for_create(attributes), &block) }
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
- relation = self
440
-
441
- if eager_loading?
442
- apply_join_dependency { |rel, _| relation = rel }
443
- end
444
-
445
- conn = klass.connection
446
- conn.unprepared_statement {
447
- conn.to_sql(relation.arel)
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(attributes = nil)
461
- scope = where_values_hash.merge!(create_with_value.stringify_keys)
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 = Proc.new if block_given?
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,
@@ -195,6 +195,8 @@ module ActiveRecord
195
195
  scope
196
196
  end
197
197
  end
198
+
199
+ generate_relation_method(name)
198
200
  end
199
201
 
200
202
  private
@@ -87,8 +87,8 @@ module ActiveRecord
87
87
  end
88
88
  end
89
89
 
90
- def self.create(connection, block = Proc.new)
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)