activerecord 5.1.7 → 5.2.4.3

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 (261) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +556 -685
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -5
  5. data/examples/performance.rb +2 -0
  6. data/examples/simple.rb +2 -0
  7. data/lib/active_record.rb +11 -4
  8. data/lib/active_record/aggregations.rb +6 -5
  9. data/lib/active_record/association_relation.rb +7 -5
  10. data/lib/active_record/associations.rb +40 -63
  11. data/lib/active_record/associations/alias_tracker.rb +19 -27
  12. data/lib/active_record/associations/association.rb +41 -37
  13. data/lib/active_record/associations/association_scope.rb +38 -50
  14. data/lib/active_record/associations/belongs_to_association.rb +27 -8
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
  16. data/lib/active_record/associations/builder/association.rb +4 -7
  17. data/lib/active_record/associations/builder/belongs_to.rb +12 -4
  18. data/lib/active_record/associations/builder/collection_association.rb +3 -3
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
  20. data/lib/active_record/associations/builder/has_many.rb +2 -0
  21. data/lib/active_record/associations/builder/has_one.rb +2 -0
  22. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  23. data/lib/active_record/associations/collection_association.rb +59 -47
  24. data/lib/active_record/associations/collection_proxy.rb +20 -49
  25. data/lib/active_record/associations/foreign_association.rb +2 -0
  26. data/lib/active_record/associations/has_many_association.rb +12 -1
  27. data/lib/active_record/associations/has_many_through_association.rb +36 -30
  28. data/lib/active_record/associations/has_one_association.rb +12 -1
  29. data/lib/active_record/associations/has_one_through_association.rb +13 -8
  30. data/lib/active_record/associations/join_dependency.rb +48 -93
  31. data/lib/active_record/associations/join_dependency/join_association.rb +39 -63
  32. data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
  33. data/lib/active_record/associations/join_dependency/join_part.rb +9 -9
  34. data/lib/active_record/associations/preloader.rb +18 -38
  35. data/lib/active_record/associations/preloader/association.rb +45 -61
  36. data/lib/active_record/associations/preloader/through_association.rb +71 -79
  37. data/lib/active_record/associations/singular_association.rb +14 -16
  38. data/lib/active_record/associations/through_association.rb +26 -11
  39. data/lib/active_record/attribute_assignment.rb +2 -5
  40. data/lib/active_record/attribute_decorators.rb +3 -2
  41. data/lib/active_record/attribute_methods.rb +65 -24
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
  43. data/lib/active_record/attribute_methods/dirty.rb +30 -214
  44. data/lib/active_record/attribute_methods/primary_key.rb +7 -6
  45. data/lib/active_record/attribute_methods/query.rb +2 -0
  46. data/lib/active_record/attribute_methods/read.rb +9 -3
  47. data/lib/active_record/attribute_methods/serialization.rb +23 -0
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
  49. data/lib/active_record/attribute_methods/write.rb +21 -9
  50. data/lib/active_record/attributes.rb +6 -5
  51. data/lib/active_record/autosave_association.rb +35 -19
  52. data/lib/active_record/base.rb +2 -0
  53. data/lib/active_record/callbacks.rb +8 -6
  54. data/lib/active_record/coders/json.rb +2 -0
  55. data/lib/active_record/coders/yaml_column.rb +2 -0
  56. data/lib/active_record/collection_cache_key.rb +12 -8
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +139 -41
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +174 -33
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +15 -5
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +13 -31
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +14 -5
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +64 -6
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +152 -81
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +84 -97
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +92 -165
  70. data/lib/active_record/connection_adapters/column.rb +3 -1
  71. data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
  72. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +13 -2
  73. data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
  74. data/lib/active_record/connection_adapters/mysql/database_statements.rb +47 -2
  75. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
  76. data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
  77. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
  78. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
  79. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
  80. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
  81. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
  82. data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
  83. data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
  84. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
  85. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -1
  101. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -2
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
  106. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  109. data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -0
  110. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  111. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +50 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
  113. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
  114. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +233 -111
  115. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
  116. data/lib/active_record/connection_adapters/postgresql/utils.rb +3 -1
  117. data/lib/active_record/connection_adapters/postgresql_adapter.rb +57 -73
  118. data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
  119. data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
  120. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
  121. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +22 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
  124. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
  125. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +75 -1
  126. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +81 -94
  127. data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
  128. data/lib/active_record/connection_handling.rb +4 -2
  129. data/lib/active_record/core.rb +41 -61
  130. data/lib/active_record/counter_cache.rb +10 -3
  131. data/lib/active_record/define_callbacks.rb +5 -3
  132. data/lib/active_record/dynamic_matchers.rb +9 -9
  133. data/lib/active_record/enum.rb +18 -13
  134. data/lib/active_record/errors.rb +42 -3
  135. data/lib/active_record/explain.rb +3 -1
  136. data/lib/active_record/explain_registry.rb +2 -0
  137. data/lib/active_record/explain_subscriber.rb +2 -0
  138. data/lib/active_record/fixture_set/file.rb +2 -0
  139. data/lib/active_record/fixtures.rb +67 -60
  140. data/lib/active_record/gem_version.rb +5 -3
  141. data/lib/active_record/inheritance.rb +49 -19
  142. data/lib/active_record/integration.rb +58 -19
  143. data/lib/active_record/internal_metadata.rb +2 -0
  144. data/lib/active_record/legacy_yaml_adapter.rb +3 -1
  145. data/lib/active_record/locking/optimistic.rb +14 -17
  146. data/lib/active_record/locking/pessimistic.rb +9 -6
  147. data/lib/active_record/log_subscriber.rb +43 -0
  148. data/lib/active_record/migration.rb +189 -139
  149. data/lib/active_record/migration/command_recorder.rb +11 -9
  150. data/lib/active_record/migration/compatibility.rb +47 -9
  151. data/lib/active_record/migration/join_table.rb +2 -0
  152. data/lib/active_record/model_schema.rb +16 -21
  153. data/lib/active_record/nested_attributes.rb +18 -6
  154. data/lib/active_record/no_touching.rb +3 -1
  155. data/lib/active_record/null_relation.rb +2 -0
  156. data/lib/active_record/persistence.rb +167 -16
  157. data/lib/active_record/query_cache.rb +6 -8
  158. data/lib/active_record/querying.rb +4 -2
  159. data/lib/active_record/railtie.rb +62 -6
  160. data/lib/active_record/railties/console_sandbox.rb +2 -0
  161. data/lib/active_record/railties/controller_runtime.rb +2 -0
  162. data/lib/active_record/railties/databases.rake +46 -36
  163. data/lib/active_record/readonly_attributes.rb +3 -2
  164. data/lib/active_record/reflection.rb +108 -194
  165. data/lib/active_record/relation.rb +120 -214
  166. data/lib/active_record/relation/batches.rb +20 -5
  167. data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
  168. data/lib/active_record/relation/calculations.rb +45 -19
  169. data/lib/active_record/relation/delegation.rb +45 -27
  170. data/lib/active_record/relation/finder_methods.rb +75 -76
  171. data/lib/active_record/relation/from_clause.rb +2 -8
  172. data/lib/active_record/relation/merger.rb +53 -23
  173. data/lib/active_record/relation/predicate_builder.rb +60 -79
  174. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
  175. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  176. data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
  177. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
  178. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  179. data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
  180. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  181. data/lib/active_record/relation/query_attribute.rb +28 -2
  182. data/lib/active_record/relation/query_methods.rb +128 -99
  183. data/lib/active_record/relation/record_fetch_warning.rb +2 -0
  184. data/lib/active_record/relation/spawn_methods.rb +4 -2
  185. data/lib/active_record/relation/where_clause.rb +65 -68
  186. data/lib/active_record/relation/where_clause_factory.rb +5 -48
  187. data/lib/active_record/result.rb +2 -0
  188. data/lib/active_record/runtime_registry.rb +2 -0
  189. data/lib/active_record/sanitization.rb +129 -121
  190. data/lib/active_record/schema.rb +4 -2
  191. data/lib/active_record/schema_dumper.rb +36 -26
  192. data/lib/active_record/schema_migration.rb +2 -0
  193. data/lib/active_record/scoping.rb +9 -8
  194. data/lib/active_record/scoping/default.rb +8 -9
  195. data/lib/active_record/scoping/named.rb +23 -7
  196. data/lib/active_record/secure_token.rb +2 -0
  197. data/lib/active_record/serialization.rb +2 -0
  198. data/lib/active_record/statement_cache.rb +23 -13
  199. data/lib/active_record/store.rb +3 -1
  200. data/lib/active_record/suppressor.rb +2 -0
  201. data/lib/active_record/table_metadata.rb +12 -3
  202. data/lib/active_record/tasks/database_tasks.rb +25 -14
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
  206. data/lib/active_record/timestamp.rb +6 -6
  207. data/lib/active_record/touch_later.rb +2 -0
  208. data/lib/active_record/transactions.rb +33 -28
  209. data/lib/active_record/translation.rb +2 -0
  210. data/lib/active_record/type.rb +4 -1
  211. data/lib/active_record/type/adapter_specific_registry.rb +2 -0
  212. data/lib/active_record/type/date.rb +2 -0
  213. data/lib/active_record/type/date_time.rb +2 -0
  214. data/lib/active_record/type/decimal_without_scale.rb +2 -0
  215. data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
  216. data/lib/active_record/type/internal/timezone.rb +2 -0
  217. data/lib/active_record/type/json.rb +30 -0
  218. data/lib/active_record/type/serialized.rb +2 -0
  219. data/lib/active_record/type/text.rb +2 -0
  220. data/lib/active_record/type/time.rb +2 -0
  221. data/lib/active_record/type/type_map.rb +2 -0
  222. data/lib/active_record/type/unsigned_integer.rb +2 -0
  223. data/lib/active_record/type_caster.rb +2 -0
  224. data/lib/active_record/type_caster/connection.rb +2 -0
  225. data/lib/active_record/type_caster/map.rb +3 -1
  226. data/lib/active_record/validations.rb +2 -0
  227. data/lib/active_record/validations/absence.rb +2 -0
  228. data/lib/active_record/validations/associated.rb +2 -0
  229. data/lib/active_record/validations/length.rb +2 -0
  230. data/lib/active_record/validations/presence.rb +2 -0
  231. data/lib/active_record/validations/uniqueness.rb +35 -5
  232. data/lib/active_record/version.rb +2 -0
  233. data/lib/rails/generators/active_record.rb +3 -1
  234. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  235. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  236. data/lib/rails/generators/active_record/migration.rb +2 -0
  237. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
  238. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
  239. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
  240. data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
  241. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
  242. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  243. metadata +23 -36
  244. data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
  245. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  246. data/lib/active_record/associations/preloader/has_many.rb +0 -15
  247. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  248. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  249. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  250. data/lib/active_record/associations/preloader/singular_association.rb +0 -18
  251. data/lib/active_record/attribute.rb +0 -240
  252. data/lib/active_record/attribute/user_provided_default.rb +0 -30
  253. data/lib/active_record/attribute_mutation_tracker.rb +0 -122
  254. data/lib/active_record/attribute_set.rb +0 -113
  255. data/lib/active_record/attribute_set/builder.rb +0 -126
  256. data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
  257. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
  258. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  259. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  260. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
  261. data/lib/active_record/type/internal/abstract_json.rb +0 -37
