activerecord 5.1.7 → 5.2.0.beta1

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 (259) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +221 -900
  3. data/README.rdoc +3 -3
  4. data/examples/performance.rb +2 -0
  5. data/examples/simple.rb +2 -0
  6. data/lib/active_record.rb +10 -3
  7. data/lib/active_record/aggregations.rb +2 -0
  8. data/lib/active_record/association_relation.rb +2 -0
  9. data/lib/active_record/associations.rb +13 -42
  10. data/lib/active_record/associations/alias_tracker.rb +17 -17
  11. data/lib/active_record/associations/association.rb +11 -22
  12. data/lib/active_record/associations/association_scope.rb +32 -44
  13. data/lib/active_record/associations/belongs_to_association.rb +6 -4
  14. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -1
  15. data/lib/active_record/associations/builder/association.rb +2 -5
  16. data/lib/active_record/associations/builder/belongs_to.rb +7 -12
  17. data/lib/active_record/associations/builder/collection_association.rb +1 -1
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
  19. data/lib/active_record/associations/builder/has_many.rb +2 -0
  20. data/lib/active_record/associations/builder/has_one.rb +2 -0
  21. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  22. data/lib/active_record/associations/collection_association.rb +41 -33
  23. data/lib/active_record/associations/collection_proxy.rb +11 -14
  24. data/lib/active_record/associations/foreign_association.rb +2 -0
  25. data/lib/active_record/associations/has_many_association.rb +4 -2
  26. data/lib/active_record/associations/has_many_through_association.rb +4 -2
  27. data/lib/active_record/associations/has_one_association.rb +3 -1
  28. data/lib/active_record/associations/has_one_through_association.rb +3 -1
  29. data/lib/active_record/associations/join_dependency.rb +22 -40
  30. data/lib/active_record/associations/join_dependency/join_association.rb +17 -56
  31. data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
  32. data/lib/active_record/associations/join_dependency/join_part.rb +2 -9
  33. data/lib/active_record/associations/preloader.rb +17 -37
  34. data/lib/active_record/associations/preloader/association.rb +42 -58
  35. data/lib/active_record/associations/preloader/through_association.rb +71 -79
  36. data/lib/active_record/associations/singular_association.rb +14 -10
  37. data/lib/active_record/associations/through_association.rb +3 -1
  38. data/lib/active_record/attribute_assignment.rb +2 -0
  39. data/lib/active_record/attribute_decorators.rb +3 -2
  40. data/lib/active_record/attribute_methods.rb +47 -7
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
  42. data/lib/active_record/attribute_methods/dirty.rb +25 -214
  43. data/lib/active_record/attribute_methods/primary_key.rb +7 -6
  44. data/lib/active_record/attribute_methods/query.rb +2 -0
  45. data/lib/active_record/attribute_methods/read.rb +8 -2
  46. data/lib/active_record/attribute_methods/serialization.rb +23 -0
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
  48. data/lib/active_record/attribute_methods/write.rb +21 -9
  49. data/lib/active_record/attributes.rb +7 -6
  50. data/lib/active_record/autosave_association.rb +5 -11
  51. data/lib/active_record/base.rb +2 -0
  52. data/lib/active_record/callbacks.rb +6 -8
  53. data/lib/active_record/coders/json.rb +2 -0
  54. data/lib/active_record/coders/yaml_column.rb +2 -0
  55. data/lib/active_record/collection_cache_key.rb +10 -5
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +110 -35
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -0
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +120 -28
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +7 -2
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +14 -33
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +13 -5
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +40 -2
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +103 -63
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +45 -9
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +62 -90
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +75 -138
  69. data/lib/active_record/connection_adapters/column.rb +3 -1
  70. data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +2 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +3 -1
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -6
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +91 -1
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -1
  86. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -11
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
  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 -1
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +3 -5
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  107. data/lib/active_record/connection_adapters/postgresql/quoting.rb +10 -0
  108. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  109. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +2 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +11 -7
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +79 -65
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -0
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +47 -82
  116. data/lib/active_record/connection_adapters/schema_cache.rb +2 -0
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
  118. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
  119. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +19 -2
  120. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
  121. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
  122. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
  123. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +71 -1
  124. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -89
  125. data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
  126. data/lib/active_record/connection_handling.rb +4 -2
  127. data/lib/active_record/core.rb +27 -57
  128. data/lib/active_record/counter_cache.rb +15 -12
  129. data/lib/active_record/define_callbacks.rb +5 -3
  130. data/lib/active_record/dynamic_matchers.rb +9 -9
  131. data/lib/active_record/enum.rb +15 -13
  132. data/lib/active_record/errors.rb +54 -21
  133. data/lib/active_record/explain.rb +3 -1
  134. data/lib/active_record/explain_registry.rb +2 -0
  135. data/lib/active_record/explain_subscriber.rb +2 -0
  136. data/lib/active_record/fixture_set/file.rb +2 -0
  137. data/lib/active_record/fixtures.rb +40 -24
  138. data/lib/active_record/gem_version.rb +5 -3
  139. data/lib/active_record/inheritance.rb +6 -5
  140. data/lib/active_record/integration.rb +58 -19
  141. data/lib/active_record/internal_metadata.rb +2 -0
  142. data/lib/active_record/legacy_yaml_adapter.rb +3 -1
  143. data/lib/active_record/locking/optimistic.rb +31 -20
  144. data/lib/active_record/locking/pessimistic.rb +10 -7
  145. data/lib/active_record/log_subscriber.rb +2 -0
  146. data/lib/active_record/migration.rb +47 -21
  147. data/lib/active_record/migration/command_recorder.rb +11 -9
  148. data/lib/active_record/migration/compatibility.rb +20 -2
  149. data/lib/active_record/migration/join_table.rb +2 -0
  150. data/lib/active_record/model_schema.rb +29 -38
  151. data/lib/active_record/nested_attributes.rb +18 -6
  152. data/lib/active_record/no_touching.rb +3 -1
  153. data/lib/active_record/null_relation.rb +2 -0
  154. data/lib/active_record/persistence.rb +184 -40
  155. data/lib/active_record/query_cache.rb +17 -12
  156. data/lib/active_record/querying.rb +3 -1
  157. data/lib/active_record/railtie.rb +54 -1
  158. data/lib/active_record/railties/console_sandbox.rb +2 -0
  159. data/lib/active_record/railties/controller_runtime.rb +2 -0
  160. data/lib/active_record/railties/databases.rake +41 -28
  161. data/lib/active_record/readonly_attributes.rb +3 -2
  162. data/lib/active_record/reflection.rb +100 -182
  163. data/lib/active_record/relation.rb +61 -193
  164. data/lib/active_record/relation/batches.rb +20 -5
  165. data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
  166. data/lib/active_record/relation/calculations.rb +40 -23
  167. data/lib/active_record/relation/delegation.rb +10 -27
  168. data/lib/active_record/relation/finder_methods.rb +53 -49
  169. data/lib/active_record/relation/from_clause.rb +2 -8
  170. data/lib/active_record/relation/merger.rb +22 -19
  171. data/lib/active_record/relation/predicate_builder.rb +42 -79
  172. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
  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 +2 -2
  175. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
  176. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +54 -0
  177. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -6
  178. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  179. data/lib/active_record/relation/query_attribute.rb +9 -2
  180. data/lib/active_record/relation/query_methods.rb +80 -69
  181. data/lib/active_record/relation/record_fetch_warning.rb +2 -0
  182. data/lib/active_record/relation/spawn_methods.rb +2 -0
  183. data/lib/active_record/relation/where_clause.rb +50 -67
  184. data/lib/active_record/relation/where_clause_factory.rb +4 -46
  185. data/lib/active_record/result.rb +2 -0
  186. data/lib/active_record/runtime_registry.rb +2 -0
  187. data/lib/active_record/sanitization.rb +15 -9
  188. data/lib/active_record/schema.rb +3 -1
  189. data/lib/active_record/schema_dumper.rb +24 -23
  190. data/lib/active_record/schema_migration.rb +2 -0
  191. data/lib/active_record/scoping.rb +9 -8
  192. data/lib/active_record/scoping/default.rb +6 -7
  193. data/lib/active_record/scoping/named.rb +15 -7
  194. data/lib/active_record/secure_token.rb +2 -0
  195. data/lib/active_record/serialization.rb +2 -0
  196. data/lib/active_record/statement_cache.rb +22 -12
  197. data/lib/active_record/store.rb +2 -0
  198. data/lib/active_record/suppressor.rb +2 -0
  199. data/lib/active_record/table_metadata.rb +3 -1
  200. data/lib/active_record/tasks/database_tasks.rb +23 -12
  201. data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
  202. data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
  203. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
  204. data/lib/active_record/timestamp.rb +5 -12
  205. data/lib/active_record/touch_later.rb +2 -0
  206. data/lib/active_record/transactions.rb +9 -7
  207. data/lib/active_record/translation.rb +2 -0
  208. data/lib/active_record/type.rb +4 -1
  209. data/lib/active_record/type/adapter_specific_registry.rb +2 -0
  210. data/lib/active_record/type/date.rb +2 -0
  211. data/lib/active_record/type/date_time.rb +2 -0
  212. data/lib/active_record/type/decimal_without_scale.rb +2 -0
  213. data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
  214. data/lib/active_record/type/internal/timezone.rb +2 -0
  215. data/lib/active_record/type/json.rb +30 -0
  216. data/lib/active_record/type/serialized.rb +2 -4
  217. data/lib/active_record/type/text.rb +2 -0
  218. data/lib/active_record/type/time.rb +2 -0
  219. data/lib/active_record/type/type_map.rb +2 -0
  220. data/lib/active_record/type/unsigned_integer.rb +2 -0
  221. data/lib/active_record/type_caster.rb +2 -0
  222. data/lib/active_record/type_caster/connection.rb +2 -0
  223. data/lib/active_record/type_caster/map.rb +2 -0
  224. data/lib/active_record/validations.rb +2 -0
  225. data/lib/active_record/validations/absence.rb +2 -0
  226. data/lib/active_record/validations/associated.rb +2 -0
  227. data/lib/active_record/validations/length.rb +2 -0
  228. data/lib/active_record/validations/presence.rb +2 -0
  229. data/lib/active_record/validations/uniqueness.rb +36 -6
  230. data/lib/active_record/version.rb +2 -0
  231. data/lib/rails/generators/active_record.rb +3 -1
  232. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  233. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  234. data/lib/rails/generators/active_record/migration.rb +2 -0
  235. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
  236. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
  237. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
  238. data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
  239. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
  240. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  241. metadata +25 -38
  242. data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
  243. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  244. data/lib/active_record/associations/preloader/has_many.rb +0 -15
  245. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  246. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  247. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  248. data/lib/active_record/associations/preloader/singular_association.rb +0 -18
  249. data/lib/active_record/attribute.rb +0 -240
  250. data/lib/active_record/attribute/user_provided_default.rb +0 -30
  251. data/lib/active_record/attribute_mutation_tracker.rb +0 -122
  252. data/lib/active_record/attribute_set.rb +0 -113
  253. data/lib/active_record/attribute_set/builder.rb +0 -126
  254. data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
  255. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
  256. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  257. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  258. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
  259. data/lib/active_record/type/internal/abstract_json.rb +0 -37
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "set"
2
4
 
