activerecord 4.2.11.3 → 5.0.7.2

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 (251) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1638 -1132
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +7 -8
  5. data/examples/performance.rb +2 -3
  6. data/examples/simple.rb +0 -1
  7. data/lib/active_record.rb +7 -2
  8. data/lib/active_record/aggregations.rb +34 -21
  9. data/lib/active_record/association_relation.rb +7 -4
  10. data/lib/active_record/associations.rb +347 -218
  11. data/lib/active_record/associations/alias_tracker.rb +19 -16
  12. data/lib/active_record/associations/association.rb +22 -10
  13. data/lib/active_record/associations/association_scope.rb +75 -104
  14. data/lib/active_record/associations/belongs_to_association.rb +21 -32
  15. data/lib/active_record/associations/builder/association.rb +28 -34
  16. data/lib/active_record/associations/builder/belongs_to.rb +43 -18
  17. data/lib/active_record/associations/builder/collection_association.rb +7 -19
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +16 -11
  19. data/lib/active_record/associations/builder/has_many.rb +4 -4
  20. data/lib/active_record/associations/builder/has_one.rb +11 -6
  21. data/lib/active_record/associations/builder/singular_association.rb +13 -11
  22. data/lib/active_record/associations/collection_association.rb +85 -69
  23. data/lib/active_record/associations/collection_proxy.rb +104 -46
  24. data/lib/active_record/associations/foreign_association.rb +1 -1
  25. data/lib/active_record/associations/has_many_association.rb +21 -78
  26. data/lib/active_record/associations/has_many_through_association.rb +6 -47
  27. data/lib/active_record/associations/has_one_association.rb +12 -5
  28. data/lib/active_record/associations/join_dependency.rb +38 -22
  29. data/lib/active_record/associations/join_dependency/join_association.rb +15 -14
  30. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  31. data/lib/active_record/associations/preloader.rb +14 -4
  32. data/lib/active_record/associations/preloader/association.rb +52 -71
  33. data/lib/active_record/associations/preloader/collection_association.rb +0 -7
  34. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  35. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  36. data/lib/active_record/associations/preloader/singular_association.rb +0 -1
  37. data/lib/active_record/associations/preloader/through_association.rb +36 -17
  38. data/lib/active_record/associations/singular_association.rb +13 -1
  39. data/lib/active_record/associations/through_association.rb +12 -4
  40. data/lib/active_record/attribute.rb +69 -19
  41. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  42. data/lib/active_record/attribute_assignment.rb +19 -140
  43. data/lib/active_record/attribute_decorators.rb +6 -5
  44. data/lib/active_record/attribute_methods.rb +69 -44
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  46. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  47. data/lib/active_record/attribute_methods/primary_key.rb +16 -3
  48. data/lib/active_record/attribute_methods/query.rb +2 -2
  49. data/lib/active_record/attribute_methods/read.rb +31 -59
  50. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  51. data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
  52. data/lib/active_record/attribute_methods/write.rb +13 -37
  53. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  54. data/lib/active_record/attribute_set.rb +32 -3
  55. data/lib/active_record/attribute_set/builder.rb +42 -16
  56. data/lib/active_record/attributes.rb +199 -81
  57. data/lib/active_record/autosave_association.rb +54 -17
  58. data/lib/active_record/base.rb +32 -23
  59. data/lib/active_record/callbacks.rb +39 -43
  60. data/lib/active_record/coders/json.rb +1 -1
  61. data/lib/active_record/coders/yaml_column.rb +20 -8
  62. data/lib/active_record/collection_cache_key.rb +50 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +467 -189
  64. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  65. data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -62
  66. data/lib/active_record/connection_adapters/abstract/query_cache.rb +39 -4
  67. data/lib/active_record/connection_adapters/abstract/quoting.rb +86 -13
  68. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  69. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
  70. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -188
  71. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
  72. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +407 -156
  73. data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
  74. data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -71
  75. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +433 -399
  76. data/lib/active_record/connection_adapters/column.rb +28 -43
  77. data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
  78. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  79. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  80. data/lib/active_record/connection_adapters/mysql/database_statements.rb +108 -0
  81. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  82. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  83. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  84. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  85. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  86. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  87. data/lib/active_record/connection_adapters/mysql2_adapter.rb +25 -166
  88. data/lib/active_record/connection_adapters/postgresql/column.rb +33 -11
  89. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -72
  90. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  92. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +37 -57
  93. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +3 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -2
  95. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  96. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  97. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +13 -3
  98. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  99. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
  101. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  102. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  105. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  106. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +56 -19
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +250 -154
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -2
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +264 -170
  116. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  118. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  119. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  120. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  121. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +151 -194
  122. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  123. data/lib/active_record/connection_handling.rb +37 -14
  124. data/lib/active_record/core.rb +92 -108
  125. data/lib/active_record/counter_cache.rb +13 -24
  126. data/lib/active_record/dynamic_matchers.rb +1 -20
  127. data/lib/active_record/enum.rb +116 -76
  128. data/lib/active_record/errors.rb +87 -48
  129. data/lib/active_record/explain.rb +20 -9
  130. data/lib/active_record/explain_registry.rb +1 -1
  131. data/lib/active_record/explain_subscriber.rb +1 -1
  132. data/lib/active_record/fixture_set/file.rb +26 -5
  133. data/lib/active_record/fixtures.rb +77 -41
  134. data/lib/active_record/gem_version.rb +4 -4
  135. data/lib/active_record/inheritance.rb +32 -40
  136. data/lib/active_record/integration.rb +17 -14
  137. data/lib/active_record/internal_metadata.rb +56 -0
  138. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  139. data/lib/active_record/locale/en.yml +3 -2
  140. data/lib/active_record/locking/optimistic.rb +15 -15
  141. data/lib/active_record/locking/pessimistic.rb +1 -1
  142. data/lib/active_record/log_subscriber.rb +48 -24
  143. data/lib/active_record/migration.rb +362 -111
  144. data/lib/active_record/migration/command_recorder.rb +59 -18
  145. data/lib/active_record/migration/compatibility.rb +126 -0
  146. data/lib/active_record/model_schema.rb +270 -73
  147. data/lib/active_record/nested_attributes.rb +58 -29
  148. data/lib/active_record/no_touching.rb +4 -0
  149. data/lib/active_record/null_relation.rb +16 -8
  150. data/lib/active_record/persistence.rb +152 -90
  151. data/lib/active_record/query_cache.rb +18 -23
  152. data/lib/active_record/querying.rb +12 -11
  153. data/lib/active_record/railtie.rb +23 -16
  154. data/lib/active_record/railties/controller_runtime.rb +1 -1
  155. data/lib/active_record/railties/databases.rake +52 -41
  156. data/lib/active_record/readonly_attributes.rb +1 -1
  157. data/lib/active_record/reflection.rb +302 -115
  158. data/lib/active_record/relation.rb +187 -120
  159. data/lib/active_record/relation/batches.rb +141 -36
  160. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  161. data/lib/active_record/relation/calculations.rb +92 -117
  162. data/lib/active_record/relation/delegation.rb +8 -20
  163. data/lib/active_record/relation/finder_methods.rb +173 -89
  164. data/lib/active_record/relation/from_clause.rb +32 -0
  165. data/lib/active_record/relation/merger.rb +16 -42
  166. data/lib/active_record/relation/predicate_builder.rb +120 -107
  167. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
  168. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  169. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  170. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  171. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  172. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  173. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  174. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  175. data/lib/active_record/relation/query_attribute.rb +19 -0
  176. data/lib/active_record/relation/query_methods.rb +308 -244
  177. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  178. data/lib/active_record/relation/spawn_methods.rb +4 -7
  179. data/lib/active_record/relation/where_clause.rb +174 -0
  180. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  181. data/lib/active_record/result.rb +11 -4
  182. data/lib/active_record/runtime_registry.rb +1 -1
  183. data/lib/active_record/sanitization.rb +105 -66
  184. data/lib/active_record/schema.rb +26 -22
  185. data/lib/active_record/schema_dumper.rb +54 -37
  186. data/lib/active_record/schema_migration.rb +11 -14
  187. data/lib/active_record/scoping.rb +34 -16
  188. data/lib/active_record/scoping/default.rb +28 -10
  189. data/lib/active_record/scoping/named.rb +59 -26
  190. data/lib/active_record/secure_token.rb +38 -0
  191. data/lib/active_record/serialization.rb +3 -5
  192. data/lib/active_record/statement_cache.rb +17 -15
  193. data/lib/active_record/store.rb +8 -3
  194. data/lib/active_record/suppressor.rb +58 -0
  195. data/lib/active_record/table_metadata.rb +69 -0
  196. data/lib/active_record/tasks/database_tasks.rb +66 -49
  197. data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
  198. data/lib/active_record/tasks/postgresql_database_tasks.rb +12 -3
  199. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  200. data/lib/active_record/timestamp.rb +20 -9
  201. data/lib/active_record/touch_later.rb +63 -0
  202. data/lib/active_record/transactions.rb +139 -57
  203. data/lib/active_record/type.rb +66 -17
  204. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  205. data/lib/active_record/type/date.rb +2 -45
  206. data/lib/active_record/type/date_time.rb +2 -49
  207. data/lib/active_record/type/internal/abstract_json.rb +33 -0
  208. data/lib/active_record/type/internal/timezone.rb +15 -0
  209. data/lib/active_record/type/serialized.rb +15 -14
  210. data/lib/active_record/type/time.rb +10 -16
  211. data/lib/active_record/type/type_map.rb +4 -4
  212. data/lib/active_record/type_caster.rb +7 -0
  213. data/lib/active_record/type_caster/connection.rb +29 -0
  214. data/lib/active_record/type_caster/map.rb +19 -0
  215. data/lib/active_record/validations.rb +33 -32
  216. data/lib/active_record/validations/absence.rb +23 -0
  217. data/lib/active_record/validations/associated.rb +10 -3
  218. data/lib/active_record/validations/length.rb +24 -0
  219. data/lib/active_record/validations/presence.rb +11 -12
  220. data/lib/active_record/validations/uniqueness.rb +33 -33
  221. data/lib/rails/generators/active_record/migration.rb +15 -0
  222. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -5
  223. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  224. data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
  225. data/lib/rails/generators/active_record/model/model_generator.rb +33 -16
  226. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  227. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  228. metadata +58 -34
  229. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  230. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  231. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  232. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  233. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  234. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  235. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  236. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  237. data/lib/active_record/type/big_integer.rb +0 -13
  238. data/lib/active_record/type/binary.rb +0 -50
  239. data/lib/active_record/type/boolean.rb +0 -31
  240. data/lib/active_record/type/decimal.rb +0 -64
  241. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  242. data/lib/active_record/type/decorator.rb +0 -14
  243. data/lib/active_record/type/float.rb +0 -19
  244. data/lib/active_record/type/integer.rb +0 -59
  245. data/lib/active_record/type/mutable.rb +0 -16
  246. data/lib/active_record/type/numeric.rb +0 -36
  247. data/lib/active_record/type/string.rb +0 -40
  248. data/lib/active_record/type/text.rb +0 -11
  249. data/lib/active_record/type/time_value.rb +0 -38
  250. data/lib/active_record/type/unsigned_integer.rb +0 -15
  251. data/lib/active_record/type/value.rb +0 -110
