activerecord 5.1.0 → 5.2.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 +5 -5
  2. data/CHANGELOG.md +596 -450
  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 +77 -85
  11. data/lib/active_record/associations/alias_tracker.rb +23 -32
  12. data/lib/active_record/associations/association.rb +49 -35
  13. data/lib/active_record/associations/association_scope.rb +55 -55
  14. data/lib/active_record/associations/belongs_to_association.rb +30 -11
  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 +21 -8
  18. data/lib/active_record/associations/builder/collection_association.rb +1 -1
  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 +66 -53
  24. data/lib/active_record/associations/collection_proxy.rb +30 -73
  25. data/lib/active_record/associations/foreign_association.rb +2 -0
  26. data/lib/active_record/associations/has_many_association.rb +13 -2
  27. data/lib/active_record/associations/has_many_through_association.rb +37 -19
  28. data/lib/active_record/associations/has_one_association.rb +14 -1
  29. data/lib/active_record/associations/has_one_through_association.rb +13 -8
  30. data/lib/active_record/associations/join_dependency.rb +52 -96
  31. data/lib/active_record/associations/join_dependency/join_association.rb +22 -75
  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 +17 -37
  35. data/lib/active_record/associations/preloader/association.rb +53 -92
  36. data/lib/active_record/associations/preloader/through_association.rb +72 -73
  37. data/lib/active_record/associations/singular_association.rb +14 -16
  38. data/lib/active_record/associations/through_association.rb +27 -12
  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 +33 -216
  44. data/lib/active_record/attribute_methods/primary_key.rb +10 -13
  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 +22 -19
  50. data/lib/active_record/attributes.rb +7 -6
  51. data/lib/active_record/autosave_association.rb +15 -13
  52. data/lib/active_record/base.rb +2 -0
  53. data/lib/active_record/callbacks.rb +12 -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 +15 -11
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +120 -39
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +192 -37
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +13 -2
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -25
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +15 -6
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +65 -7
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +158 -87
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +86 -98
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +126 -189
  70. data/lib/active_record/connection_adapters/column.rb +4 -2
  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 +45 -15
  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 -23
  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 +30 -1
  84. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -32
  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 +13 -1
  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 +3 -1
  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 -11
  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 +8 -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 +22 -1
  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 +258 -129
  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 +75 -87
  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 +24 -1
  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 +90 -96
  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 +20 -15
  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 +60 -15
  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 +4 -2
  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 +30 -42
  146. data/lib/active_record/locking/pessimistic.rb +10 -7
  147. data/lib/active_record/log_subscriber.rb +46 -4
  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 +81 -29
  151. data/lib/active_record/migration/join_table.rb +2 -0
  152. data/lib/active_record/model_schema.rb +74 -58
  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 +199 -54
  157. data/lib/active_record/query_cache.rb +8 -10
  158. data/lib/active_record/querying.rb +5 -3
  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 +48 -38
  163. data/lib/active_record/readonly_attributes.rb +3 -2
  164. data/lib/active_record/reflection.rb +137 -207
  165. data/lib/active_record/relation.rb +132 -207
  166. data/lib/active_record/relation/batches.rb +32 -17
  167. data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
  168. data/lib/active_record/relation/calculations.rb +66 -25
  169. data/lib/active_record/relation/delegation.rb +45 -29
  170. data/lib/active_record/relation/finder_methods.rb +76 -85
  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 +135 -103
  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 -67
  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 +12 -10
  194. data/lib/active_record/scoping/default.rb +10 -7
  195. data/lib/active_record/scoping/named.rb +40 -12
  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 +22 -12
  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 +38 -26
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +11 -50
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -3
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
  206. data/lib/active_record/timestamp.rb +13 -6
  207. data/lib/active_record/touch_later.rb +2 -0
  208. data/lib/active_record/transactions.rb +32 -27
  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 +6 -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 +36 -6
  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 +24 -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 -113
  254. data/lib/active_record/attribute_set.rb +0 -113
  255. data/lib/active_record/attribute_set/builder.rb +0 -124
  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 -33
@@ -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, id, id_was) # :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(@klass.primary_key => (id_was || id))
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
@@ -269,8 +214,7 @@ module ActiveRecord
269
214
  # Returns true if there are no records.
270
215
  def empty?
271
216
  return @records.empty? if loaded?
272
-
273
- limit_value == 0 || !exists?
217
+ !exists?
274
218
  end
275
219
 
276
220
  # Returns true if there are no records.
@@ -333,10 +277,17 @@ module ActiveRecord
333
277
  # Please check unscoped if you want to remove all previous scopes (including
334
278
  # the default_scope) during the execution of a block.
335
279
  def scoping
336
- previous, klass.current_scope = klass.current_scope, self
280
+ previous, klass.current_scope = klass.current_scope(true), self unless @delegate_to_klass
337
281
  yield
338
282
  ensure
339
- 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
340
291
  end
341
292
 
342
293
  # Updates all records in the current relation with details given. This method constructs a single SQL UPDATE
