activerecord 4.2.6 → 5.0.0

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 (246) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1307 -1105
  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/aggregations.rb +37 -23
  8. data/lib/active_record/association_relation.rb +3 -3
  9. data/lib/active_record/associations/alias_tracker.rb +19 -16
  10. data/lib/active_record/associations/association.rb +11 -9
  11. data/lib/active_record/associations/association_scope.rb +73 -102
  12. data/lib/active_record/associations/belongs_to_association.rb +21 -32
  13. data/lib/active_record/associations/builder/association.rb +28 -34
  14. data/lib/active_record/associations/builder/belongs_to.rb +43 -18
  15. data/lib/active_record/associations/builder/collection_association.rb +7 -19
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +14 -11
  17. data/lib/active_record/associations/builder/has_many.rb +4 -4
  18. data/lib/active_record/associations/builder/has_one.rb +11 -6
  19. data/lib/active_record/associations/builder/singular_association.rb +3 -10
  20. data/lib/active_record/associations/collection_association.rb +50 -31
  21. data/lib/active_record/associations/collection_proxy.rb +69 -29
  22. data/lib/active_record/associations/foreign_association.rb +1 -1
  23. data/lib/active_record/associations/has_many_association.rb +20 -71
  24. data/lib/active_record/associations/has_many_through_association.rb +8 -47
  25. data/lib/active_record/associations/has_one_association.rb +12 -5
  26. data/lib/active_record/associations/join_dependency/join_association.rb +20 -8
  27. data/lib/active_record/associations/join_dependency.rb +29 -19
  28. data/lib/active_record/associations/preloader/association.rb +46 -52
  29. data/lib/active_record/associations/preloader/collection_association.rb +0 -6
  30. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  31. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  32. data/lib/active_record/associations/preloader/through_association.rb +27 -14
  33. data/lib/active_record/associations/preloader.rb +14 -4
  34. data/lib/active_record/associations/singular_association.rb +7 -1
  35. data/lib/active_record/associations/through_association.rb +11 -3
  36. data/lib/active_record/associations.rb +317 -209
  37. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  38. data/lib/active_record/attribute.rb +68 -18
  39. data/lib/active_record/attribute_assignment.rb +20 -141
  40. data/lib/active_record/attribute_decorators.rb +6 -5
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  42. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  43. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  44. data/lib/active_record/attribute_methods/query.rb +2 -2
  45. data/lib/active_record/attribute_methods/read.rb +31 -59
  46. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
  48. data/lib/active_record/attribute_methods/write.rb +14 -38
  49. data/lib/active_record/attribute_methods.rb +70 -45
  50. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  51. data/lib/active_record/attribute_set/builder.rb +6 -4
  52. data/lib/active_record/attribute_set.rb +30 -3
  53. data/lib/active_record/attributes.rb +199 -80
  54. data/lib/active_record/autosave_association.rb +49 -16
  55. data/lib/active_record/base.rb +32 -23
  56. data/lib/active_record/callbacks.rb +39 -43
  57. data/lib/active_record/coders/json.rb +1 -1
  58. data/lib/active_record/coders/yaml_column.rb +20 -8
  59. data/lib/active_record/collection_cache_key.rb +40 -0
  60. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +452 -182
  61. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  62. data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -61
  63. data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -2
  64. data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -9
  65. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  66. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
  67. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -185
  68. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
  69. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +378 -140
  70. data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
  71. data/lib/active_record/connection_adapters/abstract_adapter.rb +153 -59
  72. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +405 -362
  73. data/lib/active_record/connection_adapters/column.rb +28 -43
  74. data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
  75. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  76. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  77. data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
  78. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  79. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  80. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  81. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  82. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  83. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  84. data/lib/active_record/connection_adapters/mysql2_adapter.rb +25 -176
  85. data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
  86. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +10 -72
  87. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -56
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  93. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  95. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  96. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
  97. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  98. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
  100. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  101. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  102. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  103. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  104. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  105. data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
  106. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  107. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  108. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  109. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +234 -148
  110. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  111. data/lib/active_record/connection_adapters/postgresql_adapter.rb +248 -160
  112. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  113. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  114. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  115. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  116. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  117. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +148 -203
  118. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  119. data/lib/active_record/connection_handling.rb +37 -14
  120. data/lib/active_record/core.rb +89 -107
  121. data/lib/active_record/counter_cache.rb +13 -24
  122. data/lib/active_record/dynamic_matchers.rb +1 -20
  123. data/lib/active_record/enum.rb +113 -76
  124. data/lib/active_record/errors.rb +87 -48
  125. data/lib/active_record/explain_registry.rb +1 -1
  126. data/lib/active_record/explain_subscriber.rb +1 -1
  127. data/lib/active_record/fixture_set/file.rb +26 -5
  128. data/lib/active_record/fixtures.rb +76 -40
  129. data/lib/active_record/gem_version.rb +3 -3
  130. data/lib/active_record/inheritance.rb +32 -40
  131. data/lib/active_record/integration.rb +4 -4
  132. data/lib/active_record/internal_metadata.rb +56 -0
  133. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  134. data/lib/active_record/locale/en.yml +3 -2
  135. data/lib/active_record/locking/optimistic.rb +15 -15
  136. data/lib/active_record/locking/pessimistic.rb +1 -1
  137. data/lib/active_record/log_subscriber.rb +43 -21
  138. data/lib/active_record/migration/command_recorder.rb +59 -18
  139. data/lib/active_record/migration/compatibility.rb +126 -0
  140. data/lib/active_record/migration.rb +364 -109
  141. data/lib/active_record/model_schema.rb +128 -38
  142. data/lib/active_record/nested_attributes.rb +58 -29
  143. data/lib/active_record/null_relation.rb +16 -8
  144. data/lib/active_record/persistence.rb +121 -80
  145. data/lib/active_record/query_cache.rb +15 -18
  146. data/lib/active_record/querying.rb +10 -9
  147. data/lib/active_record/railtie.rb +27 -18
  148. data/lib/active_record/railties/controller_runtime.rb +1 -1
  149. data/lib/active_record/railties/databases.rake +58 -45
  150. data/lib/active_record/readonly_attributes.rb +1 -1
  151. data/lib/active_record/reflection.rb +282 -115
  152. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  153. data/lib/active_record/relation/batches.rb +139 -34
  154. data/lib/active_record/relation/calculations.rb +80 -102
  155. data/lib/active_record/relation/delegation.rb +7 -20
  156. data/lib/active_record/relation/finder_methods.rb +163 -81
  157. data/lib/active_record/relation/from_clause.rb +32 -0
  158. data/lib/active_record/relation/merger.rb +16 -42
  159. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -15
  160. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  161. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  162. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  163. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  164. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  165. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  166. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  167. data/lib/active_record/relation/predicate_builder.rb +120 -107
  168. data/lib/active_record/relation/query_attribute.rb +19 -0
  169. data/lib/active_record/relation/query_methods.rb +308 -244
  170. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  171. data/lib/active_record/relation/spawn_methods.rb +4 -7
  172. data/lib/active_record/relation/where_clause.rb +174 -0
  173. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  174. data/lib/active_record/relation.rb +176 -116
  175. data/lib/active_record/result.rb +4 -3
  176. data/lib/active_record/runtime_registry.rb +1 -1
  177. data/lib/active_record/sanitization.rb +95 -66
  178. data/lib/active_record/schema.rb +26 -22
  179. data/lib/active_record/schema_dumper.rb +62 -38
  180. data/lib/active_record/schema_migration.rb +11 -17
  181. data/lib/active_record/scoping/default.rb +23 -9
  182. data/lib/active_record/scoping/named.rb +49 -28
  183. data/lib/active_record/scoping.rb +32 -15
  184. data/lib/active_record/secure_token.rb +38 -0
  185. data/lib/active_record/serialization.rb +2 -4
  186. data/lib/active_record/statement_cache.rb +16 -14
  187. data/lib/active_record/store.rb +8 -3
  188. data/lib/active_record/suppressor.rb +58 -0
  189. data/lib/active_record/table_metadata.rb +68 -0
  190. data/lib/active_record/tasks/database_tasks.rb +58 -41
  191. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -20
  192. data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
  193. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  194. data/lib/active_record/timestamp.rb +20 -9
  195. data/lib/active_record/touch_later.rb +58 -0
  196. data/lib/active_record/transactions.rb +138 -56
  197. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  198. data/lib/active_record/type/date.rb +2 -41
  199. data/lib/active_record/type/date_time.rb +2 -49
  200. data/lib/active_record/type/internal/abstract_json.rb +29 -0
  201. data/lib/active_record/type/internal/timezone.rb +15 -0
  202. data/lib/active_record/type/serialized.rb +15 -14
  203. data/lib/active_record/type/time.rb +10 -16
  204. data/lib/active_record/type/type_map.rb +4 -4
  205. data/lib/active_record/type.rb +66 -17
  206. data/lib/active_record/type_caster/connection.rb +29 -0
  207. data/lib/active_record/type_caster/map.rb +19 -0
  208. data/lib/active_record/type_caster.rb +7 -0
  209. data/lib/active_record/validations/absence.rb +23 -0
  210. data/lib/active_record/validations/associated.rb +10 -3
  211. data/lib/active_record/validations/length.rb +24 -0
  212. data/lib/active_record/validations/presence.rb +11 -12
  213. data/lib/active_record/validations/uniqueness.rb +30 -29
  214. data/lib/active_record/validations.rb +33 -32
  215. data/lib/active_record.rb +7 -2
  216. data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
  217. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  218. data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
  219. data/lib/rails/generators/active_record/migration.rb +7 -0
  220. data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
  221. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  222. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  223. metadata +58 -34
  224. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  225. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  226. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  227. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  228. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  229. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  230. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  231. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  232. data/lib/active_record/type/big_integer.rb +0 -13
  233. data/lib/active_record/type/binary.rb +0 -50
  234. data/lib/active_record/type/boolean.rb +0 -31
  235. data/lib/active_record/type/decimal.rb +0 -50
  236. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  237. data/lib/active_record/type/decorator.rb +0 -14
  238. data/lib/active_record/type/float.rb +0 -19
  239. data/lib/active_record/type/integer.rb +0 -59
  240. data/lib/active_record/type/mutable.rb +0 -16
  241. data/lib/active_record/type/numeric.rb +0 -36
  242. data/lib/active_record/type/string.rb +0 -40
  243. data/lib/active_record/type/text.rb +0 -11
  244. data/lib/active_record/type/time_value.rb +0 -38
  245. data/lib/active_record/type/unsigned_integer.rb +0 -15
  246. data/lib/active_record/type/value.rb +0 -105