@@ -1,14 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  # = Active Record \Relation
3
5
  class Relation
4
6
  MULTI_VALUE_METHODS = [:includes, :eager_load, :preload, :select, :group,
5
- :order, :joins, :left_joins, :left_outer_joins, :references,
7
+ :order, :joins, :left_outer_joins, :references,
6
8
  :extending, :unscope]
7
9
 
8
10
  SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering,
9
- :reverse_order, :distinct, :create_with]
11
+ :reverse_order, :distinct, :create_with, :skip_query_cache]
10
12
  CLAUSE_METHODS = [:where, :having, :from]
11
- INVALID_METHODS_FOR_DELETE_ALL = [:limit, :distinct, :offset, :group, :having]
13
+ INVALID_METHODS_FOR_DELETE_ALL = [:distinct, :group, :having]
12
14
 
13
15
  VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS + CLAUSE_METHODS
14
16
 
@@ -18,14 +20,16 @@ module ActiveRecord
18
20
  attr_reader :table, :klass, :loaded, :predicate_builder
19
21
  alias :model :klass
20
22
  alias :loaded? :loaded
23
+ alias :locked? :lock_value
21
24
 
22
- def initialize(klass, table, predicate_builder, values = {})
25
+ def initialize(klass, table: klass.arel_table, predicate_builder: klass.predicate_builder, values: {})
23
26
  @klass = klass