@@ -1,38 +1,39 @@
1
- # -*- coding: utf-8 -*-
2
- require 'arel/collectors/bind'
1
+ require "arel/collectors/bind"
3
2
 
4
3
  module ActiveRecord
5
- # = Active Record Relation
4
+ # = Active Record \Relation
6
5
  class Relation
7
6
  MULTI_VALUE_METHODS = [:includes, :eager_load, :preload, :select, :group,
8
- :order, :joins, :where, :having, :bind, :references,
7
+ :order, :joins, :left_joins, :left_outer_joins, :references,
9
8
  :extending, :unscope]
10
9
 
11
- SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :from, :reordering,
12
- :reverse_order, :distinct, :create_with, :uniq]
10
+ SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering,
11
+ :reverse_order, :distinct, :create_with]
12
+ CLAUSE_METHODS = [:where, :having, :from]
13
13
  INVALID_METHODS_FOR_DELETE_ALL = [:limit, :distinct, :offset, :group, :having]
14
14
 
15
- VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS
15
+ VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS + CLAUSE_METHODS
16
16
 
17
+ include Enumerable
17
18
  include FinderMethods, Calculations, SpawnMethods, QueryMethods, Batches, Explain, Delegation
18
19
 
19
- attr_reader :table, :klass, :loaded
20
+ attr_reader :table, :klass, :loaded, :predicate_builder
20
21
  alias :model :klass