@@ -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.
@@ -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
  #
@@ -327,22 +375,21 @@ module ActiveRecord
327
375
  def update_all(updates)
328
376
  raise ArgumentError, "Empty list of attributes to change" if updates.blank?
329
377
 
330
- stmt = Arel::UpdateManager.new(arel.engine)
378
+ stmt = Arel::UpdateManager.new
331
379
 
332
380
  stmt.set Arel.sql(@klass.send(:sanitize_sql_for_assignment, updates))
333
381
  stmt.table(table)
334
- stmt.key = table[primary_key]
335
382
 
336
383
  if joins_values.any?
337
- @klass.connection.join_to_update(stmt, arel)
384
+ @klass.connection.join_to_update(stmt, arel, arel_attribute(primary_key))
338
385
  else
386
+ stmt.key = arel_attribute(primary_key)
339
387
  stmt.take(arel.limit)
340
388
  stmt.order(*arel.orders)
341
389
  stmt.wheres = arel.constraints
342
390
  end
343
391
 
344
- bvs = arel.bind_values + bind_values
345
- @klass.connection.update stmt, 'SQL', bvs
392
+ @klass.connection.update stmt, 'SQL', bound_attributes
346
393
  end
347
394
 
348
395
  # Updates an object (or multiple objects) and saves it to the database, if validations pass.