24
27
  @table = table
25
28
  @values = values
26
29
  @offsets = {}
27
30
  @loaded = false
28
31
  @predicate_builder = predicate_builder
32
+ @delegate_to_klass = false
29
33
  end
30
34
 
31
35
  def initialize_copy(other)
@@ -33,74 +37,6 @@ module ActiveRecord
33
37
  reset
34
38
  end
35
39
 
36
- def insert(values) # :nodoc:
37
- primary_key_value = nil
38
-
39
- if primary_key && Hash === values
40
- primary_key_value = values[values.keys.find { |k|
41
- k.name == primary_key
42
- }]
43
-
44
- if !primary_key_value && klass.prefetch_primary_key?
45
- primary_key_value = klass.next_sequence_value
46
- values[arel_attribute(klass.primary_key)] = primary_key_value
47
- end
48
- end
49
-
50
- im = arel.create_insert
51
- im.into @table
52
-
53
- substitutes, binds = substitute_values values
54
-
55
- if values.empty? # empty insert
56
- im.values = Arel.sql(connection.empty_insert_statement_value)
57
- else
58
- im.insert substitutes
59
- end
60
-
61
- @klass.connection.insert(
62
- im,
63
- "SQL",
64
- primary_key || false,
65
- primary_key_value,
66
- nil,
67
- binds)
68
- end
69
-
70
- def _update_record(values, constraints) # :nodoc:
71
- substitutes, binds = substitute_values values
72
-
73
- scope = @klass.unscoped
74
-
75
- if @klass.finder_needs_type_condition?
76
- scope.unscope!(where: @klass.inheritance_column)
77
- end
78
-
79
- relation = scope.where(constraints)
80
- bvs = binds + relation.bound_attributes
81
- um = relation
82
- .arel
83
- .compile_update(substitutes, @klass.primary_key)
84
-
85
- @klass.connection.update(
86
- um,
87
- "SQL",
88
- bvs,
89
- )
90
- end
91
-
92
- def substitute_values(values) # :nodoc:
93
- binds = []
94
- substitutes = []
95
-
96
- values.each do |arel_attr, value|
97
- binds.push QueryAttribute.new(arel_attr.name, value, klass.type_for_attribute(arel_attr.name))
98
- substitutes.push [arel_attr, Arel::Nodes::BindParam.new]
99
- end
100
-
101
- [substitutes, binds]
102
- end
103
-
104
40
  def arel_attribute(name) # :nodoc:
