activerecord 4.2.11 → 5.2.4.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (274) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +580 -1626
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +10 -11
  5. data/examples/performance.rb +32 -31
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record/aggregations.rb +263 -249
  8. data/lib/active_record/association_relation.rb +11 -6
  9. data/lib/active_record/associations/alias_tracker.rb +29 -35
  10. data/lib/active_record/associations/association.rb +77 -43
  11. data/lib/active_record/associations/association_scope.rb +106 -133
  12. data/lib/active_record/associations/belongs_to_association.rb +52 -41
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
  14. data/lib/active_record/associations/builder/association.rb +29 -38
  15. data/lib/active_record/associations/builder/belongs_to.rb +77 -30
  16. data/lib/active_record/associations/builder/collection_association.rb +9 -22
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +42 -35
  18. data/lib/active_record/associations/builder/has_many.rb +6 -4
  19. data/lib/active_record/associations/builder/has_one.rb +13 -6
  20. data/lib/active_record/associations/builder/singular_association.rb +15 -11
  21. data/lib/active_record/associations/collection_association.rb +139 -280
  22. data/lib/active_record/associations/collection_proxy.rb +231 -133
  23. data/lib/active_record/associations/foreign_association.rb +3 -1
  24. data/lib/active_record/associations/has_many_association.rb +34 -89
  25. data/lib/active_record/associations/has_many_through_association.rb +49 -76
  26. data/lib/active_record/associations/has_one_association.rb +38 -24
  27. data/lib/active_record/associations/has_one_through_association.rb +18 -9
  28. data/lib/active_record/associations/join_dependency/join_association.rb +40 -87
  29. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
  31. data/lib/active_record/associations/join_dependency.rb +133 -159
  32. data/lib/active_record/associations/preloader/association.rb +85 -120
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -74
  34. data/lib/active_record/associations/preloader.rb +81 -91
  35. data/lib/active_record/associations/singular_association.rb +27 -34
  36. data/lib/active_record/associations/through_association.rb +38 -18
  37. data/lib/active_record/associations.rb +1732 -1597
  38. data/lib/active_record/attribute_assignment.rb +58 -182
  39. data/lib/active_record/attribute_decorators.rb +39 -15
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +10 -8
  41. data/lib/active_record/attribute_methods/dirty.rb +94 -135
  42. data/lib/active_record/attribute_methods/primary_key.rb +86 -71
  43. data/lib/active_record/attribute_methods/query.rb +4 -2
  44. data/lib/active_record/attribute_methods/read.rb +45 -63
  45. data/lib/active_record/attribute_methods/serialization.rb +40 -20
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +58 -36
  47. data/lib/active_record/attribute_methods/write.rb +30 -45
  48. data/lib/active_record/attribute_methods.rb +166 -109
  49. data/lib/active_record/attributes.rb +201 -82
  50. data/lib/active_record/autosave_association.rb +94 -36
  51. data/lib/active_record/base.rb +57 -44
  52. data/lib/active_record/callbacks.rb +97 -57
  53. data/lib/active_record/coders/json.rb +3 -1
  54. data/lib/active_record/coders/yaml_column.rb +24 -12
  55. data/lib/active_record/collection_cache_key.rb +53 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +712 -290
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +10 -5
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +237 -90
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +71 -21
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +118 -52
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +67 -46
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +318 -217
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +81 -36
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +570 -228
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +138 -70
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +325 -202
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +542 -601
  69. data/lib/active_record/connection_adapters/column.rb +50 -41
  70. data/lib/active_record/connection_adapters/connection_specification.rb +147 -135
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +41 -180
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +35 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +45 -114
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -58
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +10 -6
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +4 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -22
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -19
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -7
  99. data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -5
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +55 -53
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +107 -47
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +144 -90
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +462 -284
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +432 -323
  117. data/lib/active_record/connection_adapters/schema_cache.rb +48 -24
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +269 -308
  126. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  127. data/lib/active_record/connection_handling.rb +40 -27
  128. data/lib/active_record/core.rb +178 -198
  129. data/lib/active_record/counter_cache.rb +79 -36
  130. data/lib/active_record/define_callbacks.rb +22 -0
  131. data/lib/active_record/dynamic_matchers.rb +87 -105
  132. data/lib/active_record/enum.rb +135 -88
  133. data/lib/active_record/errors.rb +179 -52
  134. data/lib/active_record/explain.rb +23 -11
  135. data/lib/active_record/explain_registry.rb +4 -2
  136. data/lib/active_record/explain_subscriber.rb +10 -5
  137. data/lib/active_record/fixture_set/file.rb +35 -9
  138. data/lib/active_record/fixtures.rb +188 -132
  139. data/lib/active_record/gem_version.rb +5 -3
  140. data/lib/active_record/inheritance.rb +148 -112
  141. data/lib/active_record/integration.rb +70 -28
  142. data/lib/active_record/internal_metadata.rb +45 -0
  143. data/lib/active_record/legacy_yaml_adapter.rb +21 -3
  144. data/lib/active_record/locale/en.yml +3 -2
  145. data/lib/active_record/locking/optimistic.rb +88 -96
  146. data/lib/active_record/locking/pessimistic.rb +15 -3
  147. data/lib/active_record/log_subscriber.rb +95 -33
  148. data/lib/active_record/migration/command_recorder.rb +133 -90
  149. data/lib/active_record/migration/compatibility.rb +217 -0
  150. data/lib/active_record/migration/join_table.rb +8 -6
  151. data/lib/active_record/migration.rb +581 -282
  152. data/lib/active_record/model_schema.rb +290 -111
  153. data/lib/active_record/nested_attributes.rb +264 -222
  154. data/lib/active_record/no_touching.rb +7 -1
  155. data/lib/active_record/null_relation.rb +24 -37
  156. data/lib/active_record/persistence.rb +347 -119
  157. data/lib/active_record/query_cache.rb +13 -24
  158. data/lib/active_record/querying.rb +19 -17
  159. data/lib/active_record/railtie.rb +94 -32
  160. data/lib/active_record/railties/console_sandbox.rb +2 -0
  161. data/lib/active_record/railties/controller_runtime.rb +9 -3
  162. data/lib/active_record/railties/databases.rake +149 -156
  163. data/lib/active_record/readonly_attributes.rb +5 -4
  164. data/lib/active_record/reflection.rb +414 -267
  165. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  166. data/lib/active_record/relation/batches.rb +204 -55
  167. data/lib/active_record/relation/calculations.rb +256 -248
  168. data/lib/active_record/relation/delegation.rb +67 -60
  169. data/lib/active_record/relation/finder_methods.rb +288 -239
  170. data/lib/active_record/relation/from_clause.rb +26 -0
  171. data/lib/active_record/relation/merger.rb +86 -86
  172. data/lib/active_record/relation/predicate_builder/array_handler.rb +24 -24
  173. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  174. data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
  175. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
  176. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  177. data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
  178. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  179. data/lib/active_record/relation/predicate_builder.rb +116 -119
  180. data/lib/active_record/relation/query_attribute.rb +45 -0
  181. data/lib/active_record/relation/query_methods.rb +448 -393
  182. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  183. data/lib/active_record/relation/spawn_methods.rb +11 -13
  184. data/lib/active_record/relation/where_clause.rb +186 -0
  185. data/lib/active_record/relation/where_clause_factory.rb +34 -0
  186. data/lib/active_record/relation.rb +287 -340
  187. data/lib/active_record/result.rb +54 -36
  188. data/lib/active_record/runtime_registry.rb +6 -4
  189. data/lib/active_record/sanitization.rb +155 -124
  190. data/lib/active_record/schema.rb +30 -24
  191. data/lib/active_record/schema_dumper.rb +91 -87
  192. data/lib/active_record/schema_migration.rb +19 -16
  193. data/lib/active_record/scoping/default.rb +102 -85
  194. data/lib/active_record/scoping/named.rb +81 -32
  195. data/lib/active_record/scoping.rb +45 -26
  196. data/lib/active_record/secure_token.rb +40 -0
  197. data/lib/active_record/serialization.rb +5 -5
  198. data/lib/active_record/statement_cache.rb +45 -35
  199. data/lib/active_record/store.rb +42 -36
  200. data/lib/active_record/suppressor.rb +61 -0
  201. data/lib/active_record/table_metadata.rb +82 -0
  202. data/lib/active_record/tasks/database_tasks.rb +134 -96
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +56 -100
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +83 -41
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -16
  206. data/lib/active_record/timestamp.rb +70 -38
  207. data/lib/active_record/touch_later.rb +64 -0
  208. data/lib/active_record/transactions.rb +199 -124
  209. data/lib/active_record/translation.rb +2 -0
  210. data/lib/active_record/type/adapter_specific_registry.rb +136 -0
  211. data/lib/active_record/type/date.rb +4 -45
  212. data/lib/active_record/type/date_time.rb +4 -49
  213. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  214. data/lib/active_record/type/hash_lookup_type_map.rb +5 -3
  215. data/lib/active_record/type/internal/timezone.rb +17 -0
  216. data/lib/active_record/type/json.rb +30 -0
  217. data/lib/active_record/type/serialized.rb +24 -15
  218. data/lib/active_record/type/text.rb +2 -2
  219. data/lib/active_record/type/time.rb +11 -16
  220. data/lib/active_record/type/type_map.rb +15 -17
  221. data/lib/active_record/type/unsigned_integer.rb +9 -7
  222. data/lib/active_record/type.rb +79 -23
  223. data/lib/active_record/type_caster/connection.rb +33 -0
  224. data/lib/active_record/type_caster/map.rb +23 -0
  225. data/lib/active_record/type_caster.rb +9 -0
  226. data/lib/active_record/validations/absence.rb +25 -0
  227. data/lib/active_record/validations/associated.rb +13 -4
  228. data/lib/active_record/validations/length.rb +26 -0
  229. data/lib/active_record/validations/presence.rb +14 -13
  230. data/lib/active_record/validations/uniqueness.rb +40 -41
  231. data/lib/active_record/validations.rb +38 -35
  232. data/lib/active_record/version.rb +3 -1
  233. data/lib/active_record.rb +34 -22
  234. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  235. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  236. data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -35
  237. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +8 -3
  238. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +8 -1
  239. data/lib/rails/generators/active_record/migration.rb +18 -1
  240. data/lib/rails/generators/active_record/model/model_generator.rb +18 -22
  241. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +3 -0
  242. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  243. data/lib/rails/generators/active_record.rb +7 -5
  244. metadata +72 -50
  245. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  246. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  247. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  248. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  249. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  250. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  251. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  252. data/lib/active_record/attribute.rb +0 -163
  253. data/lib/active_record/attribute_set/builder.rb +0 -106
  254. data/lib/active_record/attribute_set.rb +0 -81
  255. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  256. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  257. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  258. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  259. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  260. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  261. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  262. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  263. data/lib/active_record/type/big_integer.rb +0 -13
  264. data/lib/active_record/type/binary.rb +0 -50
  265. data/lib/active_record/type/boolean.rb +0 -31
  266. data/lib/active_record/type/decimal.rb +0 -64
  267. data/lib/active_record/type/decorator.rb +0 -14
  268. data/lib/active_record/type/float.rb +0 -19
  269. data/lib/active_record/type/integer.rb +0 -59
  270. data/lib/active_record/type/mutable.rb +0 -16
  271. data/lib/active_record/type/numeric.rb +0 -36
  272. data/lib/active_record/type/string.rb +0 -40
  273. data/lib/active_record/type/time_value.rb +0 -38
  274. data/lib/active_record/type/value.rb +0 -110