21
22
  alias :loaded? :loaded
22
23
 
23
- def initialize(klass, table, values = {})
24
+ def initialize(klass, table, predicate_builder, values = {})
24
25
  @klass = klass
25
26
  @table = table
26
27
  @values = values
27
28
  @offsets = {}
28
29
  @loaded = false
30
+ @predicate_builder = predicate_builder
29
31
  end
30
32
 
31
33
  def initialize_copy(other)
32
34
  # This method is a hot spot, so for now, use Hash[] to dup the hash.
33
35
  # https://bugs.ruby-lang.org/issues/7166
34
36
  @values = Hash[@values]
35
- @values[:bind] = @values[:bind].dup if @values.key? :bind
36
37
  reset
37
38
  end
38
39
 
@@ -44,9 +45,9 @@ module ActiveRecord
44
45
  k.name == primary_key
45
46
  }]
46
47
 
47
- if !primary_key_value && connection.prefetch_primary_key?(klass.table_name)
48
- primary_key_value = connection.next_sequence_value(klass.sequence_name)
49
- values[klass.arel_table[klass.primary_key]] = primary_key_value
48
+ if !primary_key_value && klass.prefetch_primary_key?
49
+ primary_key_value = klass.next_sequence_value
50
+ values[arel_attribute(klass.primary_key)] = primary_key_value
50
51
  end
51
52
  end
52
53
 
@@ -80,7 +81,7 @@ module ActiveRecord
80
81
  end
81
82
 
82
83
  relation = scope.where(@klass.primary_key => (id_was || id))
83
- bvs = binds + relation.bind_values
84
+ bvs = binds + relation.bound_attributes
84
85
  um = relation
85
86
  .arel
86
87
  .compile_update(substitutes, @klass.primary_key)
@@ -93,21 +94,25 @@ module ActiveRecord
93
94
  end
94
95
 
95
96
  def substitute_values(values) # :nodoc:
96
- binds = values.map do |arel_attr, value|
97
- [@klass.columns_hash[arel_attr.name], value]
98
- end
97
+ binds = []
98
+ substitutes = []
99
99
 
100
- substitutes = values.each_with_index.map do |(arel_attr, _), i|
101
- [arel_attr, @klass.connection.substitute_at(binds[i][0])]
100
+ values.each do |arel_attr, value|
101
+ binds.push QueryAttribute.new(arel_attr.name, value, klass.type_for_attribute(arel_attr.name))
102
+ substitutes.push [arel_attr, Arel::Nodes::BindParam.new]
102
103
  end