105
41
  klass.arel_attribute(name, table)
106
42
  end
@@ -117,8 +53,8 @@ module ActiveRecord
117
53
  #
118
54
  # user = users.new { |user| user.name = 'Oscar' }
119
55
  # user.name # => Oscar
120
- def new(*args, &block)
121
- scoping { @klass.new(*args, &block) }
56
+ def new(attributes = nil, &block)
57
+ scoping { klass.new(values_for_create(attributes), &block) }
122
58
  end
123
59
 
124
60
  alias build new
@@ -142,8 +78,12 @@ module ActiveRecord
142
78
  #
143
79
  # users.create(name: nil) # validation on name
144
80
  # # => #<User id: nil, name: nil, ...>
145
- def create(*args, &block)
146
- scoping { @klass.create(*args, &block) }
81
+ def create(attributes = nil, &block)
82
+ if attributes.is_a?(Array)
83
+ attributes.collect { |attr| create(attr, &block) }
84
+ else
85
+ scoping { klass.create(values_for_create(attributes), &block) }
86
+ end
147
87
  end
148
88
 
149
89
  # Similar to #create, but calls
@@ -152,8 +92,12 @@ module ActiveRecord
152
92
  #
153
93
  # Expects arguments in the same format as
154
94
  # {ActiveRecord::Base.create!}[rdoc-ref:Persistence::ClassMethods#create!].