3
5
  module ActiveRecord
@@ -8,23 +10,22 @@ module ActiveRecord
8
10
  # Returns this record's primary key value wrapped in an array if one is
9
11
  # available.
10
12
  def to_key
11
- sync_with_transaction_state
12
13
  key = id
13
14
  [key] if key
14
15
  end
15
16
 
16
17
  # Returns the primary key value.
17
18
  def id
18
- if pk = self.class.primary_key
19
- sync_with_transaction_state
20
- _read_attribute(pk)
21
- end
19
+ sync_with_transaction_state
20
+ primary_key = self.class.primary_key
21
+ _read_attribute(primary_key) if primary_key
22
22
  end
23
23
 
24
24
  # Sets the primary key value.
25
25
  def id=(value)
26
26
  sync_with_transaction_state
27
- write_attribute(self.class.primary_key, value) if self.class.primary_key
27
+ primary_key = self.class.primary_key
28
+ _write_attribute(primary_key, value) if primary_key
28
29
  end
29
30
 
30
31
  # Queries the primary key value.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module AttributeMethods
3
5
  module Query
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module AttributeMethods
3
5
  module Read
4
6
  extend ActiveSupport::Concern
5
7
 
6
- module ClassMethods
8
+ module ClassMethods # :nodoc:
7
9
  private