@@ -1,27 +1,28 @@
1
- require 'yaml'
2
- require 'set'
3
- require 'active_support/benchmarkable'
4
- require 'active_support/dependencies'
5
- require 'active_support/descendants_tracker'
6
- require 'active_support/time'
7
- require 'active_support/core_ext/module/attribute_accessors'
8
- require 'active_support/core_ext/class/delegating_attributes'
9
- require 'active_support/core_ext/array/extract_options'
10
- require 'active_support/core_ext/hash/deep_merge'
11
- require 'active_support/core_ext/hash/slice'
12
- require 'active_support/core_ext/hash/transform_values'
13
- require 'active_support/core_ext/string/behavior'
14
- require 'active_support/core_ext/kernel/singleton_class'
15
- require 'active_support/core_ext/module/introspection'
16
- require 'active_support/core_ext/object/duplicable'
17
- require 'active_support/core_ext/class/subclasses'
18
- require 'arel'
19
- require 'active_record/attribute_decorators'
20
- require 'active_record/errors'
21
- require 'active_record/log_subscriber'
22
- require 'active_record/explain_subscriber'
23
- require 'active_record/relation/delegation'
24
- require 'active_record/attributes'
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require "active_support/benchmarkable"
5
+ require "active_support/dependencies"
6
+ require "active_support/descendants_tracker"
7
+ require "active_support/time"
8
+ require "active_support/core_ext/module/attribute_accessors"
9
+ require "active_support/core_ext/array/extract_options"
10
+ require "active_support/core_ext/hash/deep_merge"
11
+ require "active_support/core_ext/hash/slice"
12
+ require "active_support/core_ext/hash/transform_values"
13
+ require "active_support/core_ext/string/behavior"
14
+ require "active_support/core_ext/kernel/singleton_class"
15
+ require "active_support/core_ext/module/introspection"
16
+ require "active_support/core_ext/object/duplicable"
17
+ require "active_support/core_ext/class/subclasses"
18
+ require "active_record/attribute_decorators"
19
+ require "active_record/define_callbacks"
20
+ require "active_record/errors"
21
+ require "active_record/log_subscriber"
22
+ require "active_record/explain_subscriber"
23
+ require "active_record/relation/delegation"
24
+ require "active_record/attributes"
25
+ require "active_record/type_caster"
25
26
 