155
- def create!(*args, &block)
156
- scoping { @klass.create!(*args, &block) }
95
+ def create!(attributes = nil, &block)
96
+ if attributes.is_a?(Array)
97
+ attributes.collect { |attr| create!(attr, &block) }
98
+ else
99
+ scoping { klass.create!(values_for_create(attributes), &block) }
100
+ end
157
101
  end
158
102
 
159
103
  def first_or_create(attributes = nil, &block) # :nodoc:
@@ -247,9 +191,10 @@ module ActiveRecord
247
191
  end
248
192
 
249
193
  # Converts relation objects to Array.
250
- def to_a
194
+ def to_ary
251
195
  records.dup
252
196
  end
197
+ alias to_a to_ary
253
198
 
254
199
  def records # :nodoc:
255
200
  load
@@ -332,10 +277,17 @@ module ActiveRecord
332
277
  # Please check unscoped if you want to remove all previous scopes (including
333
278
  # the default_scope) during the execution of a block.
334
279
  def scoping
335
- previous, klass.current_scope = klass.current_scope(true), self
280
+ previous, klass.current_scope = klass.current_scope(true), self unless @delegate_to_klass
336
281
  yield
337
282
  ensure
338
- klass.current_scope = previous
283
+ klass.current_scope = previous unless @delegate_to_klass
284
+ end
285
+
286
+ def _exec_scope(*args, &block) # :nodoc:
287
+ @delegate_to_klass = true
288
+ instance_exec(*args, &block) || self
289
+ ensure
290
+ @delegate_to_klass = false
339
291
  end
340
292
 
341
293
  # Updates all records in the current relation with details given. This method constructs a single SQL UPDATE
@@ -363,12 +315,17 @@ module ActiveRecord
363
315
  def update_all(updates)
364
316
  raise ArgumentError, "Empty list of attributes to change" if updates.blank?
365
317
 
318
+ if eager_loading?
319
+ relation = apply_join_dependency
320
+ return relation.update_all(updates)
321
+ end
322
+
366
323
  stmt = Arel::UpdateManager.new
367
324
 
368
- stmt.set Arel.sql(@klass.send(:sanitize_sql_for_assignment, updates))
325
+ stmt.set Arel.sql(@klass.sanitize_sql_for_assignment(updates))
369
326
  stmt.table(table)
370
327
 
371
- if has_join_values?
328
+ if has_join_values? || offset_value
372
329
  @klass.connection.join_to_update(stmt, arel, arel_attribute(primary_key))
373
330
  else
374
331
  stmt.key = arel_attribute(primary_key)
@@ -377,50 +334,14 @@ module ActiveRecord
377
334
  stmt.wheres = arel.constraints
378
335
  end
379
336
 
380
- @klass.connection.update stmt, "SQL", bound_attributes
337
+ @klass.connection.update stmt, "#{@klass} Update All"
381
338
  end
382
339
 
383
- # Updates an object (or multiple objects) and saves it to the database, if validations pass.
384
- # The resulting object is returned whether the object was saved successfully to the database or not.
385
- #
386
- # ==== Parameters
387
- #
388
- # * +id+ - This should be the id or an array of ids to be updated.
389
- # * +attributes+ - This should be a hash of attributes or an array of hashes.
390
- #
391
- # ==== Examples
392
- #
393
- # # Updates one record
394
- # Person.update(15, user_name: 'Samuel', group: 'expert')
395
- #
396
- # # Updates multiple records
397
- # people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy" } }
398
- # Person.update(people.keys, people.values)
399
- #
400
- # # Updates multiple records from the result of a relation
401
- # people = Person.where(group: 'expert')
402
- # people.update(group: 'masters')
403
- #
404
- # Note: Updating a large number of records will run an
405
- # UPDATE query for each record, which may cause a performance
406
- # issue. So if it is not needed to run callbacks for each update, it is
407
- # preferred to use #update_all for updating all records using
408
- # a single query.
409
- def update(id = :all, attributes)
410
- if id.is_a?(Array)
411
- id.map.with_index { |one_id, idx| update(one_id, attributes[idx]) }
412
- elsif id == :all
413
- records.each { |record| record.update(attributes) }
340
+ def update(id = :all, attributes) # :nodoc:
341
+ if id == :all
342
+ each { |record| record.update(attributes) }
414
343
  else