@@ -364,12 +315,17 @@ module ActiveRecord
364
315
  def update_all(updates)
365
316
  raise ArgumentError, "Empty list of attributes to change" if updates.blank?
366
317
 
318
+ if eager_loading?
319
+ relation = apply_join_dependency
320
+ return relation.update_all(updates)
321
+ end
322
+
367
323
  stmt = Arel::UpdateManager.new
368
324
 
369
- stmt.set Arel.sql(@klass.send(:sanitize_sql_for_assignment, updates))
325
+ stmt.set Arel.sql(@klass.sanitize_sql_for_assignment(updates))
370
326
  stmt.table(table)
371
327
 
372
- if has_join_values?
328
+ if has_join_values? || offset_value
373
329
  @klass.connection.join_to_update(stmt, arel, arel_attribute(primary_key))
374
330
  else
375
331
  stmt.key = arel_attribute(primary_key)
@@ -378,50 +334,14 @@ module ActiveRecord
378
334
  stmt.wheres = arel.constraints
379
335
  end
380
336
 
381
- @klass.connection.update stmt, "SQL", bound_attributes
337
+ @klass.connection.update stmt, "#{@klass} Update All"
382
338
  end
383
339
 
384
- # Updates an object (or multiple objects) and saves it to the database, if validations pass.
385
- # The resulting object is returned whether the object was saved successfully to the database or not.
386
- #
387
- # ==== Parameters
388
- #
389
- # * +id+ - This should be the id or an array of ids to be updated.
390
- # * +attributes+ - This should be a hash of attributes or an array of hashes.
391
- #
392
- # ==== Examples
393
- #
394
- # # Updates one record
395
- # Person.update(15, user_name: 'Samuel', group: 'expert')
396
- #
397
- # # Updates multiple records
398
- # people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy" } }
399
- # Person.update(people.keys, people.values)
400
- #
401
- # # Updates multiple records from the result of a relation
402
- # people = Person.where(group: 'expert')
403
- # people.update(group: 'masters')
404
- #
405
- # Note: Updating a large number of records will run an
406
- # UPDATE query for each record, which may cause a performance
407
- # issue. So if it is not needed to run callbacks for each update, it is
408
- # preferred to use #update_all for updating all records using
409
- # a single query.
410
- def update(id = :all, attributes)
411
- if id.is_a?(Array)
412
- id.map.with_index { |one_id, idx| update(one_id, attributes[idx]) }
413
- elsif id == :all
414
- records.each { |record| record.update(attributes) }
340
+ def update(id = :all, attributes) # :nodoc:
341
+ if id == :all
342
+ each { |record| record.update(attributes) }
415
343
  else
416
- if ActiveRecord::Base === id
417
- raise ArgumentError, <<-MSG.squish
418
- You are passing an instance of ActiveRecord::Base to `update`.
419
- Please pass the id of the object by calling `.id`.
420
- MSG
421
- end
422
- object = find(id)
423
- object.update(attributes)
424
- object
344
+ klass.update(id, attributes)
425
345
  end
426
346
  end
427
347
 
@@ -445,33 +365,6 @@ module ActiveRecord
445
365
  records.each(&:destroy).tap { reset }
446
366
  end
447
367
 
448
- # Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
449
- # therefore all callbacks and filters are fired off before the object is deleted. This method is
450
- # less efficient than #delete but allows cleanup methods and other actions to be run.
451
- #
452
- # This essentially finds the object (or multiple objects) with the given id, creates a new object
453
- # from the attributes, and then calls destroy on it.
454
- #
455
- # ==== Parameters
456
- #
457
- # * +id+ - Can be either an Integer or an Array of Integers.
458
- #
459
- # ==== Examples
460
- #
461
- # # Destroy a single object
462
- # Todo.destroy(1)
463
- #
464
- # # Destroy multiple objects
465
- # todos = [1,2,3]
466
- # Todo.destroy(todos)
467
- def destroy(id)
468
- if id.is_a?(Array)
469
- id.map { |one_id| destroy(one_id) }
470
- else
471
- find(id).destroy
472
- end
473
- end
474
-
475
368
  # Deletes the records without instantiating the records
476
369
  # first, and hence not calling the {#destroy}[rdoc-ref:Persistence#destroy]
477
370
  # method nor invoking callbacks.
@@ -488,8 +381,8 @@ module ActiveRecord
488
381
  #
489
382
  # If an invalid method is supplied, #delete_all raises an ActiveRecordError:
490
383
  #
491
- # Post.limit(100).delete_all
492
- # # => ActiveRecord::ActiveRecordError: delete_all doesn't support limit
384
+ # Post.distinct.delete_all
385
+ # # => ActiveRecord::ActiveRecordError: delete_all doesn't support distinct
493
386
  def delete_all
494
387
  invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select do |method|
495
388
  value = get_value(method)
@@ -499,44 +392,26 @@ module ActiveRecord
499
392
  raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
500
393
  end
501
394
 