103
104
 
104
105
  [substitutes, binds]
105
106
  end
106
107
 
108
+ def arel_attribute(name) # :nodoc:
109
+ klass.arel_attribute(name, table)
110
+ end
111
+
107
112
  # Initializes new record from relation while maintaining the current
108
113
  # scope.
109
114
  #
110
- # Expects arguments in the same format as +Base.new+.
115
+ # Expects arguments in the same format as {ActiveRecord::Base.new}[rdoc-ref:Core.new].
111
116
  #
112
117
  # users = User.where(name: 'DHH')
113
118
  # user = users.new # => #<User id: nil, name: "DHH", created_at: nil, updated_at: nil>
@@ -125,28 +130,32 @@ module ActiveRecord
125
130
  # Tries to create a new record with the same scoped attributes
126
131
  # defined in the relation. Returns the initialized object if validation fails.
127
132
  #
128
- # Expects arguments in the same format as +Base.create+.
133
+ # Expects arguments in the same format as
134
+ # {ActiveRecord::Base.create}[rdoc-ref:Persistence::ClassMethods#create].
129
135
  #
130
136
  # ==== Examples
137
+ #
131
138
  # users = User.where(name: 'Oscar')
132
- # users.create # #<User id: 3, name: "oscar", ...>
139
+ # users.create # => #<User id: 3, name: "Oscar", ...>
133
140
  #
134
141
  # users.create(name: 'fxn')
135
- # users.create # #<User id: 4, name: "fxn", ...>
142
+ # users.create # => #<User id: 4, name: "fxn", ...>
136
143
  #
137
144
  # users.create { |user| user.name = 'tenderlove' }
138
- # # #<User id: 5, name: "tenderlove", ...>
145
+ # # => #<User id: 5, name: "tenderlove", ...>
139
146
  #
140
147
  # users.create(name: nil) # validation on name
141
- # # #<User id: nil, name: nil, ...>
148
+ # # => #<User id: nil, name: nil, ...>
142
149
  def create(*args, &block)
143
150
  scoping { @klass.create(*args, &block) }
144
151
  end
145
152
 
146
- # Similar to #create, but calls +create!+ on the base class. Raises
147
- # an exception if a validation error occurs.
153
+ # Similar to #create, but calls
154
+ # {create!}[rdoc-ref:Persistence::ClassMethods#create!]
155
+ # on the base class. Raises an exception if a validation error occurs.
148
156
  #
149
- # Expects arguments in the same format as <tt>Base.create!</tt>.
157
+ # Expects arguments in the same format as
158
+ # {ActiveRecord::Base.create!}[rdoc-ref:Persistence::ClassMethods#create!].
150
159
  def create!(*args, &block)
151
160
  scoping { @klass.create!(*args, &block) }
152
161
  end
@@ -180,7 +189,7 @@ module ActiveRecord
180
189
  # User.create_with(last_name: 'Johansson').find_or_create_by(first_name: 'Scarlett')
181
190
  # # => #<User id: 2, first_name: "Scarlett", last_name: "Johansson">
182
191
  #
183
- # This method accepts a block, which is passed down to +create+. The last example
192
+ # This method accepts a block, which is passed down to #create. The last example
184
193
  # above can be alternatively written this way:
185
194
  #
186
195
  # # Find the first user named "Scarlett" or create a new one with a
@@ -192,7 +201,7 @@ module ActiveRecord
192
201
  #
193
202
  # This method always returns a record, but if creation was attempted and
194
203
  # failed due to validation errors it won't be persisted, you get what
195
- # +create+ returns in such situation.
204
+ # #create returns in such situation.
196
205
  #
197
206
  # Please note *this method is not atomic*, it runs first a SELECT, and if
198
207
  # there are no results an INSERT is attempted. If there are other threads
@@ -204,7 +213,9 @@ module ActiveRecord
204
213
  # constraint an exception may be raised, just retry:
205
214
  #
206
215
  # begin
207
- # CreditAccount.find_or_create_by(user_id: user.id)
216
+ # CreditAccount.transaction(requires_new: true) do
217
+ # CreditAccount.find_or_create_by(user_id: user.id)
218
+ # end
208
219
  # rescue ActiveRecord::RecordNotUnique
209
220
  # retry
210
221
  # end
@@ -213,13 +224,15 @@ module ActiveRecord
213
224
  find_by(attributes) || create(attributes, &block)
214
225
  end
215
226
 
216
- # Like <tt>find_or_create_by</tt>, but calls <tt>create!</tt> so an exception
227
+ # Like #find_or_create_by, but calls
228
+ # {create!}[rdoc-ref:Persistence::ClassMethods#create!] so an exception
217
229
  # is raised if the created record is invalid.
218
230
  def find_or_create_by!(attributes, &block)
219
231
  find_by(attributes) || create!(attributes, &block)
220
232
  end
221
233
 