@@ -361,20 +408,39 @@ module ActiveRecord
361
408
  # # Updates multiple records
362
409
  # people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy" } }
363
410
  # Person.update(people.keys, people.values)
364
- def update(id, attributes)
411
+ #
412
+ # # Updates multiple records from the result of a relation
413
+ # people = Person.where(group: 'expert')
414
+ # people.update(group: 'masters')
415
+ #
416
+ # Note: Updating a large number of records will run an
417
+ # UPDATE query for each record, which may cause a performance
418
+ # issue. So if it is not needed to run callbacks for each update, it is
419
+ # preferred to use #update_all for updating all records using
420
+ # a single query.
421
+ def update(id = :all, attributes)
365
422
  if id.is_a?(Array)
366
423
  id.map.with_index { |one_id, idx| update(one_id, attributes[idx]) }
424
+ elsif id == :all
425
+ records.each { |record| record.update(attributes) }
367
426
  else
427
+ if ActiveRecord::Base === id
428
+ id = id.id
429
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
430
+ You are passing an instance of ActiveRecord::Base to `update`.
431
+ Please pass the id of the object by calling `.id`.
432
+ MSG
433
+ end
368
434
  object = find(id)
369
435
  object.update(attributes)
370
436
  object
371
437
  end
372
438
  end