8
10
 
9
11
  # We want to generate the methods via module_eval rather than
@@ -29,9 +31,11 @@ module ActiveRecord
29
31
  temp_method = "__temp__#{safe_name}"
30
32
 
31
33
  ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
34
+ sync_with_transaction_state = "sync_with_transaction_state" if name == primary_key
32
35
 
33
36
  generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
34
37
  def #{temp_method}
38
+ #{sync_with_transaction_state}
35
39
  name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
36
40
  _read_attribute(name) { |n| missing_attribute(n, caller) }
37
41
  end
@@ -54,7 +58,9 @@ module ActiveRecord
54
58
  attr_name.to_s
55
59
  end
56
60
 
57
- name = self.class.primary_key if name == "id".freeze && self.class.primary_key
61
+ primary_key = self.class.primary_key
62
+ name = primary_key if name == "id".freeze && primary_key
63
+ sync_with_transaction_state if name == primary_key
58
64
  _read_attribute(name, &block)
59
65
  end
60
66
 
@@ -1,8 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module AttributeMethods
3
5
  module Serialization
4
6
  extend ActiveSupport::Concern
5
7
 
8
+ class ColumnNotSerializableError < StandardError
9
+ def initialize(name, type)
10
+ super <<-EOS.strip_heredoc
11
+ Column `#{name}` of type #{type.class} does not support `serialize` feature.
12
+ Usually it means that you are trying to use `serialize`
13
+ on a column that already implements serialization natively.
14
+ EOS
15
+ end
16
+ end
17
+
6
18
  module ClassMethods
7
19
  # If you have an attribute that needs to be saved to the database as an
8
20
  # object, and retrieved as the same object, then specify the name of that
@@ -58,9 +70,20 @@ module ActiveRecord
58
70
  end
59
71
 