222
- # Like <tt>find_or_create_by</tt>, but calls <tt>new</tt> instead of <tt>create</tt>.
234
+ # Like #find_or_create_by, but calls {new}[rdoc-ref:Core#new]
235
+ # instead of {create}[rdoc-ref:Persistence::ClassMethods#create].
223
236
  def find_or_initialize_by(attributes, &block)
224
237
  find_by(attributes) || new(attributes, &block)
225
238
  end
@@ -240,17 +253,21 @@ module ActiveRecord
240
253
 
241
254
  # Converts relation objects to Array.
242
255
  def to_a
256
+ records.dup
257
+ end
258
+
259
+ def records # :nodoc:
243
260
  load
244
261
  @records
245
262
  end
246
263
 
247
264
  # Serializes the relation objects Array.
248
265
  def encode_with(coder)
249
- coder.represent_seq(nil, to_a)
266
+ coder.represent_seq(nil, records)
250
267
  end
251
268
 
252
269
  def as_json(options = nil) #:nodoc:
253
- to_a.as_json(options)
270
+ records.as_json(options)
254
271
  end
255
272
 
256
273
  # Returns size of the records.
@@ -270,22 +287,54 @@ module ActiveRecord
270
287
  end
271
288
  end
272
289
 
290
+ # Returns true if there are no records.
291
+ def none?
292
+ return super if block_given?
293
+ empty?
294
+ end
295
+
273
296
  # Returns true if there are any records.
274
297
  def any?
275
- if block_given?
276
- to_a.any? { |*block_args| yield(*block_args) }
277
- else
278
- !empty?
279
- end
298
+ return super if block_given?
299
+ !empty?
300
+ end
301
+
302
+ # Returns true if there is exactly one record.
303
+ def one?
304
+ return super if block_given?
305
+ limit_value ? records.one? : size == 1
280
306
  end
281
307
 
282
308
  # Returns true if there is more than one record.
283
309
  def many?
284
- if block_given?
285
- to_a.many? { |*block_args| yield(*block_args) }
286
- else
287
- limit_value ? to_a.many? : size > 1
288
- end
310
+ return super if block_given?
311
+ limit_value ? records.many? : size > 1
312
+ end
313
+
314
+ # Returns a cache key that can be used to identify the records fetched by
315
+ # this query. The cache key is built with a fingerprint of the sql query,
316
+ # the number of records matched by the query and a timestamp of the last
317
+ # updated record. When a new record comes to match the query, or any of
318
+ # the existing records is updated or deleted, the cache key changes.
319
+ #
320
+ # Product.where("name like ?", "%Cosmic Encounter%").cache_key
321
+ # # => "products/query-1850ab3d302391b85b8693e941286659-1-20150714212553907087000"
322
+ #
323
+ # If the collection is loaded, the method will iterate through the records
324
+ # to generate the timestamp, otherwise it will trigger one SQL query like:
325
+ #
326
+ # SELECT COUNT(*), MAX("products"."updated_at") FROM "products" WHERE (name like '%Cosmic Encounter%')
327
+ #
328
+ # You can also pass a custom timestamp column to fetch the timestamp of the
329
+ # last updated record.
330
+ #
331
+ # Product.where("name like ?", "%Game%").cache_key(:last_reviewed_at)
332
+ #
333
+ # You can customize the strategy to generate the key on a per model basis
334
+ # overriding ActiveRecord::Base#collection_cache_key.
335
+ def cache_key(timestamp_column = :updated_at)
336
+ @cache_keys ||= {}
337
+ @cache_keys[timestamp_column] ||= @klass.collection_cache_key(self, timestamp_column)
289
338
  end
290
339
 
291
340
  # Scope all queries to the current scope.
@@ -298,7 +347,7 @@ module ActiveRecord
298
347
  # Please check unscoped if you want to remove all previous scopes (including
299
348
  # the default_scope) during the execution of a block.
300
349
  def scoping
301
- previous, klass.current_scope = klass.current_scope, self
350
+ previous, klass.current_scope = klass.current_scope(true), self
302
351
  yield
303
352
  ensure
304
353
  klass.current_scope = previous
@@ -306,9 +355,8 @@ module ActiveRecord
306
355
 
307
356
  # Updates all records in the current relation with details given. This method constructs a single SQL UPDATE
308
357
  # statement and sends it straight to the database. It does not instantiate the involved models and it does not
309
- # trigger Active Record callbacks or validations. Values passed to `update_all` will not go through
310
- # ActiveRecord's type-casting behavior. It should receive only values that can be passed as-is to the SQL
311
- # database.
358
+ # trigger Active Record callbacks or validations. However, values passed to #update_all will still go through
359
+ # Active Record's normal type casting and serialization.
312
360
  #
313
361
  # ==== Parameters
314
362
  #
@@ -324,25 +372,27 @@ module ActiveRecord
324
372
  #
325
373
  # # Update all books that match conditions, but limit it to 5 ordered by date
326
374
  # Book.where('title LIKE ?', '%Rails%').order(:created_at).limit(5).update_all(author: 'David')
375
+ #
376
+ # # Update all invoices and set the number column to its id value.
377
+ # Invoice.update_all('number = id')
327
378
  def update_all(updates)