373
439
 
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
440
+ # Destroys the records by instantiating each
441
+ # record and calling its {#destroy}[rdoc-ref:Persistence#destroy] method.
442
+ # Each object's callbacks are executed (including <tt>:dependent</tt> association options).
443
+ # Returns the collection of objects that were destroyed; each will be frozen, to
378
444
  # reflect that no changes should be made (since they can't be persisted).
379
445
  #
380
446
  # Note: Instantiation, callback execution, and deletion of each
@@ -382,31 +448,26 @@ module ActiveRecord
382
448
  # once. It generates at least one SQL +DELETE+ query per record (or
383
449
  # possibly more, to enforce your callbacks). If you want to delete many
384
450
  # 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.
451
+ # #delete_all instead.
393
452
  #
394
453
  # ==== Examples
395
454
  #
396
- # Person.destroy_all("last_login < '2004-04-04'")
397
- # Person.destroy_all(status: "inactive")
398
455
  # Person.where(age: 0..18).destroy_all
399
456
  def destroy_all(conditions = nil)
400
457
  if conditions
458
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
459
+ Passing conditions to destroy_all is deprecated and will be removed in Rails 5.1.
460
+ To achieve the same use where(conditions).destroy_all.
461
+ MESSAGE
401
462
  where(conditions).destroy_all
402
463
  else
403
- to_a.each {|object| object.destroy }.tap { reset }
464
+ records.each(&:destroy).tap { reset }
404
465
  end
405
466
  end
406
467
 
407
468
  # Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
408
469
  # 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.
470
+ # less efficient than #delete but allows cleanup methods and other actions to be run.
410
471
  #
411
472
  # This essentially finds the object (or multiple objects) with the given id, creates a new object
412
473
  # from the attributes, and then calls destroy on it.
@@ -431,22 +492,21 @@ module ActiveRecord
431
492
  end
432
493
  end
433
494
 
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
495
+ # Deletes the records without instantiating the records
496
+ # first, and hence not calling the {#destroy}[rdoc-ref:Persistence#destroy]
497
+ # method nor invoking callbacks.
498
+ # This is a single SQL DELETE statement that goes straight to the database, much more
499
+ # efficient than #destroy_all. Be careful with relations though, in particular
438
500
  # <tt>:dependent</tt> rules defined on associations are not honored. Returns the
439
501
  # number of rows affected.
440
502
  #
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
503
  # Post.where(person_id: 5).where(category: ['Something', 'Else']).delete_all
444
504
  #
445
505
  # Both calls delete the affected posts all at once with a single DELETE statement.
446
506
  # If you need to destroy dependent associations or call your <tt>before_*</tt> or
447
- # +after_destroy+ callbacks, use the +destroy_all+ method instead.
507
+ # +after_destroy+ callbacks, use the #destroy_all method instead.
448
508
  #
449
- # If an invalid method is supplied, +delete_all+ raises an ActiveRecord error:
509
+ # If an invalid method is supplied, #delete_all raises an ActiveRecordError:
450
510
  #
451
511
  # Post.limit(100).delete_all
452
512
  # # => ActiveRecord::ActiveRecordError: delete_all doesn't support limit