26
27
  module ActiveRecord #:nodoc:
27
28
  # = Active Record
@@ -133,14 +134,11 @@ module ActiveRecord #:nodoc:
133
134
  # end
134
135
  # end
135
136
  #
136
- # You can alternatively use <tt>self[:attribute]=(value)</tt> and <tt>self[:attribute]</tt>
137
- # or <tt>write_attribute(:attribute, value)</tt> and <tt>read_attribute(:attribute)</tt>.
138
- #
139
137
  # == Attribute query methods
140
138
  #
141
139
  # In addition to the basic accessors, query methods are also automatically available on the Active Record object.
142
140
  # Query methods allow you to test whether an attribute value is present.
143
- # For numeric values, present is defined as non-zero.
141
+ # Additionally, when dealing with numeric values, a query method will return false if the value is zero.
144
142
  #
145
143
  # For example, an Active Record User with the <tt>name</tt> attribute has a <tt>name?</tt> method that you can call
146
144
  # to determine whether the user has a name:
@@ -171,10 +169,11 @@ module ActiveRecord #:nodoc:
171
169
  # <tt>Person.find_by_user_name(user_name)</tt>.
172
170
  #
173
171
  # It's possible to add an exclamation point (!) on the end of the dynamic finders to get them to raise an
174
- # <tt>ActiveRecord::RecordNotFound</tt> error if they do not return any records,
172
+ # ActiveRecord::RecordNotFound error if they do not return any records,
175
173
  # like <tt>Person.find_by_last_name!</tt>.