60
72
  decorate_attribute_type(attr_name, :serialize) do |type|
73
+ if type_incompatible_with_serialize?(type, class_name_or_coder)
74
+ raise ColumnNotSerializableError.new(attr_name, type)
75
+ end
76
+
61
77
  Type::Serialized.new(type, coder)
62
78
  end
63
79
  end
80
+
81
+ private
82
+
83
+ def type_incompatible_with_serialize?(type, class_name)
84
+ type.is_a?(ActiveRecord::Type::Json) && class_name == ::JSON ||
85
+ type.respond_to?(:type_cast_array, true) && class_name == ::Array
86
+ end
64
87
  end
65
88
  end
66
89
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module AttributeMethods
3
5
  module TimeZoneConversion
@@ -54,17 +56,13 @@ module ActiveRecord
54
56
  extend ActiveSupport::Concern
55
57
 
56
58
  included do
57
- mattr_accessor :time_zone_aware_attributes, instance_writer: false
58
- self.time_zone_aware_attributes = false
59
-
60
- class_attribute :skip_time_zone_conversion_for_attributes, instance_writer: false
61
- self.skip_time_zone_conversion_for_attributes = []
59
+ mattr_accessor :time_zone_aware_attributes, instance_writer: false, default: false
62
60
 
63
- class_attribute :time_zone_aware_types, instance_writer: false
64
- self.time_zone_aware_types = [:datetime, :time]
61
+ class_attribute :skip_time_zone_conversion_for_attributes, instance_writer: false, default: []
62
+ class_attribute :time_zone_aware_types, instance_writer: false, default: [ :datetime, :time ]
65
63
  end
66
64
 
67
- module ClassMethods
65
+ module ClassMethods # :nodoc:
68
66
  private
69
67
 
70
68
  def inherited(subclass)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module AttributeMethods
3
5
  module Write
@@ -7,17 +9,19 @@ module ActiveRecord
7
9
  attribute_method_suffix "="
8
10
  end
9
11
 
10
- module ClassMethods
12
+ module ClassMethods # :nodoc:
11
13
  private
12
14
 
13
15
  def define_method_attribute=(name)
14
16
  safe_name = name.unpack("h*".freeze).first
15
17
  ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
18
+ sync_with_transaction_state = "sync_with_transaction_state" if name == primary_key
16
19
 
17
20
  generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
18
21
  def __temp__#{safe_name}=(value)
19
22
  name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
20
- write_attribute(name, value)
23
+ #{sync_with_transaction_state}
24
+ _write_attribute(name, value)
21
25
  end
22
26
  alias_method #{(name + '=').inspect}, :__temp__#{safe_name}=
23
27
  undef_method :__temp__#{safe_name}=
@@ -35,21 +39,29 @@ module ActiveRecord
35
39
  attr_name.to_s
36
40
  end
37
41
 
38
- name = self.class.primary_key if name == "id".freeze && self.class.primary_key
39
- @attributes.write_from_user(name, value)
40
- value
42
+ primary_key = self.class.primary_key
43
+ name = primary_key if name == "id".freeze && primary_key
44
+ sync_with_transaction_state if name == primary_key
45
+ _write_attribute(name, value)
41
46
  end
42
47
 
43
- def raw_write_attribute(attr_name, value) # :nodoc:
44
- name = attr_name.to_s
45
- @attributes.write_cast_value(name, value)
48
+ # This method exists to avoid the expensive primary_key check internally, without
49
+ # breaking compatibility with the write_attribute API
50
+ def _write_attribute(attr_name, value) # :nodoc:
51
+ @attributes.write_from_user(attr_name.to_s, value)
46
52
  value
47
53
  end
48
54
 
49
55
  private
56
+ def write_attribute_without_type_cast(attr_name, value)
57
+ name = attr_name.to_s
58
+ @attributes.write_cast_value(name, value)
59
+ value
60
+ end
61
+
50
62
  # Handle *= for method_missing.
51
63
  def attribute=(attribute_name, value)
52
- write_attribute(attribute_name, value)
64
+ _write_attribute(attribute_name, value)
53
65
  end
54
66
  end
55
67
  end
@@ -1,4 +1,6 @@
1
- require "active_record/attribute/user_provided_default"
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model/attribute/user_provided_default"
2
4
 
3
5
  module ActiveRecord
4
6
  # See ActiveRecord::Attributes::ClassMethods for documentation
@@ -6,8 +8,7 @@ module ActiveRecord
6
8
  extend ActiveSupport::Concern
7
9
 
8
10
  included do
9
- class_attribute :attributes_to_define_after_schema_loads, instance_accessor: false # :internal:
10
- self.attributes_to_define_after_schema_loads = {}
11
+ class_attribute :attributes_to_define_after_schema_loads, instance_accessor: false, default: {} # :internal:
11
12
  end
12
13
 
13
14
  module ClassMethods