328
379
  raise ArgumentError, "Empty list of attributes to change" if updates.blank?
329
380
 
330
- stmt = Arel::UpdateManager.new(arel.engine)
381
+ stmt = Arel::UpdateManager.new
331
382
 
332
383
  stmt.set Arel.sql(@klass.send(:sanitize_sql_for_assignment, updates))
333
384
  stmt.table(table)
334
- stmt.key = table[primary_key]
335
385
 
336
386
  if joins_values.any?
337
- @klass.connection.join_to_update(stmt, arel)
387
+ @klass.connection.join_to_update(stmt, arel, arel_attribute(primary_key))
338
388
  else
389
+ stmt.key = arel_attribute(primary_key)
339
390
  stmt.take(arel.limit)
340
391
  stmt.order(*arel.orders)
341
392
  stmt.wheres = arel.constraints
342
393
  end
343
394
 
344
- bvs = arel.bind_values + bind_values
345
- @klass.connection.update stmt, 'SQL', bvs
395
+ @klass.connection.update stmt, 'SQL', bound_attributes
346
396
  end
347
397
 
348
398
  # Updates an object (or multiple objects) and saves it to the database, if validations pass.
@@ -361,20 +411,39 @@ module ActiveRecord
361
411
  # # Updates multiple records
362
412
  # people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy" } }
363
413
  # Person.update(people.keys, people.values)
364
- def update(id, attributes)
414
+ #
415
+ # # Updates multiple records from the result of a relation
416
+ # people = Person.where(group: 'expert')
417
+ # people.update(group: 'masters')
418
+ #
419
+ # Note: Updating a large number of records will run an
420
+ # UPDATE query for each record, which may cause a performance
421
+ # issue. So if it is not needed to run callbacks for each update, it is
422
+ # preferred to use #update_all for updating all records using
423
+ # a single query.
424
+ def update(id = :all, attributes)
365
425
  if id.is_a?(Array)
366
426
  id.map.with_index { |one_id, idx| update(one_id, attributes[idx]) }
427
+ elsif id == :all
428
+ records.each { |record| record.update(attributes) }
367
429
  else
430
+ if ActiveRecord::Base === id
431
+ id = id.id
432
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
433
+ You are passing an instance of ActiveRecord::Base to `update`.
434
+ Please pass the id of the object by calling `.id`.
435
+ MSG
436
+ end
368
437
  object = find(id)
369
438
  object.update(attributes)
370
439
  object
371
440
  end
372
441
  end
373
442
 
374
- # Destroys the records matching +conditions+ by instantiating each
375
- # record and calling its +destroy+ method. Each object's callbacks are
376
- # executed (including <tt>:dependent</tt> association options). Returns the
377
- # collection of objects that were destroyed; each will be frozen, to
443
+ # Destroys the records by instantiating each
444
+ # record and calling its {#destroy}[rdoc-ref:Persistence#destroy] method.
445
+ # Each object's callbacks are executed (including <tt>:dependent</tt> association options).
446
+ # Returns the collection of objects that were destroyed; each will be frozen, to
378
447
  # reflect that no changes should be made (since they can't be persisted).
379
448
  #
380
449
  # Note: Instantiation, callback execution, and deletion of each
@@ -382,31 +451,26 @@ module ActiveRecord
382
451
  # once. It generates at least one SQL +DELETE+ query per record (or
383
452
  # possibly more, to enforce your callbacks). If you want to delete many
384
453
  # rows quickly, without concern for their associations or callbacks, use
385
- # +delete_all+ instead.
386
- #
387
- # ==== Parameters
388
- #
389
- # * +conditions+ - A string, array, or hash that specifies which records
390
- # to destroy. If omitted, all records are destroyed. See the
391
- # Conditions section in the introduction to ActiveRecord::Base for
392
- # more information.
454
+ # #delete_all instead.
393
455
  #
394
456
  # ==== Examples
395
457
  #
396
- # Person.destroy_all("last_login < '2004-04-04'")
397
- # Person.destroy_all(status: "inactive")
398
458
  # Person.where(age: 0..18).destroy_all
399
459
  def destroy_all(conditions = nil)
400
460
  if conditions
461
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
462
+ Passing conditions to destroy_all is deprecated and will be removed in Rails 5.1.
463
+ To achieve the same use where(conditions).destroy_all.
464
+ MESSAGE
401
465
  where(conditions).destroy_all
402
466
  else
403
- to_a.each {|object| object.destroy }.tap { reset }
467
+ records.each(&:destroy).tap { reset }
404
468
  end
405
469
  end
406
470
 
407
471
  # Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
408
472
  # therefore all callbacks and filters are fired off before the object is deleted. This method is
409
- # less efficient than ActiveRecord#delete but allows cleanup methods and other actions to be run.
473
+ # less efficient than #delete but allows cleanup methods and other actions to be run.
410
474
  #
411
475
  # This essentially finds the object (or multiple objects) with the given id, creates a new object
412
476
  # from the attributes, and then calls destroy on it.
@@ -431,22 +495,21 @@ module ActiveRecord
431
495
  end