176
174
  #
177
- # It's also possible to use multiple attributes in the same find by separating them with "_and_".
175
+ # It's also possible to use multiple attributes in the same <tt>find_by_</tt> by separating them with
176
+ # "_and_".
178
177
  #
179
178
  # Person.find_by(user_name: user_name, password: password)
180
179
  # Person.find_by_user_name_and_password(user_name, password) # with dynamic finder
@@ -186,7 +185,8 @@ module ActiveRecord #:nodoc:
186
185
  # == Saving arrays, hashes, and other non-mappable objects in text columns
187
186
  #
188
187
  # Active Record can serialize any object in text columns using YAML. To do so, you must
189
- # specify this with a call to the class method +serialize+.
188
+ # specify this with a call to the class method
189
+ # {serialize}[rdoc-ref:AttributeMethods::Serialization::ClassMethods#serialize].
190
190
  # This makes it possible to store arrays, hashes, and other non-mappable objects without doing
191
191
  # any additional work.
192
192
  #
@@ -226,39 +226,47 @@ module ActiveRecord #:nodoc:
226
226
  #
227
227
  # == Connection to multiple databases in different models
228
228
  #
229
- # Connections are usually created through ActiveRecord::Base.establish_connection and retrieved
229
+ # Connections are usually created through
230
+ # {ActiveRecord::Base.establish_connection}[rdoc-ref:ConnectionHandling#establish_connection] and retrieved
230
231
  # by ActiveRecord::Base.connection. All classes inheriting from ActiveRecord::Base will use this
231
232
  # connection. But you can also set a class-specific connection. For example, if Course is an
232
233
  # ActiveRecord::Base, but resides in a different database, you can just say <tt>Course.establish_connection</tt>
233
234
  # and Course and all of its subclasses will use this connection instead.
234
235
  #
235
236
  # This feature is implemented by keeping a connection pool in ActiveRecord::Base that is
236
- # a Hash indexed by the class. If a connection is requested, the retrieve_connection method
237
+ # a hash indexed by the class. If a connection is requested, the
238
+ # {ActiveRecord::Base.retrieve_connection}[rdoc-ref:ConnectionHandling#retrieve_connection] method
237
239
  # will go up the class-hierarchy until a connection is found in the connection pool.
238
240
  #
239
241
  # == Exceptions
240
242
  #
241
243
  # * ActiveRecordError - Generic error class and superclass of all other errors raised by Active Record.
242
- # * AdapterNotSpecified - The configuration hash used in <tt>establish_connection</tt> didn't include an
243
- # <tt>:adapter</tt> key.
244
- # * AdapterNotFound - The <tt>:adapter</tt> key used in <tt>establish_connection</tt> specified a
245
- # non-existent adapter
244
+ # * AdapterNotSpecified - The configuration hash used in
245
+ # {ActiveRecord::Base.establish_connection}[rdoc-ref:ConnectionHandling#establish_connection]
246
+ # didn't include an <tt>:adapter</tt> key.
247
+ # * AdapterNotFound - The <tt>:adapter</tt> key used in
248
+ # {ActiveRecord::Base.establish_connection}[rdoc-ref:ConnectionHandling#establish_connection]
249
+ # specified a non-existent adapter
246
250
  # (or a bad spelling of an existing one).
247
251
  # * AssociationTypeMismatch - The object assigned to the association wasn't of the type
248
252
  # specified in the association definition.
249
253
  # * AttributeAssignmentError - An error occurred while doing a mass assignment through the
250
- # <tt>attributes=</tt> method.
254
+ # {ActiveRecord::Base#attributes=}[rdoc-ref:AttributeAssignment#attributes=] method.
251
255
  # You can inspect the +attribute+ property of the exception object to determine which attribute
252
256
  # triggered the error.
253
- # * ConnectionNotEstablished - No connection has been established. Use <tt>establish_connection</tt>
254
- # before querying.
257
+ # * ConnectionNotEstablished - No connection has been established.
258
+ # Use {ActiveRecord::Base.establish_connection}[rdoc-ref:ConnectionHandling#establish_connection] before querying.
255
259
  # * MultiparameterAssignmentErrors - Collection of errors that occurred during a mass assignment using the