@@ -56,7 +57,7 @@ module ActiveRecord
56
57
  # store_listing = StoreListing.new(price_in_cents: '10.1')
57
58
  #
58
59
  # # before
59
- # store_listing.price_in_cents # => BigDecimal(10.1)
60
+ # store_listing.price_in_cents # => BigDecimal.new(10.1)
60
61
  #
61
62
  # class StoreListing < ActiveRecord::Base
62
63
  # attribute :price_in_cents, :integer
@@ -249,14 +250,14 @@ module ActiveRecord
249
250
  if value == NO_DEFAULT_PROVIDED
250
251
  default_attribute = _default_attributes[name].with_type(type)
251
252
  elsif from_user
252
- default_attribute = Attribute::UserProvidedDefault.new(
253
+ default_attribute = ActiveModel::Attribute::UserProvidedDefault.new(
253
254
  name,
254
255
  value,
255
256
  type,
256
257
  _default_attributes.fetch(name.to_s) { nil },
257
258
  )
258
259
  else
259
- default_attribute = Attribute.from_database(name, value, type)
260
+ default_attribute = ActiveModel::Attribute.from_database(name, value, type)
260
261
  end
261
262
  _default_attributes[name] = default_attribute
262
263
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  # = Active Record Autosave Association
3
5
  #
@@ -140,8 +142,7 @@ module ActiveRecord
140
142
 
141
143
  included do
142
144
  Associations::Builder::Association.extensions << AssociationBuilderExtension
143
- mattr_accessor :index_nested_attribute_errors, instance_writer: false
144
- self.index_nested_attribute_errors = false
145
+ mattr_accessor :index_nested_attribute_errors, instance_writer: false, default: false
145
146
  end
146
147
 
147
148
  module ClassMethods # :nodoc:
@@ -216,13 +217,7 @@ module ActiveRecord
216
217
  method = :validate_single_association
217
218
  end
218
219
 
219
- define_non_cyclic_method(validation_method) do
220
- send(method, reflection)
221
- # TODO: remove the following line as soon as the return value of
222
- # callbacks is ignored, that is, returning `false` does not
223
- # display a deprecation warning or halts the callback chain.
224
- true
225
- end
220
+ define_non_cyclic_method(validation_method) { send(method, reflection) }
226
221
  validate validation_method
227
222
  after_validation :_ensure_no_duplicate_errors
228
223
  end
@@ -369,7 +364,6 @@ module ActiveRecord
369
364
  # association whether or not the parent was a new record before saving.
370
365
  def before_save_collection_association
371
366
  @new_record_before_save = new_record?
372
- true
373
367
  end
374
368
 
375
369
  def after_save_collection_association
@@ -389,7 +383,7 @@ module ActiveRecord
389
383
  autosave = reflection.options[:autosave]
390
384
 
391
385
  # reconstruct the scope now that we know the owner's id
392
- association.reset_scope if association.respond_to?(:reset_scope)
386
+ association.reset_scope
393
387
 
394
388
  if records = associated_records_to_validate_or_save(association, @new_record_before_save, autosave)
395
389
  if autosave
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "yaml"
2
4
  require "active_support/benchmarkable"
3
5
  require "active_support/dependencies"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  # = Active Record \Callbacks
3
5
  #
@@ -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
  #
@@ -238,7 +240,7 @@ module ActiveRecord
238
240
  #
239
241
  # private
240
242
  #
241
- # def log_chidren
243
+ # def log_children
242
244
  # # Child processing
243
245
  # end
244
246
  #
@@ -263,7 +265,7 @@ module ActiveRecord
263
265
  #
264
266
  # private
265
267
  #
266
- # def log_chidren
268
+ # def log_children
267
269
  # # Child processing
268
270
  # end
269
271
  #
@@ -330,10 +332,6 @@ module ActiveRecord
330
332
  _run_touch_callbacks { super }
331
333
  end
332
334
 
333
- def increment!(attribute, by = 1, touch: nil) # :nodoc:
334
- touch ? _run_touch_callbacks { super } : super
335
- end
336
-
337
335
  private
338
336
 
339
337
  def create_or_update(*)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Coders # :nodoc:
3
5
  class JSON # :nodoc:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "yaml"
2
4
 
3
5
  module ActiveRecord
@@ -1,17 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module CollectionCacheKey
3
5
  def collection_cache_key(collection = all, timestamp_column = :updated_at) # :nodoc:
4
6
  query_signature = Digest::MD5.hexdigest(collection.to_sql)
5
7
  key = "#{collection.model_name.cache_key}/query-#{query_signature}"
6
8
 
7
- if collection.loaded? || collection.distinct_value
8
- size = collection.records.size
9
+ if collection.loaded?
10
+ size = collection.size
9
11
  if size > 0
10
12
  timestamp = collection.max_by(&timestamp_column)._read_attribute(timestamp_column)
11
13
  end
12
14
  else
15
+ if collection.eager_loading?
16
+ collection = collection.send(:apply_join_dependency)
17
+ end
13
18
  column_type = type_for_attribute(timestamp_column.to_s)
14
- column = "#{connection.quote_table_name(collection.table_name)}.#{connection.quote_column_name(timestamp_column)}"
19
+ column = connection.column_name_from_arel_node(collection.arel_attribute(timestamp_column))
15
20
  select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
16
21
 
17
22
  if collection.has_limit_or_offset?
@@ -20,14 +25,14 @@ module ActiveRecord
20
25
  subquery_alias = "subquery_for_cache_key"
21
26
  subquery_column = "#{subquery_alias}.#{timestamp_column}"
22
27
  subquery = query.arel.as(subquery_alias)
23
- arel = Arel::SelectManager.new(query.engine).project(select_values % subquery_column).from(subquery)
28
+ arel = Arel::SelectManager.new(subquery).project(select_values % subquery_column)
24
29
  else
25
30
  query = collection.unscope(:order)
26
31
  query.select_values = [select_values % column]
27
32
  arel = query.arel
28
33
  end
29
34
 
30
- result = connection.select_one(arel, nil, query.bound_attributes)
35
+ result = connection.select_one(arel, nil)
31
36
 
32
37
  if result.blank?
33
38
  size = 0
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "thread"
2
4
  require "concurrent/map"
3
5
  require "monitor"
@@ -61,15 +63,13 @@ module ActiveRecord
61
63
  # There are several connection-pooling-related options that you can add to
62
64
  # your database connection configuration:
63
65
  #
64
- # * +pool+: number indicating size of connection pool (default 5)
65
- # * +checkout_timeout+: number of seconds to block and wait for a connection
66
- # before giving up and raising a timeout error (default 5 seconds).
67
- # * +reaping_frequency+: frequency in seconds to periodically run the
68
- # Reaper, which attempts to find and recover connections from dead
69
- # threads, which can occur if a programmer forgets to close a
70
- # connection at the end of a thread or a thread dies unexpectedly.
71
- # Regardless of this setting, the Reaper will be invoked before every
72
- # blocking wait. (Default +nil+, which means don't schedule the Reaper).
66
+ # * +pool+: maximum number of connections the pool may manage (default 5).
67
+ # * +idle_timeout+: number of seconds that a connection will be kept
68
+ # unused in the pool before it is automatically disconnected (default
69
+ # 300 seconds). Set this to zero to keep connections forever.
70
+ # * +checkout_timeout+: number of seconds to wait for a connection to
71
+ # become available before giving up and raising a timeout error (default
72
+ # 5 seconds).
73
73
  #
74
74
  #--
75
75
  # Synchronization policy:
@@ -80,11 +80,8 @@ module ActiveRecord
80
80
  # * private methods that require being called in a +synchronize+ blocks
81
81
  # are now explicitly documented
82
82
  class ConnectionPool
83
- # Threadsafe, fair, FIFO queue. Meant to be used by ConnectionPool
84
- # with which it shares a Monitor. But could be a generic Queue.
85
- #
86
- # The Queue in stdlib's 'thread' could replace this class except
87
- # stdlib's doesn't support waiting with a timeout.
83
+ # Threadsafe, fair, LIFO queue. Meant to be used by ConnectionPool
84
+ # with which it shares a Monitor.
88
85
  class Queue
89
86
  def initialize(lock = Monitor.new)
90
87
  @lock = lock
@@ -173,7 +170,7 @@ module ActiveRecord
173
170
 
174
171
  # Removes and returns the head of the queue if possible, or +nil+.
175
172
  def remove
176
- @queue.shift
173
+ @queue.pop
177
174
  end
178
175
 
179
176
  # Remove and return the head the queue if the number of
@@ -191,9 +188,7 @@ module ActiveRecord
191
188
  t0 = Time.now
192
189
  elapsed = 0
193
190
  loop do
194
- ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
195
- @cond.wait(timeout - elapsed)
196
- end
191
+ @cond.wait(timeout - elapsed)
197
192
 
198
193
  return remove if any?
199
194
 
@@ -270,7 +265,7 @@ module ActiveRecord
270
265
  # Connections must be leased while holding the main pool mutex. This is
271
266
  # an internal subclass that also +.leases+ returned connections while
272
267
  # still in queue's critical section (queue synchronizes with the same
273
- # +@lock+ as the main pool) so that a returned connection is already
268
+ # <tt>@lock</tt> as the main pool) so that a returned connection is already
274
269
  # leased and there is no need to re-enter synchronized block.
275
270
  class ConnectionLeasingQueue < Queue # :nodoc:
276
271
  include BiasableQueue
@@ -283,12 +278,12 @@ module ActiveRecord
283
278
  end
284
279
  end
285
280
 
286
- # Every +frequency+ seconds, the reaper will call +reap+ on +pool+.
287
- # A reaper instantiated with a +nil+ frequency will never reap the
288
- # connection pool.
281
+ # Every +frequency+ seconds, the reaper will call +reap+ and +flush+ on
282
+ # +pool+. A reaper instantiated with a zero frequency will never reap
283
+ # the connection pool.
289
284
  #
290
- # Configure the frequency by setting "reaping_frequency" in your
291
- # database yaml file.
285
+ # Configure the frequency by setting +reaping_frequency+ in your database
286
+ # yaml file (default 60 seconds).
292
287
  class Reaper
293
288
  attr_reader :pool, :frequency
294
289
 
@@ -298,11 +293,12 @@ module ActiveRecord
298
293
  end
299
294
 
300
295
  def run
301
- return unless frequency
296
+ return unless frequency && frequency > 0
302
297
  Thread.new(frequency, pool) { |t, p|
303
298
  loop do
304
299
  sleep t
305
300
  p.reap
301
+ p.flush
306
302
  end
307
303
  }
308
304
  end
@@ -326,8 +322,10 @@ module ActiveRecord
326
322
  @spec = spec
327
323
 
328
324
  @checkout_timeout = (spec.config[:checkout_timeout] && spec.config[:checkout_timeout].to_f) || 5
329
- @reaper = Reaper.new(self, (spec.config[:reaping_frequency] && spec.config[:reaping_frequency].to_f))
330
- @reaper.run
325
+ if @idle_timeout = spec.config.fetch(:idle_timeout, 300)
326
+ @idle_timeout = @idle_timeout.to_f
327
+ @idle_timeout = nil if @idle_timeout <= 0
328
+ end
331
329
 
332
330
  # default max pool size to 5
333
331
  @size = (spec.config[:pool] && spec.config[:pool].to_i) || 5
@@ -340,7 +338,7 @@ module ActiveRecord
340
338
  # then that +thread+ does indeed own that +conn+. However, an absence of a such
341
339
  # mapping does not mean that the +thread+ doesn't own the said connection. In
342
340
  # that case +conn.owner+ attr should be consulted.
343
- # Access and modification of +@thread_cached_conns+ does not require
341
+ # Access and modification of <tt>@thread_cached_conns</tt> does not require
344
342
  # synchronization.
345
343
  @thread_cached_conns = Concurrent::Map.new(initial_capacity: @size)
346
344
 
@@ -357,6 +355,12 @@ module ActiveRecord
357
355
  @available = ConnectionLeasingQueue.new self
358
356
 
359
357
  @lock_thread = false
358
+
359
+ # +reaping_frequency+ is configurable mostly for historical reasons, but it could
360
+ # also be useful if someone wants a very low +idle_timeout+.
361
+ reaping_frequency = spec.config.fetch(:reaping_frequency, 60)
362
+ @reaper = Reaper.new(self, reaping_frequency && reaping_frequency.to_f)
363
+ @reaper.run
360
364
  end
361
365
 
362
366
  def lock_thread=(lock_thread)
@@ -449,6 +453,21 @@ module ActiveRecord
449
453
  disconnect(false)
450
454
  end
451
455
 
456
+ # Discards all connections in the pool (even if they're currently
457
+ # leased!), along with the pool itself. Any further interaction with the
458
+ # pool (except #spec and #schema_cache) is undefined.
459
+ #
460
+ # See AbstractAdapter#discard!
461
+ def discard! # :nodoc:
462
+ synchronize do
463
+ return if @connections.nil? # already discarded
464
+ @connections.each do |conn|
465
+ conn.discard!
466
+ end
467
+ @connections = @available = @thread_cached_conns = nil
468
+ end
469
+ end
470
+
452
471
  # Clears the cache which maps classes and re-connects connections that
453
472
  # require reloading.
454
473
  #
@@ -574,6 +593,35 @@ module ActiveRecord
574
593
  end
575
594
  end
576
595
 
596
+ # Disconnect all connections that have been idle for at least
597
+ # +minimum_idle+ seconds. Connections currently checked out, or that were
598
+ # checked in less than +minimum_idle+ seconds ago, are unaffected.
599
+ def flush(minimum_idle = @idle_timeout)
600
+ return if minimum_idle.nil?
601
+
602
+ idle_connections = synchronize do
603
+ @connections.select do |conn|
604
+ !conn.in_use? && conn.seconds_idle >= minimum_idle
605
+ end.each do |conn|
606
+ conn.lease
607
+
608
+ @available.delete conn
609
+ @connections.delete conn
610
+ end
611
+ end
612
+
613
+ idle_connections.each do |conn|
614
+ conn.disconnect!
615
+ end
616
+ end
617
+
618
+ # Disconnect all currently idle connections. Connections currently checked
619
+ # out are unaffected.
620
+ def flush!
621
+ reap
622
+ flush(-1)
623
+ end
624
+
577
625
  def num_waiting_in_queue # :nodoc:
578
626
  @available.num_waiting
579
627
  end
@@ -681,7 +729,7 @@ module ActiveRecord
681
729
  # this block can't be easily moved into attempt_to_checkout_all_existing_connections's
682
730
  # rescue block, because doing so would put it outside of synchronize section, without
683
731
  # being in a critical section thread_report might become inaccurate
684
- msg = "could not obtain ownership of all database connections in #{checkout_timeout} seconds"
732
+ msg = "could not obtain ownership of all database connections in #{checkout_timeout} seconds".dup
685
733
 
686
734
  thread_report = []
687
735
  @connections.each do |conn|
@@ -736,10 +784,10 @@ module ActiveRecord
736
784
  # Implementation detail: the connection returned by +acquire_connection+
737
785
  # will already be "+connection.lease+ -ed" to the current thread.
738
786
  def acquire_connection(checkout_timeout)
739
- # NOTE: we rely on +@available.poll+ and +try_to_checkout_new_connection+ to
787
+ # NOTE: we rely on <tt>@available.poll</tt> and +try_to_checkout_new_connection+ to
740
788
  # +conn.lease+ the returned connection (and to do this in a +synchronized+
741
789
  # section). This is not the cleanest implementation, as ideally we would
742
- # <tt>synchronize { conn.lease }</tt> in this method, but by leaving it to +@available.poll+
790
+ # <tt>synchronize { conn.lease }</tt> in this method, but by leaving it to <tt>@available.poll</tt>
743
791
  # and +try_to_checkout_new_connection+ we can piggyback on +synchronize+ sections
744
792
  # of the said methods and avoid an additional +synchronize+ overhead.
745
793
  if conn = @available.poll || try_to_checkout_new_connection
@@ -763,7 +811,7 @@ module ActiveRecord
763
811
  end
764
812
  end
765
813
 
766
- # If the pool is not at a +@size+ limit, establish new connection. Connecting
814
+ # If the pool is not at a <tt>@size</tt> limit, establish new connection. Connecting
767
815
  # to the DB is done outside main synchronized section.
768
816
  #--
769
817
  # Implementation constraint: a newly established connection returned by this
@@ -829,7 +877,7 @@ module ActiveRecord
829
877
  # end
830
878
  #
831
879
  # class Book < ActiveRecord::Base
832
- # establish_connection "library_db"
880
+ # establish_connection :library_db
833
881
  # end
834
882
  #
835
883
  # class ScaryBook < Book
@@ -861,15 +909,35 @@ module ActiveRecord
861
909
  # All Active Record models use this handler to determine the connection pool that they
862
910
  # should use.
863
911
  #
864
- # The ConnectionHandler class is not coupled with the Active models, as it has no knowlodge
912
+ # The ConnectionHandler class is not coupled with the Active models, as it has no knowledge
865
913
  # about the model. The model needs to pass a specification name to the handler,
866
- # in order to lookup the correct connection pool.
914
+ # in order to look up the correct connection pool.
867
915
  class ConnectionHandler
916
+ def self.unowned_pool_finalizer(pid_map) # :nodoc:
917
+ lambda do |_|
918
+ discard_unowned_pools(pid_map)
919
+ end
920
+ end
921
+
922
+ def self.discard_unowned_pools(pid_map) # :nodoc:
923
+ pid_map.each do |pid, pools|
924
+ pools.values.compact.each(&:discard!) unless pid == Process.pid
925
+ end
926
+ end
927
+
868
928
  def initialize
869
929
  # These caches are keyed by spec.name (ConnectionSpecification#name).
870
930
  @owner_to_pool = Concurrent::Map.new(initial_capacity: 2) do |h, k|
931
+ # Discard the parent's connection pools immediately; we have no need
932
+ # of them
933
+ ConnectionHandler.discard_unowned_pools(h)
934
+
871
935
  h[k] = Concurrent::Map.new(initial_capacity: 2)
872
936
  end
937
+
938
+ # Backup finalizer: if the forked child never needed a pool, the above
939
+ # early discard has not occurred
940
+ ObjectSpace.define_finalizer self, ConnectionHandler.unowned_pool_finalizer(@owner_to_pool)
873
941
  end
874
942
 
875
943
  def connection_pool_list
@@ -923,6 +991,13 @@ module ActiveRecord
923
991
  connection_pool_list.each(&:disconnect!)
924
992
  end
925
993
 
994
+ # Disconnects all currently idle connections.
995
+ #
996
+ # See ConnectionPool#flush! for details.
997
+ def flush_idle_connections!
998
+ connection_pool_list.each(&:flush!)
999
+ end
1000
+
926
1001
  # Locate the connection of the nearest super class. This can be an
927
1002
  # active or defined connection: if it is the latter, it will be
928
1003
  # opened and set as the active connection for the class it was defined