415
- if ActiveRecord::Base === id
416
- raise ArgumentError, <<-MSG.squish
417
- You are passing an instance of ActiveRecord::Base to `update`.
418
- Please pass the id of the object by calling `.id`.
419
- MSG
420
- end
421
- object = find(id)
422
- object.update(attributes)
423
- object
344
+ klass.update(id, attributes)
424
345
  end
425
346
  end
426
347
 
@@ -444,33 +365,6 @@ module ActiveRecord
444
365
  records.each(&:destroy).tap { reset }
445
366
  end
446
367
 
447
- # Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
448
- # therefore all callbacks and filters are fired off before the object is deleted. This method is
449
- # less efficient than #delete but allows cleanup methods and other actions to be run.
450
- #
451
- # This essentially finds the object (or multiple objects) with the given id, creates a new object
452
- # from the attributes, and then calls destroy on it.
453
- #
454
- # ==== Parameters
455
- #
456
- # * +id+ - Can be either an Integer or an Array of Integers.
457
- #
458
- # ==== Examples
459
- #
460
- # # Destroy a single object
461
- # Todo.destroy(1)
462
- #
463
- # # Destroy multiple objects
464
- # todos = [1,2,3]
465
- # Todo.destroy(todos)
466
- def destroy(id)
467
- if id.is_a?(Array)
468
- id.map { |one_id| destroy(one_id) }
469
- else
470
- find(id).destroy
471
- end
472
- end
473
-
474
368
  # Deletes the records without instantiating the records
475
369
  # first, and hence not calling the {#destroy}[rdoc-ref:Persistence#destroy]
476
370
  # method nor invoking callbacks.
@@ -487,8 +381,8 @@ module ActiveRecord
487
381
  #
488
382
  # If an invalid method is supplied, #delete_all raises an ActiveRecordError:
489
383
  #
490
- # Post.limit(100).delete_all
491
- # # => ActiveRecord::ActiveRecordError: delete_all doesn't support limit
384
+ # Post.distinct.delete_all
385
+ # # => ActiveRecord::ActiveRecordError: delete_all doesn't support distinct
492
386
  def delete_all
493
387
  invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select do |method|
494
388
  value = get_value(method)
@@ -498,44 +392,26 @@ module ActiveRecord
498
392
  raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
499
393
  end
500
394
 
395
+ if eager_loading?
396
+ relation = apply_join_dependency
397
+ return relation.delete_all
398
+ end
399
+
501
400
  stmt = Arel::DeleteManager.new
502
401
  stmt.from(table)
503
402
 
504
- if has_join_values?
403
+ if has_join_values? || has_limit_or_offset?
505
404
  @klass.connection.join_to_delete(stmt, arel, arel_attribute(primary_key))
506
405
  else
507
406
  stmt.wheres = arel.constraints
508
407
  end
509
408
 
510
- affected = @klass.connection.delete(stmt, "SQL", bound_attributes)
409
+ affected = @klass.connection.delete(stmt, "#{@klass} Destroy")
511
410
 
512
411
  reset
513
412
  affected
514
413
  end
515
414
 
516
- # Deletes the row with a primary key matching the +id+ argument, using a
517
- # SQL +DELETE+ statement, and returns the number of rows deleted. Active
518
- # Record objects are not instantiated, so the object's callbacks are not
519
- # executed, including any <tt>:dependent</tt> association options.
520
- #
521
- # You can delete multiple rows at once by passing an Array of <tt>id</tt>s.
522
- #
523
- # Note: Although it is often much faster than the alternative,
524
- # #destroy, skipping callbacks might bypass business logic in
525
- # your application that ensures referential integrity or performs other
526
- # essential jobs.
527
- #
528
- # ==== Examples
529
- #
530
- # # Delete a single row
531
- # Todo.delete(1)
532
- #
533
- # # Delete multiple rows
534
- # Todo.delete([2,3,4])
535
- def delete(id_or_array)
536
- where(primary_key => id_or_array).delete_all
537
- end
538
-
539
415
  # Causes the records to be loaded from the database if they have not
540
416
  # been loaded already. You can use this if for some reason you need
541
417
  # to explicitly load some records before actually using them. The
@@ -555,8 +431,8 @@ module ActiveRecord
555
431
  end
556
432
 
557
433
  def reset