256
- # <tt>attributes=</tt> method. The +errors+ property of this exception contains an array of
260
+ # {ActiveRecord::Base#attributes=}[rdoc-ref:AttributeAssignment#attributes=] method.
261
+ # The +errors+ property of this exception contains an array of
257
262
  # AttributeAssignmentError
258
263
  # objects that should be inspected to determine which attributes triggered the errors.
259
- # * RecordInvalid - raised by save! and create! when the record is invalid.
260
- # * RecordNotFound - No record responded to the +find+ method. Either the row with the given ID doesn't exist
261
- # or the row didn't meet the additional restrictions. Some +find+ calls do not raise this exception to signal
264
+ # * RecordInvalid - raised by {ActiveRecord::Base#save!}[rdoc-ref:Persistence#save!] and
265
+ # {ActiveRecord::Base.create!}[rdoc-ref:Persistence::ClassMethods#create!]
266
+ # when the record is invalid.
267
+ # * RecordNotFound - No record responded to the {ActiveRecord::Base.find}[rdoc-ref:FinderMethods#find] method.
268
+ # Either the row with the given ID doesn't exist or the row didn't meet the additional restrictions.
269
+ # Some {ActiveRecord::Base.find}[rdoc-ref:FinderMethods#find] calls do not raise this exception to signal
262
270
  # nothing was found, please check its documentation for further details.
263
271
  # * SerializationTypeMismatch - The serialized object wasn't of the class specified as the second parameter.
264
272
  # * StatementInvalid - The database server rejected the SQL statement. The precise error is added in the message.
@@ -280,6 +288,7 @@ module ActiveRecord #:nodoc:
280
288
  extend Explain
281
289
  extend Enum
282
290
  extend Delegation::DelegateCache
291
+ extend CollectionCacheKey
283
292
 
284
293
  include Core
285
294
  include Persistence
@@ -297,6 +306,7 @@ module ActiveRecord #:nodoc:
297
306
  include AttributeDecorators
298
307
  include Locking::Optimistic
299
308
  include Locking::Pessimistic
309
+ include DefineCallbacks
300
310
  include AttributeMethods
301
311
  include Callbacks
302
312
  include Timestamp
@@ -306,10 +316,13 @@ module ActiveRecord #:nodoc:
306
316
  include NestedAttributes
307
317
  include Aggregations
308
318
  include Transactions
319
+ include TouchLater
309
320
  include NoTouching
310
321
  include Reflection
311
322
  include Serialization
312
323
  include Store
324
+ include SecureToken
325
+ include Suppressor
313
326
  end
314
327
 
315
328
  ActiveSupport.run_load_hooks(:active_record, Base)
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
- # = Active Record Callbacks
4
+ # = Active Record \Callbacks
3
5
  #
4
- # Callbacks are hooks into the life cycle of an Active Record object that allow you to trigger logic
6
+ # \Callbacks are hooks into the life cycle of an Active Record object that allow you to trigger logic
5
7
  # before or after an alteration of the object state. This can be used to make sure that associated and
6
- # dependent objects are deleted when +destroy+ is called (by overwriting +before_destroy+) or to massage attributes
7
- # before they're validated (by overwriting +before_validation+). As an example of the callbacks initiated, consider
8
- # the <tt>Base#save</tt> call for a new record:
8
+ # dependent objects are deleted when {ActiveRecord::Base#destroy}[rdoc-ref:Persistence#destroy] is called (by overwriting +before_destroy+) or
9
+ # to massage attributes before they're validated (by overwriting +before_validation+).
10
+ # As an example of the callbacks initiated, consider the {ActiveRecord::Base#save}[rdoc-ref:Persistence#save] call for a new record:
9
11
  #
10
12
  # * (-) <tt>save</tt>
11
13
  # * (-) <tt>valid</tt>
@@ -20,7 +22,7 @@ module ActiveRecord
20
22
  # * (7) <tt>after_commit</tt>
21
23
  #
22
24
  # Also, an <tt>after_rollback</tt> callback can be configured to be triggered whenever a rollback is issued.
23
- # Check out <tt>ActiveRecord::Transactions</tt> for more details about <tt>after_commit</tt> and
25
+ # Check out ActiveRecord::Transactions for more details about <tt>after_commit</tt> and
24
26
  # <tt>after_rollback</tt>.
25
27
  #
26
28
  # Additionally, an <tt>after_touch</tt> callback is triggered whenever an
@@ -31,7 +33,7 @@ module ActiveRecord
31
33
  # are instantiated as well.
32
34
  #
33
35
  # There are nineteen callbacks in total, which give you immense power to react and prepare for each state in the
34
- # Active Record life cycle. The sequence for calling <tt>Base#save</tt> for an existing record is similar,
36
+ # Active Record life cycle. The sequence for calling {ActiveRecord::Base#save}[rdoc-ref:Persistence#save] for an existing record is similar,
35
37
  # except that each <tt>_create</tt> callback is replaced by the corresponding <tt>_update</tt> callback.
36
38
  #
37
39
  # Examples:
@@ -53,9 +55,9 @@ module ActiveRecord
53
55
  # end