432
496
  end
433
497
 
434
- # Deletes the records matching +conditions+ without instantiating the records
435
- # first, and hence not calling the +destroy+ method nor invoking callbacks. This
436
- # is a single SQL DELETE statement that goes straight to the database, much more
437
- # efficient than +destroy_all+. Be careful with relations though, in particular
498
+ # Deletes the records without instantiating the records
499
+ # first, and hence not calling the {#destroy}[rdoc-ref:Persistence#destroy]
500
+ # method nor invoking callbacks.
501
+ # This is a single SQL DELETE statement that goes straight to the database, much more
502
+ # efficient than #destroy_all. Be careful with relations though, in particular
438
503
  # <tt>:dependent</tt> rules defined on associations are not honored. Returns the
439
504
  # number of rows affected.
440
505
  #
441
- # Post.delete_all("person_id = 5 AND (category = 'Something' OR category = 'Else')")
442
- # Post.delete_all(["person_id = ? AND (category = ? OR category = ?)", 5, 'Something', 'Else'])
443
506
  # Post.where(person_id: 5).where(category: ['Something', 'Else']).delete_all
444
507
  #
445
508
  # Both calls delete the affected posts all at once with a single DELETE statement.
446
509
  # If you need to destroy dependent associations or call your <tt>before_*</tt> or
447
- # +after_destroy+ callbacks, use the +destroy_all+ method instead.
510
+ # +after_destroy+ callbacks, use the #destroy_all method instead.
448
511
  #
449
- # If an invalid method is supplied, +delete_all+ raises an ActiveRecord error:
512
+ # If an invalid method is supplied, #delete_all raises an ActiveRecordError:
450
513
  #
451
514
  # Post.limit(100).delete_all
452
515
  # # => ActiveRecord::ActiveRecordError: delete_all doesn't support limit
@@ -454,8 +517,10 @@ module ActiveRecord
454
517
  invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select { |method|
455
518
  if MULTI_VALUE_METHODS.include?(method)
456
519
  send("#{method}_values").any?
457
- else
520
+ elsif SINGLE_VALUE_METHODS.include?(method)
458
521
  send("#{method}_value")
522
+ elsif CLAUSE_METHODS.include?(method)
523
+ send("#{method}_clause").any?
459
524
  end
460
525
  }
461
526
  if invalid_methods.any?
@@ -463,19 +528,22 @@ module ActiveRecord
463
528
  end
464
529
 
465
530
  if conditions
531
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
532
+ Passing conditions to delete_all is deprecated and will be removed in Rails 5.1.
533
+ To achieve the same use where(conditions).delete_all.
534
+ MESSAGE
466
535
  where(conditions).delete_all
467
536
  else
468
- stmt = Arel::DeleteManager.new(arel.engine)
537
+ stmt = Arel::DeleteManager.new
469
538
  stmt.from(table)
470
539
 
471
540
  if joins_values.any?
472
- @klass.connection.join_to_delete(stmt, arel, table[primary_key])
541
+ @klass.connection.join_to_delete(stmt, arel, arel_attribute(primary_key))
473
542
  else
474
543
  stmt.wheres = arel.constraints
475
544
  end
476
545
 
477
- bvs = arel.bind_values + bind_values
478
- affected = @klass.connection.delete(stmt, 'SQL', bvs)
546
+ affected = @klass.connection.delete(stmt, 'SQL', bound_attributes)
479
547
 
480
548
  reset
481
549
  affected
@@ -490,7 +558,7 @@ module ActiveRecord
490
558
  # You can delete multiple rows at once by passing an Array of <tt>id</tt>s.
491
559
  #
492
560
  # Note: Although it is often much faster than the alternative,
493
- # <tt>#destroy</tt>, skipping callbacks might bypass business logic in
561
+ # #destroy, skipping callbacks might bypass business logic in
494
562
  # your application that ensures referential integrity or performs other
495
563
  # essential jobs.
496
564
  #
@@ -511,8 +579,8 @@ module ActiveRecord
511
579
  # return value is the relation itself, not the records.
512
580
  #
513
581
  # Post.where(published: true).load # => #<ActiveRecord::Relation>
514
- def load
515
- exec_queries unless loaded?
582
+ def load(&block)
583
+ exec_queries(&block) unless loaded?
516
584
 
517
585
  self
518
586
  end
@@ -526,7 +594,7 @@ module ActiveRecord
526
594
  def reset
527
595
  @last = @to_sql = @order_clause = @scope_for_create = @arel = @loaded = nil
528
596
  @should_eager_load = @join_dependency = nil
529
- @records = []
597
+ @records = [].freeze
530
598
  @offsets = {}
531
599
  self
532
600
  end
@@ -545,10 +613,10 @@ module ActiveRecord
545
613
  find_with_associations { |rel| relation = rel }
546
614
  end
547
615
 