@@ -454,8 +514,10 @@ module ActiveRecord
454
514
  invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select { |method|
455
515
  if MULTI_VALUE_METHODS.include?(method)
456
516
  send("#{method}_values").any?
457
- else
517
+ elsif SINGLE_VALUE_METHODS.include?(method)
458
518
  send("#{method}_value")
519
+ elsif CLAUSE_METHODS.include?(method)
520
+ send("#{method}_clause").any?
459
521
  end
460
522
  }
461
523
  if invalid_methods.any?
@@ -463,19 +525,22 @@ module ActiveRecord
463
525
  end
464
526
 
465
527
  if conditions
528
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
529
+ Passing conditions to delete_all is deprecated and will be removed in Rails 5.1.
530
+ To achieve the same use where(conditions).delete_all.
531
+ MESSAGE
466
532
  where(conditions).delete_all
467
533
  else
468
- stmt = Arel::DeleteManager.new(arel.engine)
534
+ stmt = Arel::DeleteManager.new
469
535
  stmt.from(table)
470
536
 
471
537
  if joins_values.any?
472
- @klass.connection.join_to_delete(stmt, arel, table[primary_key])
538
+ @klass.connection.join_to_delete(stmt, arel, arel_attribute(primary_key))
473
539
  else
474
540
  stmt.wheres = arel.constraints
475
541
  end
476
542
 
477
- bvs = arel.bind_values + bind_values
478
- affected = @klass.connection.delete(stmt, 'SQL', bvs)
543
+ affected = @klass.connection.delete(stmt, 'SQL', bound_attributes)
479
544
 
480
545
  reset
481
546
  affected
@@ -490,7 +555,7 @@ module ActiveRecord
490
555
  # You can delete multiple rows at once by passing an Array of <tt>id</tt>s.
491
556
  #
492
557
  # Note: Although it is often much faster than the alternative,
493
- # <tt>#destroy</tt>, skipping callbacks might bypass business logic in
558
+ # #destroy, skipping callbacks might bypass business logic in
494
559
  # your application that ensures referential integrity or performs other
495
560
  # essential jobs.
496
561
  #
@@ -526,7 +591,7 @@ module ActiveRecord
526
591
  def reset
527
592
  @last = @to_sql = @order_clause = @scope_for_create = @arel = @loaded = nil
528
593
  @should_eager_load = @join_dependency = nil
529
- @records = []
594
+ @records = [].freeze
530
595
  @offsets = {}
531
596
  self
532
597
  end
@@ -545,10 +610,10 @@ module ActiveRecord
545
610
  find_with_associations { |rel| relation = rel }
546
611
  end
547
612
 
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)
613
+ binds = relation.bound_attributes
614
+ binds = connection.prepare_binds_for_database(binds)
615
+ binds.map! { |value| connection.quote(value) }
616
+ collect = visitor.accept(relation.arel.ast, Arel::Collectors::Bind.new)
552
617
  collect.substitute_binds(binds).join
553
618
  end
554
619
  end
@@ -558,22 +623,7 @@ module ActiveRecord
558
623
  # User.where(name: 'Oscar').where_values_hash
559
624
  # # => {name: "Oscar"}
560
625
  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
- }]
626
+ where_clause.to_h(relation_table_name)
577
627
  end
578
628
 
579
629
  def scope_for_create
@@ -595,31 +645,34 @@ module ActiveRecord
595
645
  includes_values & joins_values
596
646
  end
597
647
 
598
- # +uniq+ and +uniq!+ are silently deprecated. +uniq_value+ delegates to +distinct_value+
599
- # to maintain backwards compatibility. Use +distinct_value+ instead.
648
+ # {#uniq}[rdoc-ref:QueryMethods#uniq] and
649
+ # {#uniq!}[rdoc-ref:QueryMethods#uniq!] are silently deprecated.
650
+ # #uniq_value delegates to #distinct_value to maintain backwards compatibility.
651
+ # Use #distinct_value instead.
600
652
  def uniq_value
601
653
  distinct_value
602
654
  end
655
+ deprecate uniq_value: :distinct_value
603
656
 
604
657
  # Compares two relations for equality.
605
658
  def ==(other)
606
659
  case other