54
56
  #
55
57
  # class Firm < ActiveRecord::Base
56
- # # Destroys the associated clients and people when the firm is destroyed
57
- # before_destroy { |record| Person.destroy_all "firm_id = #{record.id}" }
58
- # before_destroy { |record| Client.destroy_all "client_of = #{record.id}" }
58
+ # # Disables access to the system, for associated clients and people when the firm is destroyed
59
+ # before_destroy { |record| Person.where(firm_id: record.id).update_all(access: 'disabled') }
60
+ # before_destroy { |record| Client.where(client_of: record.id).update_all(access: 'disabled') }
59
61
  # end
60
62
  #
61
63
  # == Inheritable callback queues
@@ -96,9 +98,9 @@ module ActiveRecord
96
98
  # == Types of callbacks
97
99
  #
98
100
  # There are four types of callbacks accepted by the callback macros: Method references (symbol), callback objects,
99
- # inline methods (using a proc), and inline eval methods (using a string). Method references and callback objects
101
+ # inline methods (using a proc). Method references and callback objects
100
102
  # are the recommended approaches, inline methods using a proc are sometimes appropriate (such as for
101
- # creating mix-ins), and inline eval methods are deprecated.
103
+ # creating mix-ins).
102
104
  #
103
105
  # The method reference callbacks work by specifying a protected or private method available in the object, like this:
104
106
  #
@@ -175,43 +177,30 @@ module ActiveRecord
175
177
  # end
176
178
  # end
177
179
  #
178
- # The callback macros usually accept a symbol for the method they're supposed to run, but you can also
179
- # pass a "method string", which will then be evaluated within the binding of the callback. Example:
180
- #
181
- # class Topic < ActiveRecord::Base
182
- # before_destroy 'self.class.delete_all "parent_id = #{id}"'
183
- # end
184
- #
185
- # Notice that single quotes (') are used so the <tt>#{id}</tt> part isn't evaluated until the callback
186
- # is triggered. Also note that these inline callbacks can be stacked just like the regular ones:
187
- #
188
- # class Topic < ActiveRecord::Base
189
- # before_destroy 'self.class.delete_all "parent_id = #{id}"',
190
- # 'puts "Evaluated after parents are destroyed"'
191
- # end
192
- #
193
180
  # == <tt>before_validation*</tt> returning statements
194
181
  #
195
- # If the returning value of a +before_validation+ callback can be evaluated to +false+, the process will be
196
- # aborted and <tt>Base#save</tt> will return +false+. If Base#save! is called it will raise a
197
- # ActiveRecord::RecordInvalid exception. Nothing will be appended to the errors object.
182
+ # If the +before_validation+ callback throws +:abort+, the process will be
183
+ # aborted and {ActiveRecord::Base#save}[rdoc-ref:Persistence#save] will return +false+.
184
+ # If {ActiveRecord::Base#save!}[rdoc-ref:Persistence#save!] is called it will raise an ActiveRecord::RecordInvalid exception.
185
+ # Nothing will be appended to the errors object.
198
186
  #
199
187
  # == Canceling callbacks
200
188
  #
201
- # If a <tt>before_*</tt> callback returns +false+, all the later callbacks and the associated action are
202
- # cancelled.
189
+ # If a <tt>before_*</tt> callback throws +:abort+, all the later callbacks and
190
+ # the associated action are cancelled.
203
191
  # Callbacks are generally run in the order they are defined, with the exception of callbacks defined as
204
192
  # methods on the model, which are called last.
205
193
  #
206
194
  # == Ordering callbacks
207
195
  #
208
196
  # Sometimes the code needs that the callbacks execute in a specific order. For example, a +before_destroy+
209
- # callback (+log_children+ in this case) should be executed before the children get destroyed by the +dependent: destroy+ option.
197
+ # callback (+log_children+ in this case) should be executed before the children get destroyed by the
198
+ # <tt>dependent: :destroy</tt> option.
210
199
  #
211
200
  # Let's look at the code below:
212
201
  #
213
202
  # class Topic < ActiveRecord::Base
214
- # has_many :children, dependent: destroy
203
+ # has_many :children, dependent: :destroy
215
204
  #
216
205
  # before_destroy :log_children
217
206
  #
@@ -222,10 +211,11 @@ module ActiveRecord
222
211
  # end
223
212
  #
224
213
  # In this case, the problem is that when the +before_destroy+ callback is executed, the children are not available
225
- # because the +destroy+ callback gets executed first. You can use the +prepend+ option on the +before_destroy+ callback to avoid this.
214
+ # because the {ActiveRecord::Base#destroy}[rdoc-ref:Persistence#destroy] callback gets executed first.
215
+ # You can use the +prepend+ option on the +before_destroy+ callback to avoid this.
226
216
  #
227
217
  # class Topic < ActiveRecord::Base
228
- # has_many :children, dependent: destroy
218
+ # has_many :children, dependent: :destroy
229
219
  #