548
- arel = relation.arel
549
- binds = (arel.bind_values + relation.bind_values).dup
550
- binds.map! { |bv| connection.quote(*bv.reverse) }
551
- collect = visitor.accept(arel.ast, Arel::Collectors::Bind.new)
616
+ binds = relation.bound_attributes
617
+ binds = connection.prepare_binds_for_database(binds)
618
+ binds.map! { |value| connection.quote(value) }
619
+ collect = visitor.accept(relation.arel.ast, Arel::Collectors::Bind.new)
552
620
  collect.substitute_binds(binds).join
553
621
  end
554
622
  end
@@ -558,22 +626,7 @@ module ActiveRecord
558
626
  # User.where(name: 'Oscar').where_values_hash
559
627
  # # => {name: "Oscar"}
560
628
  def where_values_hash(relation_table_name = table_name)
561
- equalities = where_values.grep(Arel::Nodes::Equality).find_all { |node|
562
- node.left.relation.name == relation_table_name
563
- }
564
-
565
- binds = Hash[bind_values.find_all(&:first).map { |column, v| [column.name, v] }]
566
-
567
- Hash[equalities.map { |where|
568
- name = where.left.name
569
- [name, binds.fetch(name.to_s) {
570
- case where.right
571
- when Array then where.right.map(&:val)
572
- when Arel::Nodes::Casted
573
- where.right.val
574
- end
575
- }]
576
- }]
629
+ where_clause.to_h(relation_table_name)
577
630
  end
578
631
 
579
632
  def scope_for_create
@@ -595,31 +648,34 @@ module ActiveRecord
595
648
  includes_values & joins_values
596
649
  end
597
650
 
598
- # +uniq+ and +uniq!+ are silently deprecated. +uniq_value+ delegates to +distinct_value+
599
- # to maintain backwards compatibility. Use +distinct_value+ instead.
651
+ # {#uniq}[rdoc-ref:QueryMethods#uniq] and
652
+ # {#uniq!}[rdoc-ref:QueryMethods#uniq!] are silently deprecated.
653
+ # #uniq_value delegates to #distinct_value to maintain backwards compatibility.
654
+ # Use #distinct_value instead.
600
655
  def uniq_value
601
656
  distinct_value
602
657
  end
658
+ deprecate uniq_value: :distinct_value
603
659
 
604
660
  # Compares two relations for equality.
605
661
  def ==(other)
606
662
  case other
607
663
  when Associations::CollectionProxy, AssociationRelation
608
- self == other.to_a
664
+ self == other.records
609
665
  when Relation
610
666
  other.to_sql == to_sql
611
667
  when Array
612
- to_a == other
668
+ records == other
613
669
  end
614
670
  end
615
671
 
616
672
  def pretty_print(q)
617
- q.pp(self.to_a)
673
+ q.pp(self.records)
618
674
  end
619
675
 
620
676
  # Returns true if relation is blank.
621
677
  def blank?
622
- to_a.blank?
678
+ records.blank?
623
679
  end
624
680
 
625
681
  def values
@@ -627,16 +683,27 @@ module ActiveRecord
627
683
  end
628
684
 
629
685
  def inspect
630
- entries = to_a.take([limit_value, 11].compact.min).map!(&:inspect)
686
+ entries = records.take([limit_value, 11].compact.min).map!(&:inspect)
631
687
  entries[10] = '...' if entries.size == 11
632
688
 
633
689
  "#<#{self.class.name} [#{entries.join(', ')}]>"
634
690
  end
635
691
 
692
+ def empty_scope? # :nodoc:
693
+ @values == klass.unscoped.values
694
+ end
695
+
696
+ protected
697
+
698
+ def load_records(records)
699
+ @records = records.freeze
700
+ @loaded = true
701
+ end
702
+
636
703
  private
637
704
 
638
- def exec_queries
639
- @records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel, arel.bind_values + bind_values)
705
+ def exec_queries(&block)
706
+ @records = eager_loading? ? find_with_associations.freeze : @klass.find_by_sql(arel, bound_attributes, &block).freeze
640
707
 
641
708
  preload = preload_values
642
709
  preload += includes_values unless eager_loading?
@@ -645,7 +712,7 @@ module ActiveRecord
645
712
  preloader.preload @records, associations
646
713
  end
647
714
 
648
- @records.each { |record| record.readonly! } if readonly_value
715
+ @records.each(&:readonly!) if readonly_value
649
716
 
650
717
  @loaded = true
651
718
  @records
@@ -667,7 +734,7 @@ module ActiveRecord
667
734
  joined_tables += [table.name, table.table_alias]
668
735
 
669
736
  # always convert table names to downcase as in Oracle quoted table names are in uppercase
670
- joined_tables = joined_tables.flatten.compact.map { |t| t.downcase }.uniq
737
+ joined_tables = joined_tables.flatten.compact.map(&:downcase).uniq
671
738
 
672
739
  (references_values - joined_tables).any?
673
740
  end
@@ -676,7 +743,7 @@ module ActiveRecord
676
743
  return [] if string.blank?
677
744
  # always convert table names to downcase as in Oracle quoted table names are in uppercase
678
745
  # ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
679
- string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map{ |s| s.downcase }.uniq - ['raw_sql_']
746
+ string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map(&:downcase).uniq - ['raw_sql_']
680
747
  end
681
748
  end
682
749
  end