607
660
  when Associations::CollectionProxy, AssociationRelation
608
- self == other.to_a
661
+ self == other.records
609
662
  when Relation
610
663
  other.to_sql == to_sql
611
664
  when Array
612
- to_a == other
665
+ records == other
613
666
  end
614
667
  end
615
668
 
616
669
  def pretty_print(q)
617
- q.pp(self.to_a)
670
+ q.pp(self.records)
618
671
  end
619
672
 
620
673
  # Returns true if relation is blank.
621
674
  def blank?
622
- to_a.blank?
675
+ records.blank?
623
676
  end
624
677
 
625
678
  def values
@@ -627,16 +680,23 @@ module ActiveRecord
627
680
  end
628
681
 
629
682
  def inspect
630
- entries = to_a.take([limit_value, 11].compact.min).map!(&:inspect)
683
+ entries = records.take([limit_value, 11].compact.min).map!(&:inspect)
631
684
  entries[10] = '...' if entries.size == 11
632
685
 
633
686
  "#<#{self.class.name} [#{entries.join(', ')}]>"
634
687
  end
635
688
 
689
+ protected
690
+
691
+ def load_records(records)
692
+ @records = records.freeze
693
+ @loaded = true
694
+ end
695
+
636
696
  private
637
697
 
638
698
  def exec_queries
639
- @records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel, arel.bind_values + bind_values)
699
+ @records = eager_loading? ? find_with_associations.freeze : @klass.find_by_sql(arel, bound_attributes).freeze
640
700
 
641
701
  preload = preload_values
642
702
  preload += includes_values unless eager_loading?
@@ -645,7 +705,7 @@ module ActiveRecord
645
705
  preloader.preload @records, associations
646
706
  end
647
707
 
648
- @records.each { |record| record.readonly! } if readonly_value
708
+ @records.each(&:readonly!) if readonly_value
649
709
 
650
710
  @loaded = true
651
711
  @records
@@ -667,7 +727,7 @@ module ActiveRecord
667
727
  joined_tables += [table.name, table.table_alias]
668
728
 
669
729
  # 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
730
+ joined_tables = joined_tables.flatten.compact.map(&:downcase).uniq
671
731
 
672
732
  (references_values - joined_tables).any?
673
733
  end
@@ -676,7 +736,7 @@ module ActiveRecord
676
736
  return [] if string.blank?
677
737
  # always convert table names to downcase as in Oracle quoted table names are in uppercase
678
738
  # 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_']
739
+ string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map(&:downcase).uniq - ['raw_sql_']
680
740
  end
681
741
  end
682
742
  end
@@ -1,7 +1,8 @@
1
1
  module ActiveRecord
2
2
  ###
3
- # This class encapsulates a Result returned from calling +exec_query+ on any
4
- # database connection adapter. For example:
3
+ # This class encapsulates a result returned from calling
4
+ # {#exec_query}[rdoc-ref:ConnectionAdapters::DatabaseStatements#exec_query]
5
+ # on any database connection adapter. For example:
5
6
  #
6
7
  # result = ActiveRecord::Base.connection.exec_query('SELECT id, title, body FROM posts')
7
8
  # result # => #<ActiveRecord::Result:0xdeadbeef>
@@ -81,7 +82,7 @@ module ActiveRecord
81
82
  def cast_values(type_overrides = {}) # :nodoc:
82
83
  types = columns.map { |name| column_type(name, type_overrides) }
83
84
  result = rows.map do |values|
84
- types.zip(values).map { |type, value| type.type_cast_from_database(value) }
85
+ types.zip(values).map { |type, value| type.deserialize(value) }
85
86
  end
86
87
 
87
88
  columns.one? ? result.map!(&:first) : result
@@ -7,7 +7,7 @@ module ActiveRecord
7
7
  #
8
8
  # returns the connection handler local to the current thread.
9
9
  #
10
- # See the documentation of <tt>ActiveSupport::PerThreadRegistry</tt>
10
+ # See the documentation of ActiveSupport::PerThreadRegistry
11
11
  # for further details.
12
12
  class RuntimeRegistry # :nodoc:
13
13
  extend ActiveSupport::PerThreadRegistry