230
220
  # before_destroy :log_children, prepend: true
231
221
  #
@@ -235,23 +225,72 @@ module ActiveRecord
235
225
  # end
236
226
  # end
237
227
  #
238
- # This way, the +before_destroy+ gets executed before the <tt>dependent: destroy</tt> is called, and the data is still available.
228
+ # This way, the +before_destroy+ gets executed before the <tt>dependent: :destroy</tt> is called, and the data is still available.
229
+ #
230
+ # Also, there are cases when you want several callbacks of the same type to
231
+ # be executed in order.
232
+ #
233
+ # For example:
234
+ #
235
+ # class Topic < ActiveRecord::Base
236
+ # has_many :children
237
+ #
238
+ # after_save :log_children
239
+ # after_save :do_something_else
240
+ #
241
+ # private
242
+ #
243
+ # def log_children
244
+ # # Child processing
245
+ # end
246
+ #
247
+ # def do_something_else
248
+ # # Something else
249
+ # end
250
+ # end
251
+ #
252
+ # In this case the +log_children+ gets executed before +do_something_else+.
253
+ # The same applies to all non-transactional callbacks.
254
+ #
255
+ # In case there are multiple transactional callbacks as seen below, the order
256
+ # is reversed.
257
+ #
258
+ # For example:
239
259
  #
240
- # == Transactions
260
+ # class Topic < ActiveRecord::Base
261
+ # has_many :children
262
+ #
263
+ # after_commit :log_children
264
+ # after_commit :do_something_else
241
265
  #
242
- # The entire callback chain of a +save+, <tt>save!</tt>, or +destroy+ call runs
243
- # within a transaction. That includes <tt>after_*</tt> hooks. If everything
244
- # goes fine a COMMIT is executed once the chain has been completed.
266
+ # private
267
+ #
268
+ # def log_children
269
+ # # Child processing
270
+ # end
271
+ #
272
+ # def do_something_else
273
+ # # Something else
274
+ # end
275
+ # end
276
+ #
277
+ # In this case the +do_something_else+ gets executed before +log_children+.
278
+ #
279
+ # == \Transactions
280
+ #
281
+ # The entire callback chain of a {#save}[rdoc-ref:Persistence#save], {#save!}[rdoc-ref:Persistence#save!],
282
+ # or {#destroy}[rdoc-ref:Persistence#destroy] call runs within a transaction. That includes <tt>after_*</tt> hooks.
283
+ # If everything goes fine a COMMIT is executed once the chain has been completed.
245
284
  #
246
285
  # If a <tt>before_*</tt> callback cancels the action a ROLLBACK is issued. You
247
286
  # can also trigger a ROLLBACK raising an exception in any of the callbacks,
248
287
  # including <tt>after_*</tt> hooks. Note, however, that in that case the client
249
- # needs to be aware of it because an ordinary +save+ will raise such exception
288
+ # needs to be aware of it because an ordinary {#save}[rdoc-ref:Persistence#save] will raise such exception
250
289
  # instead of quietly returning +false+.
251
290
  #
252
291
  # == Debugging callbacks
253
292
  #
254
- # The callback chain is accessible via the <tt>_*_callbacks</tt> method on an object. ActiveModel Callbacks support
293
+ # The callback chain is accessible via the <tt>_*_callbacks</tt> method on an object. Active Model \Callbacks support
255
294
  # <tt>:before</tt>, <tt>:after</tt> and <tt>:around</tt> as values for the <tt>kind</tt> property. The <tt>kind</tt> property
256
295
  # defines what part of the chain the callback runs in.
257
296
  #
@@ -277,36 +316,37 @@ module ActiveRecord
277
316
  :before_destroy, :around_destroy, :after_destroy, :after_commit, :after_rollback
278
317
  ]
279
318
 
280
- module ClassMethods
281
- include ActiveModel::Callbacks
282
- end
283
-
284
- included do
285
- include ActiveModel::Validations::Callbacks
286
-
287
- define_model_callbacks :initialize, :find, :touch, :only => :after
288
- define_model_callbacks :save, :create, :update, :destroy
289
- end
290
-
291
319
  def destroy #:nodoc:
320
+ @_destroy_callback_already_called ||= false
321
+ return if @_destroy_callback_already_called
322
+ @_destroy_callback_already_called = true
292
323
  _run_destroy_callbacks { super }
324
+ rescue RecordNotDestroyed => e
325
+ @_association_destroy_exception = e
326
+ false
327
+ ensure
328
+ @_destroy_callback_already_called = false
293
329
  end
294
330
 
295
331
  def touch(*) #:nodoc:
296
332
  _run_touch_callbacks { super }
297
333
  end
298
334
 
335
+ def increment!(attribute, by = 1, touch: nil) # :nodoc:
336
+ touch ? _run_touch_callbacks { super } : super
337
+ end
338
+
299
339
  private
300
340
 
301
- def create_or_update #:nodoc:
341
+ def create_or_update(*)
302
342
  _run_save_callbacks { super }