558
- @last = @to_sql = @order_clause = @scope_for_create = @arel = @loaded = nil
559
- @should_eager_load = @join_dependency = nil
434
+ @delegate_to_klass = false
435
+ @to_sql = @arel = @loaded = @should_eager_load = nil
560
436
  @records = [].freeze
561
437
  @offsets = {}
562
438
  self
@@ -568,29 +444,28 @@ module ActiveRecord
568
444
  # # => SELECT "users".* FROM "users" WHERE "users"."name" = 'Oscar'
569
445
  def to_sql
570
446
  @to_sql ||= begin
571
- relation = self
572
-
573
- if eager_loading?
574
- find_with_associations { |rel, _| relation = rel }
575
- end
576
-
577
- conn = klass.connection
578
- conn.unprepared_statement {
579
- conn.to_sql(relation.arel, relation.bound_attributes)
580
- }
581
- 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
582
457
  end
583
458
 
584
459
  # Returns a hash of where conditions.
585
460
  #
586
461
  # User.where(name: 'Oscar').where_values_hash
587
462
  # # => {name: "Oscar"}
588
- def where_values_hash(relation_table_name = table_name)
463
+ def where_values_hash(relation_table_name = klass.table_name)
589
464
  where_clause.to_h(relation_table_name)
590
465
  end
591
466
 
592
467
  def scope_for_create
593
- @scope_for_create ||= where_values_hash.merge(create_with_value)
468
+ where_values_hash.merge!(create_with_value.stringify_keys)
594
469
  end
595
470
 
596
471
  # Returns true if relation needs eager loading.
@@ -650,6 +525,11 @@ module ActiveRecord
650
525
  limit_value || offset_value
651
526
  end
652
527
 
528
+ def alias_tracker(joins = [], aliases = nil) # :nodoc:
529
+ joins += [aliases] if aliases
530
+ ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins)
531
+ end
532
+
653
533
  protected
654
534
 
655
535
  def load_records(records)
@@ -664,32 +544,45 @@ module ActiveRecord
664
544
  end
665
545
 
666
546
  def exec_queries(&block)
667
- @records =
668
- if eager_loading?
669
- find_with_associations do |relation, join_dependency|
670
- if ActiveRecord::NullRelation === relation
671
- []
672
- else
673
- rows = connection.select_all(relation.arel, "SQL", relation.bound_attributes)
674
- join_dependency.instantiate(rows, &block)
675
- end.freeze
547
+ skip_query_cache_if_necessary do
548
+ @records =
549
+ if eager_loading?
550
+ apply_join_dependency do |relation, join_dependency|
551
+ if ActiveRecord::NullRelation === relation
552
+ []
553
+ else
554
+ relation = join_dependency.apply_column_aliases(relation)
555
+ rows = connection.select_all(relation.arel, "SQL")
556
+ join_dependency.instantiate(rows, &block)
557
+ end.freeze
558
+ end
559
+ else
560
+ klass.find_by_sql(arel, &block).freeze
676
561
  end
677
- else
678
- klass.find_by_sql(arel, bound_attributes, &block).freeze
562
+
563
+ preload = preload_values
564
+ preload += includes_values unless eager_loading?
565
+ preloader = nil
566
+ preload.each do |associations|
567
+ preloader ||= build_preloader
568
+ preloader.preload @records, associations
679
569
  end
680
570
 
681
- preload = preload_values
682
- preload += includes_values unless eager_loading?
683
- preloader = nil
684
- preload.each do |associations|
685
- preloader ||= build_preloader
686
- preloader.preload @records, associations
687
- end
571
+ @records.each(&:readonly!) if readonly_value
688
572
 
689
- @records.each(&:readonly!) if readonly_value
573
+ @loaded = true
574
+ @records
575
+ end
576
+ end
690
577
 
691
- @loaded = true
692
- @records
578
+ def skip_query_cache_if_necessary
579
+ if skip_query_cache_value
580
+ uncached do
581
+ yield
582
+ end
583
+ else
584
+ yield
585
+ end
693
586
  end
694
587
 
695
588
  def build_preloader
@@ -719,5 +612,18 @@ module ActiveRecord
719
612
  # ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
720
613
  string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map(&:downcase).uniq - ["raw_sql_"]
721
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
722
628
  end
723
629
  end