395
+ if eager_loading?
396
+ relation = apply_join_dependency
397
+ return relation.delete_all
398
+ end
399
+
502
400
  stmt = Arel::DeleteManager.new
503
401
  stmt.from(table)
504
402
 
505
- if has_join_values?
403
+ if has_join_values? || has_limit_or_offset?
506
404
  @klass.connection.join_to_delete(stmt, arel, arel_attribute(primary_key))
507
405
  else
508
406
  stmt.wheres = arel.constraints
509
407
  end
510
408
 
511
- affected = @klass.connection.delete(stmt, "SQL", bound_attributes)
409
+ affected = @klass.connection.delete(stmt, "#{@klass} Destroy")
512
410
 
513
411
  reset
514
412
  affected
515
413
  end
516
414
 
517
- # Deletes the row with a primary key matching the +id+ argument, using a
518
- # SQL +DELETE+ statement, and returns the number of rows deleted. Active
519
- # Record objects are not instantiated, so the object's callbacks are not
520
- # executed, including any <tt>:dependent</tt> association options.
521
- #
522
- # You can delete multiple rows at once by passing an Array of <tt>id</tt>s.
523
- #
524
- # Note: Although it is often much faster than the alternative,
525
- # #destroy, skipping callbacks might bypass business logic in
526
- # your application that ensures referential integrity or performs other
527
- # essential jobs.
528
- #
529
- # ==== Examples
530
- #
531
- # # Delete a single row
532
- # Todo.delete(1)
533
- #
534
- # # Delete multiple rows
535
- # Todo.delete([2,3,4])
536
- def delete(id_or_array)
537
- where(primary_key => id_or_array).delete_all
538
- end
539
-
540
415
  # Causes the records to be loaded from the database if they have not
541
416
  # been loaded already. You can use this if for some reason you need
542
417
  # to explicitly load some records before actually using them. The
@@ -556,8 +431,8 @@ module ActiveRecord
556
431
  end
557
432
 
558
433
  def reset
559
- @last = @to_sql = @order_clause = @scope_for_create = @arel = @loaded = nil
560
- @should_eager_load = @join_dependency = nil
434
+ @delegate_to_klass = false
435
+ @to_sql = @arel = @loaded = @should_eager_load = nil
561
436
  @records = [].freeze
562
437
  @offsets = {}
563
438
  self
@@ -569,29 +444,28 @@ module ActiveRecord
569
444
  # # => SELECT "users".* FROM "users" WHERE "users"."name" = 'Oscar'
570
445
  def to_sql
571
446
  @to_sql ||= begin
572
- relation = self
573
-
574
- if eager_loading?
575
- find_with_associations { |rel| relation = rel }
576
- end
577
-
578
- conn = klass.connection
579
- conn.unprepared_statement {
580
- conn.to_sql(relation.arel, relation.bound_attributes)
581
- }
582
- 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
583
457
  end
584
458
 
585
459
  # Returns a hash of where conditions.
586
460
  #
587
461
  # User.where(name: 'Oscar').where_values_hash
588
462
  # # => {name: "Oscar"}
589
- def where_values_hash(relation_table_name = table_name)
463
+ def where_values_hash(relation_table_name = klass.table_name)
590
464
  where_clause.to_h(relation_table_name)
591
465
  end
592
466
 
593
467
  def scope_for_create
594
- @scope_for_create ||= where_values_hash.merge(create_with_value)
468
+ where_values_hash.merge!(create_with_value.stringify_keys)
595
469
  end
596
470
 
597
471
  # Returns true if relation needs eager loading.
@@ -643,6 +517,19 @@ module ActiveRecord
643
517
  "#<#{self.class.name} [#{entries.join(', ')}]>"
644
518
  end
645
519
 
520
+ def empty_scope? # :nodoc:
521
+ @values == klass.unscoped.values
522
+ end
523
+
524
+ def has_limit_or_offset? # :nodoc:
525
+ limit_value || offset_value
526
+ end
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
+
646
533
  protected
647
534
 
648
535
  def load_records(records)
@@ -657,20 +544,45 @@ module ActiveRecord
657
544
  end
658
545
 
659
546
  def exec_queries(&block)
660
- @records = eager_loading? ? find_with_associations.freeze : @klass.find_by_sql(arel, bound_attributes, &block).freeze
661
-
662
- preload = preload_values
663
- preload += includes_values unless eager_loading?
664
- preloader = nil
665
- preload.each do |associations|
666
- preloader ||= build_preloader
667
- preloader.preload @records, associations
668
- end
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
561
+ end
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
569
+ end
669
570
 
670
- @records.each(&:readonly!) if readonly_value
571
+ @records.each(&:readonly!) if readonly_value
671
572
 
672
- @loaded = true
673
- @records
573
+ @loaded = true
574
+ @records
575
+ end
576
+ end
577
+
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
674
586
  end
675
587
 
676
588
  def build_preloader
@@ -700,5 +612,18 @@ module ActiveRecord
700
612
  # ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
701
613
  string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map(&:downcase).uniq - ["raw_sql_"]
702
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
703
628
  end
704
629
  end