303
343
  end
304
344
 
305
- def _create_record #:nodoc:
345
+ def _create_record
306
346
  _run_create_callbacks { super }
307
347
  end
308
348
 
309
- def _update_record(*) #:nodoc:
349
+ def _update_record(*)
310
350
  _run_update_callbacks { super }
311
351
  end
312
352
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Coders # :nodoc:
3
5
  class JSON # :nodoc:
@@ -6,7 +8,7 @@ module ActiveRecord
6
8
  end
7
9
 
8
10
  def self.load(json)
9
- ActiveSupport::JSON.decode(json) unless json.nil?
11
+ ActiveSupport::JSON.decode(json) unless json.blank?
10
12
  end
11
13
  end
12
14
  end
@@ -1,38 +1,50 @@
1
- require 'yaml'
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
2
4
 
3
5
  module ActiveRecord
4
6
  module Coders # :nodoc:
5
7
  class YAMLColumn # :nodoc:
6
-
7
8
  attr_accessor :object_class
8
9
 
9
- def initialize(object_class = Object)
10
+ def initialize(attr_name, object_class = Object)
11
+ @attr_name = attr_name
10
12
  @object_class = object_class
13
+ check_arity_of_constructor
11
14
  end
12
15
 
13
16
  def dump(obj)
14
17
  return if obj.nil?
15
18
 
16
- unless obj.is_a?(object_class)
17
- raise SerializationTypeMismatch,
18
- "Attribute was supposed to be a #{object_class}, but was a #{obj.class}. -- #{obj.inspect}"
19
- end
19
+ assert_valid_value(obj, action: "dump")
20
20
  YAML.dump obj
21
21
  end
22
22
 
23
23
  def load(yaml)
24
24
  return object_class.new if object_class != Object && yaml.nil?
25
- return yaml unless yaml.is_a?(String) && yaml =~ /^---/
25
+ return yaml unless yaml.is_a?(String) && /^---/.match?(yaml)
26
26
  obj = YAML.load(yaml)
27
27
 
28
- unless obj.is_a?(object_class) || obj.nil?
29
- raise SerializationTypeMismatch,
30
- "Attribute was supposed to be a #{object_class}, but was a #{obj.class}"
31
- end
28
+ assert_valid_value(obj, action: "load")
32
29
  obj ||= object_class.new if object_class != Object
33
30
 
34
31
  obj
35
32
  end
33
+
34
+ def assert_valid_value(obj, action:)
35
+ unless obj.nil? || obj.is_a?(object_class)
36
+ raise SerializationTypeMismatch,
37
+ "can't #{action} `#{@attr_name}`: was supposed to be a #{object_class}, but was a #{obj.class}. -- #{obj.inspect}"
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def check_arity_of_constructor
44
+ load(nil)
45
+ rescue ArgumentError
46
+ raise ArgumentError, "Cannot serialize #{object_class}. Classes passed to `serialize` must have a 0 argument constructor."
47
+ end
36
48
  end
37
49
  end
38
50
  end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module CollectionCacheKey
5
+ def collection_cache_key(collection = all, timestamp_column = :updated_at) # :nodoc:
6
+ query_signature = ActiveSupport::Digest.hexdigest(collection.to_sql)
7
+ key = "#{collection.model_name.cache_key}/query-#{query_signature}"
8
+
9
+ if collection.loaded? || collection.distinct_value
10
+ size = collection.records.size
11
+ if size > 0
12
+ timestamp = collection.max_by(&timestamp_column)._read_attribute(timestamp_column)
13
+ end
14
+ else
15
+ if collection.eager_loading?
16
+ collection = collection.send(:apply_join_dependency)
17
+ end
18
+ column_type = type_for_attribute(timestamp_column)
19
+ column = connection.column_name_from_arel_node(collection.arel_attribute(timestamp_column))
20
+ select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
21
+
22
+ if collection.has_limit_or_offset?
23
+ query = collection.select("#{column} AS collection_cache_key_timestamp")
24
+ subquery_alias = "subquery_for_cache_key"
25
+ subquery_column = "#{subquery_alias}.collection_cache_key_timestamp"
26
+ subquery = query.arel.as(subquery_alias)
27
+ arel = Arel::SelectManager.new(subquery).project(select_values % subquery_column)
28
+ else
29
+ query = collection.unscope(:order)
30
+ query.select_values = [select_values % column]
31
+ arel = query.arel
32
+ end
33
+
34
+ result = connection.select_one(arel, nil)
35
+
36
+ if result.blank?
37
+ size = 0
38
+ timestamp = nil
39
+ else
40
+ size = result["size"]
41
+ timestamp = column_type.deserialize(result["timestamp"])
42
+ end
43
+
44
+ end
45
+
46
+ if timestamp
47
+ "#{key}-#{size}-#{timestamp.utc.to_s(cache_timestamp_format)}"
48
+ else
49
+ "#{key}-#{size}"
50
+ end
51
+ end
52
+ end
53
+ end