activerecord 4.2.0 → 5.2.8.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 +5 -5
  2. data/CHANGELOG.md +640 -928
  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 +264 -247
  8. data/lib/active_record/association_relation.rb +24 -6
  9. data/lib/active_record/associations/alias_tracker.rb +29 -35
  10. data/lib/active_record/associations/association.rb +87 -41
  11. data/lib/active_record/associations/association_scope.rb +106 -132
  12. data/lib/active_record/associations/belongs_to_association.rb +55 -36
  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 +14 -23
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +50 -39
  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 +145 -266
  22. data/lib/active_record/associations/collection_proxy.rb +242 -138
  23. data/lib/active_record/associations/foreign_association.rb +13 -0
  24. data/lib/active_record/associations/has_many_association.rb +35 -75
  25. data/lib/active_record/associations/has_many_through_association.rb +51 -69
  26. data/lib/active_record/associations/has_one_association.rb +39 -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 -81
  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 +134 -154
  32. data/lib/active_record/associations/preloader/association.rb +85 -116
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -74
  34. data/lib/active_record/associations/preloader.rb +83 -93
  35. data/lib/active_record/associations/singular_association.rb +27 -40
  36. data/lib/active_record/associations/through_association.rb +48 -23
  37. data/lib/active_record/associations.rb +1732 -1596
  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 +12 -5
  41. data/lib/active_record/attribute_methods/dirty.rb +94 -125
  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 +62 -36
  47. data/lib/active_record/attribute_methods/write.rb +31 -46
  48. data/lib/active_record/attribute_methods.rb +170 -117
  49. data/lib/active_record/attributes.rb +201 -74
  50. data/lib/active_record/autosave_association.rb +118 -45
  51. data/lib/active_record/base.rb +60 -48
  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 +37 -13
  55. data/lib/active_record/collection_cache_key.rb +53 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +712 -284
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +10 -5
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +254 -87
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +72 -22
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -52
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +6 -4
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +67 -46
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -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 +617 -212
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +139 -75
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +332 -191
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +567 -563
  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 +42 -195
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +35 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -115
  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 -57
  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 +5 -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 -13
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +7 -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 +7 -9
  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 -1
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +65 -51
  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 +466 -280
  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 +439 -330
  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 -324
  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 +205 -202
  129. data/lib/active_record/counter_cache.rb +80 -37
  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 +136 -90
  133. data/lib/active_record/errors.rb +180 -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 +11 -6
  137. data/lib/active_record/fixture_set/file.rb +35 -9
  138. data/lib/active_record/fixtures.rb +193 -135
  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 +48 -0
  144. data/lib/active_record/locale/en.yml +3 -2
  145. data/lib/active_record/locking/optimistic.rb +92 -98
  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 +594 -267
  152. data/lib/active_record/model_schema.rb +292 -111
  153. data/lib/active_record/nested_attributes.rb +266 -214
  154. data/lib/active_record/no_touching.rb +8 -2
  155. data/lib/active_record/null_relation.rb +24 -37
  156. data/lib/active_record/persistence.rb +350 -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 +117 -35
  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 +160 -174
  163. data/lib/active_record/readonly_attributes.rb +5 -4
  164. data/lib/active_record/reflection.rb +447 -288
  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 +259 -244
  168. data/lib/active_record/relation/delegation.rb +67 -60
  169. data/lib/active_record/relation/finder_methods.rb +290 -253
  170. data/lib/active_record/relation/from_clause.rb +26 -0
  171. data/lib/active_record/relation/merger.rb +91 -68
  172. data/lib/active_record/relation/predicate_builder/array_handler.rb +24 -23
  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 +118 -92
  180. data/lib/active_record/relation/query_attribute.rb +45 -0
  181. data/lib/active_record/relation/query_methods.rb +446 -389
  182. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  183. data/lib/active_record/relation/spawn_methods.rb +18 -16
  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 -339
  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 -19
  193. data/lib/active_record/scoping/default.rb +102 -84
  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 +136 -95
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +59 -89
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -31
  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 +208 -123
  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 -41
  212. data/lib/active_record/type/date_time.rb +4 -38
  213. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  214. data/lib/active_record/type/hash_lookup_type_map.rb +13 -5
  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 +30 -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 +41 -32
  231. data/lib/active_record/validations.rb +38 -35
  232. data/lib/active_record/version.rb +3 -1
  233. data/lib/active_record.rb +36 -21
  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 -6
  238. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +8 -7
  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.rb +7 -5
  243. metadata +77 -53
  244. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  245. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  246. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  247. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  248. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  249. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  250. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  251. data/lib/active_record/attribute.rb +0 -149
  252. data/lib/active_record/attribute_set/builder.rb +0 -86
  253. data/lib/active_record/attribute_set.rb +0 -77
  254. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  255. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  256. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  257. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  258. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  259. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  260. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  261. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  262. data/lib/active_record/type/big_integer.rb +0 -13
  263. data/lib/active_record/type/binary.rb +0 -50
  264. data/lib/active_record/type/boolean.rb +0 -30
  265. data/lib/active_record/type/decimal.rb +0 -40
  266. data/lib/active_record/type/decorator.rb +0 -14
  267. data/lib/active_record/type/float.rb +0 -19
  268. data/lib/active_record/type/integer.rb +0 -55
  269. data/lib/active_record/type/mutable.rb +0 -16
  270. data/lib/active_record/type/numeric.rb +0 -36
  271. data/lib/active_record/type/string.rb +0 -36
  272. data/lib/active_record/type/time_value.rb +0 -38
  273. data/lib/active_record/type/value.rb +0 -101
  274. /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,7 +1,8 @@
1
- require 'thread'
2
- require 'active_support/core_ext/hash/indifferent_access'
3
- require 'active_support/core_ext/object/duplicable'
4
- require 'active_support/core_ext/string/filters'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/hash/indifferent_access"
4
+ require "active_support/core_ext/string/filters"
5
+ require "concurrent/map"
5
6
 
6
7
  module ActiveRecord
7
8
  module Core
@@ -16,6 +17,13 @@ module ActiveRecord
16
17
  # retrieved on both a class and instance level by calling +logger+.
17
18
  mattr_accessor :logger, instance_writer: false
18
19
 
20
+ ##
21
+ # :singleton-method:
22
+ #
23
+ # Specifies if the methods calling database queries should be logged below
24
+ # their relevant queries. Defaults to false.
25
+ mattr_accessor :verbose_query_logs, instance_writer: false, default: false
26
+
19
27
  ##
20
28
  # Contains the database configuration - as is typically stored in config/database.yml -
21
29
  # as a Hash.
@@ -56,8 +64,7 @@ module ActiveRecord
56
64
  # :singleton-method:
57
65
  # Determines whether to use Time.utc (using :utc) or Time.local (using :local) when pulling
58
66
  # dates and times from the database. This is set to :utc by default.
59
- mattr_accessor :default_timezone, instance_writer: false
60
- self.default_timezone = :utc
67
+ mattr_accessor :default_timezone, instance_writer: false, default: :utc
61
68
 
62
69
  ##
63
70
  # :singleton-method:
@@ -67,14 +74,27 @@ module ActiveRecord
67
74
  # ActiveRecord::Schema file which can be loaded into any database that
68
75
  # supports migrations. Use :ruby if you want to have different database
69
76
  # adapters for, e.g., your development and test environments.
70
- mattr_accessor :schema_format, instance_writer: false
71
- self.schema_format = :ruby
77
+ mattr_accessor :schema_format, instance_writer: false, default: :ruby
78
+
79
+ ##
80
+ # :singleton-method:
81
+ # Specifies if an error should be raised if the query has an order being
82
+ # ignored when doing batch queries. Useful in applications where the
83
+ # scope being ignored is error-worthy, rather than a warning.
84
+ mattr_accessor :error_on_ignored_order, instance_writer: false, default: false
85
+
86
+ # :singleton-method:
87
+ # Specify the behavior for unsafe raw query methods. Values are as follows
88
+ # deprecated - Warnings are logged when unsafe raw SQL is passed to
89
+ # query methods.
90
+ # disabled - Unsafe raw SQL passed to query methods results in
91
+ # UnknownAttributeReference exception.
92
+ mattr_accessor :allow_unsafe_raw_sql, instance_writer: false, default: :deprecated
72
93
 
73
94
  ##
74
95
  # :singleton-method:
75
96
  # Specify whether or not to use timestamps for migration versions
76
- mattr_accessor :timestamped_migrations, instance_writer: false
77
- self.timestamped_migrations = true
97
+ mattr_accessor :timestamped_migrations, instance_writer: false, default: true
78
98
 
79
99
  ##
80
100
  # :singleton-method:
@@ -82,20 +102,40 @@ module ActiveRecord
82
102
  # db:migrate rake task. This is true by default, which is useful for the
83
103
  # development environment. This should ideally be false in the production
84
104
  # environment where dumping schema is rarely needed.
85
- mattr_accessor :dump_schema_after_migration, instance_writer: false
86
- self.dump_schema_after_migration = true
105
+ mattr_accessor :dump_schema_after_migration, instance_writer: false, default: true
106
+
107
+ ##
108
+ # :singleton-method:
109
+ # Specifies which database schemas to dump when calling db:structure:dump.
110
+ # If the value is :schema_search_path (the default), any schemas listed in
111
+ # schema_search_path are dumped. Use :all to dump all schemas regardless
112
+ # of schema_search_path, or a string of comma separated schemas for a
113
+ # custom list.
114
+ mattr_accessor :dump_schemas, instance_writer: false, default: :schema_search_path
115
+
116
+ ##
117
+ # :singleton-method:
118
+ # Specify a threshold for the size of query result sets. If the number of
119
+ # records in the set exceeds the threshold, a warning is logged. This can
120
+ # be used to identify queries which load thousands of records and
121
+ # potentially cause memory bloat.
122
+ mattr_accessor :warn_on_records_fetched_greater_than, instance_writer: false
87
123
 
88
124
  mattr_accessor :maintain_test_schema, instance_accessor: false
89
125
 
90
- def self.disable_implicit_join_references=(value)
91
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
92
- Implicit join references were removed with Rails 4.1.
93
- Make sure to remove this configuration because it does nothing.
94
- MSG
95
- end
126
+ mattr_accessor :belongs_to_required_by_default, instance_accessor: false
127
+
128
+ ##
129
+ # :singleton-method:
130
+ # Application configurable boolean that instructs the YAML Coder to use
131
+ # an unsafe load if set to true.
132
+ mattr_accessor :use_yaml_unsafe_load, instance_writer: false, default: false
133
+
134
+ # Application configurable array that provides additional permitted classes
135
+ # to Psych safe_load in the YAML Coder
136
+ mattr_accessor :yaml_column_permitted_classes, instance_writer: false, default: []
96
137
 
97
138
  class_attribute :default_connection_handler, instance_writer: false
98
- class_attribute :find_by_statement_cache
99
139
 
100
140
  def self.connection_handler
101
141
  ActiveRecord::RuntimeRegistry.connection_handler || default_connection_handler
@@ -108,101 +148,95 @@ module ActiveRecord
108
148
  self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new
109
149
  end
110
150
 
111
- module ClassMethods
151
+ module ClassMethods # :nodoc:
112
152
  def allocate
113
153
  define_attribute_methods
114
154
  super
115
155
  end
116
156
 
117
- def initialize_find_by_cache
118
- self.find_by_statement_cache = {}.extend(Mutex_m)
157
+ def initialize_find_by_cache # :nodoc:
158
+ @find_by_statement_cache = { true => Concurrent::Map.new, false => Concurrent::Map.new }
119
159
  end
120
160
 
121
- def inherited(child_class)
161
+ def inherited(child_class) # :nodoc:
162
+ # initialize cache at class definition for thread safety
122
163
  child_class.initialize_find_by_cache
123
164
  super
124
165
  end
125
166
 
126
- def find(*ids)
167
+ def find(*ids) # :nodoc:
127
168
  # We don't have cache keys for this stuff yet
128
169
  return super unless ids.length == 1
129
- # Allow symbols to super to maintain compatibility for deprecated finders until Rails 5
130
- return super if ids.first.kind_of?(Symbol)
131
170
  return super if block_given? ||
132
171
  primary_key.nil? ||
133
- default_scopes.any? ||
134
- columns_hash.include?(inheritance_column) ||
135
- ids.first.kind_of?(Array)
136
-
137
- id = ids.first
138
- if ActiveRecord::Base === id
139
- id = id.id
140
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
141
- You are passing an instance of ActiveRecord::Base to `find`.
142
- Please pass the id of the object by calling `.id`
143
- MSG
144
- end
172
+ scope_attributes? ||
173
+ columns_hash.include?(inheritance_column)
174
+
175
+ id = ids.first
176
+
177
+ return super if StatementCache.unsupported_value?(id)
178
+
145
179
  key = primary_key
146
180
 
147
- s = find_by_statement_cache[key] || find_by_statement_cache.synchronize {
148
- find_by_statement_cache[key] ||= StatementCache.create(connection) { |params|
149
- where(key => params.bind).limit(1)
150
- }
181
+ statement = cached_find_by_statement(key) { |params|
182
+ where(key => params.bind).limit(1)
151
183
  }
152
- record = s.execute([id], self, connection).first
184
+
185
+ record = statement.execute([id], connection).first
153
186
  unless record
154
- raise RecordNotFound, "Couldn't find #{name} with '#{primary_key}'=#{id}"
187
+ raise RecordNotFound.new("Couldn't find #{name} with '#{primary_key}'=#{id}",
188
+ name, primary_key, id)
155
189
  end
156
190
  record
157
- rescue RangeError
158
- raise RecordNotFound, "Couldn't find #{name} with an out of range value for '#{primary_key}'"
191
+ rescue ::RangeError
192
+ raise RecordNotFound.new("Couldn't find #{name} with an out of range value for '#{primary_key}'",
193
+ name, primary_key)
159
194
  end
160
195
 
161
- def find_by(*args)
162
- return super if current_scope || !(Hash === args.first) || reflect_on_all_aggregations.any?
163
- return super if default_scopes.any?
196
+ def find_by(*args) # :nodoc:
197
+ return super if scope_attributes? || reflect_on_all_aggregations.any? ||
198
+ columns_hash.key?(inheritance_column) && base_class != self
164
199
 
165
200
  hash = args.first
166
201
 
167
- return super if hash.values.any? { |v|
168
- v.nil? || Array === v || Hash === v
202
+ return super if !(Hash === hash) || hash.values.any? { |v|
203
+ StatementCache.unsupported_value?(v)
169
204
  }
170
205
 
171
206
  # We can't cache Post.find_by(author: david) ...yet
172
207
  return super unless hash.keys.all? { |k| columns_hash.has_key?(k.to_s) }
173
208
 
174
- key = hash.keys
209
+ keys = hash.keys
175
210
 
176
- klass = self
177
- s = find_by_statement_cache[key] || find_by_statement_cache.synchronize {
178
- find_by_statement_cache[key] ||= StatementCache.create(connection) { |params|
179
- wheres = key.each_with_object({}) { |param,o|
180
- o[param] = params.bind
181
- }
182
- klass.where(wheres).limit(1)
211
+ statement = cached_find_by_statement(keys) { |params|
212
+ wheres = keys.each_with_object({}) { |param, o|
213
+ o[param] = params.bind
183
214
  }
215
+ where(wheres).limit(1)
184
216
  }
185
217
  begin
186
- s.execute(hash.values, self, connection).first
187
- rescue TypeError => e
188
- raise ActiveRecord::StatementInvalid.new(e.message, e)
189
- rescue RangeError
218
+ statement.execute(hash.values, connection).first
219
+ rescue TypeError
220
+ raise ActiveRecord::StatementInvalid
221
+ rescue ::RangeError
190
222
  nil
191
223
  end
192
224
  end
193
225
 
194
- def find_by!(*args)
195
- find_by(*args) or raise RecordNotFound.new("Couldn't find #{name}")
226
+ def find_by!(*args) # :nodoc:
227
+ find_by(*args) || raise(RecordNotFound.new("Couldn't find #{name}", name))
196
228
  end
197
229
 
198
- def initialize_generated_modules
230
+ def initialize_generated_modules # :nodoc:
199
231
  generated_association_methods
200
232
  end
201
233
 
202
234
  def generated_association_methods
203
235
  @generated_association_methods ||= begin
204
236
  mod = const_set(:GeneratedAssociationMethods, Module.new)
237
+ private_constant :GeneratedAssociationMethods
205
238
  include mod
239
+
206
240
  mod
207
241
  end
208
242
  end
@@ -216,14 +250,14 @@ module ActiveRecord
216
250
  elsif !connected?
217
251
  "#{super} (call '#{super}.connection' to establish a connection)"
218
252
  elsif table_exists?
219
- attr_list = columns.map { |c| "#{c.name}: #{c.type}" } * ', '
253
+ attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } * ", "
220
254
  "#{super}(#{attr_list})"
221
255
  else
222
256
  "#{super}(Table doesn't exist)"
223
257
  end
224
258
  end
225
259
 
226
- # Overwrite the default class equality method to provide support for association proxies.
260
+ # Overwrite the default class equality method to provide support for decorated models.
227
261
  def ===(object)
228
262
  object.is_a?(self)
229
263
  end
@@ -231,33 +265,46 @@ module ActiveRecord
231
265
  # Returns an instance of <tt>Arel::Table</tt> loaded with the current table name.
232
266
  #
233
267
  # class Post < ActiveRecord::Base
234
- # scope :published_and_commented, -> { published.and(self.arel_table[:comments_count].gt(0)) }
268
+ # scope :published_and_commented, -> { published.and(arel_table[:comments_count].gt(0)) }
235
269
  # end
236
270
  def arel_table # :nodoc:
237
- @arel_table ||= Arel::Table.new(table_name, arel_engine)
271
+ @arel_table ||= Arel::Table.new(table_name, type_caster: type_caster)
238
272
  end
239
273
 
240
- # Returns the Arel engine.
241
- def arel_engine # :nodoc:
242
- @arel_engine ||=
243
- if Base == self || connection_handler.retrieve_connection_pool(self)
244
- self
245
- else
246
- superclass.arel_engine
247
- end
274
+ def arel_attribute(name, table = arel_table) # :nodoc:
275
+ name = attribute_alias(name) if attribute_alias?(name)
276
+ table[name]
277
+ end
278
+
279
+ def predicate_builder # :nodoc:
280
+ @predicate_builder ||= PredicateBuilder.new(table_metadata)
281
+ end
282
+
283
+ def type_caster # :nodoc:
284
+ TypeCaster::Map.new(self)
248
285
  end
249
286
 
250
287
  private
251
288
 
252
- def relation #:nodoc:
253
- relation = Relation.create(self, arel_table)
289
+ def cached_find_by_statement(key, &block)
290
+ cache = @find_by_statement_cache[connection.prepared_statements]
291
+ cache.compute_if_absent(key) { StatementCache.create(connection, &block) }
292
+ end
254
293
 
255
- if finder_needs_type_condition?
256
- relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
257
- else
258
- relation
294
+ def relation
295
+ relation = Relation.create(self)
296
+
297
+ if finder_needs_type_condition? && !ignore_default_scope?
298
+ relation.where!(type_condition)
299
+ relation.create_with!(inheritance_column.to_s => sti_name)
300
+ else
301
+ relation
302
+ end
303
+ end
304
+
305
+ def table_metadata
306
+ TableMetadata.new(self, arel_table)
259
307
  end
260
- end
261
308
  end
262
309
 
263
310
  # New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
@@ -268,40 +315,45 @@ module ActiveRecord
268
315
  # ==== Example:
269
316
  # # Instantiates a single new object
270
317
  # User.new(first_name: 'Jamie')
271
- def initialize(attributes = nil, options = {})
272
- @attributes = self.class._default_attributes.dup
318
+ def initialize(attributes = nil)
319
+ self.class.define_attribute_methods
320
+ @attributes = self.class._default_attributes.deep_dup
273
321
 
274
322
  init_internals
275
323
  initialize_internals_callback
276
324
 
277
- self.class.define_attribute_methods
278
- # +options+ argument is only needed to make protected_attributes gem easier to hook.
279
- # Remove it when we drop support to this gem.
280
- init_attributes(attributes, options) if attributes
325
+ assign_attributes(attributes) if attributes
281
326
 
282
327
  yield self if block_given?
283
328
  _run_initialize_callbacks
284
329
  end
285
330
 
286
- # Initialize an empty model object from +coder+. +coder+ must contain
287
- # the attributes necessary for initializing an empty model object. For
288
- # example:
331
+ # Initialize an empty model object from +coder+. +coder+ should be
332
+ # the result of previously encoding an Active Record model, using
333
+ # #encode_with.
289
334
  #
290
335
  # class Post < ActiveRecord::Base
291
336
  # end
292
337
  #
338
+ # old_post = Post.new(title: "hello world")
339
+ # coder = {}
340
+ # old_post.encode_with(coder)
341
+ #
293
342
  # post = Post.allocate
294
- # post.init_with('attributes' => { 'title' => 'hello world' })
343
+ # post.init_with(coder)
295
344
  # post.title # => 'hello world'
296
345
  def init_with(coder)
297
- @attributes = coder['attributes']
346
+ coder = LegacyYamlAdapter.convert(self.class, coder)
347
+ @attributes = self.class.yaml_encoder.decode(coder)
298
348
 
299
349
  init_internals
300
350
 
301
- @new_record = coder['new_record']
351
+ @new_record = coder["new_record"]
302
352
 
303
353
  self.class.define_attribute_methods
304
354
 
355
+ yield self if block_given?
356
+
305
357
  _run_find_callbacks
306
358
  _run_initialize_callbacks
307
359
 
@@ -336,23 +388,22 @@ module ActiveRecord
336
388
 
337
389
  ##
338
390
  def initialize_dup(other) # :nodoc:
339
- @attributes = @attributes.dup
391
+ @attributes = @attributes.deep_dup
340
392
  @attributes.reset(self.class.primary_key)
341
393
 
342
394
  _run_initialize_callbacks
343
395
 
344
- @aggregation_cache = {}
345
- @association_cache = {}
346
-
347
- @new_record = true
348
- @destroyed = false
396
+ @new_record = true
397
+ @destroyed = false
398
+ @_start_transaction_state = {}
399
+ @transaction_state = nil
349
400
 
350
401
  super
351
402
  end
352
403
 
353
404
  # Populate +coder+ with attributes about this record that should be
354
405
  # serialized. The structure of +coder+ defined in this method is
355
- # guaranteed to match the structure of +coder+ passed to the +init_with+
406
+ # guaranteed to match the structure of +coder+ passed to the #init_with
356
407
  # method.
357
408
  #
358
409
  # Example:
@@ -363,10 +414,9 @@ module ActiveRecord
363
414
  # Post.new.encode_with(coder)
364
415
  # coder # => {"attributes" => {"id" => nil, ... }}
365
416
  def encode_with(coder)
366
- # FIXME: Remove this when we better serialize attributes
367
- coder['raw_attributes'] = attributes_before_type_cast
368
- coder['attributes'] = @attributes
369
- coder['new_record'] = new_record?
417
+ self.class.yaml_encoder.encode(@attributes, coder)
418
+ coder["new_record"] = new_record?
419
+ coder["active_record_yaml_version"] = 2
370
420
  end
371
421
 
372
422
  # Returns true if +comparison_object+ is the same exact object, or +comparison_object+
@@ -390,7 +440,7 @@ module ActiveRecord
390
440
  # [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
391
441
  def hash
392
442
  if id
393
- id.hash
443
+ self.class.hash ^ id.hash
394
444
  else
395
445
  super
396
446
  end
@@ -412,7 +462,7 @@ module ActiveRecord
412
462
  # Allows sort on objects
413
463
  def <=>(other_object)
414
464
  if other_object.is_a?(self.class)
415
- self.to_key <=> other_object.to_key
465
+ to_key <=> other_object.to_key
416
466
  else
417
467
  super
418
468
  end
@@ -438,129 +488,82 @@ module ActiveRecord
438
488
  # We check defined?(@attributes) not to issue warnings if the object is
439
489
  # allocated but not initialized.
440
490
  inspection = if defined?(@attributes) && @attributes
441
- self.class.column_names.collect { |name|
442
- if has_attribute?(name)
443
- "#{name}: #{attribute_for_inspect(name)}"
444
- end
445
- }.compact.join(", ")
446
- else
447
- "not initialized"
448
- end
491
+ self.class.attribute_names.collect do |name|
492
+ if has_attribute?(name)
493
+ "#{name}: #{attribute_for_inspect(name)}"
494
+ end
495
+ end.compact.join(", ")
496
+ else
497
+ "not initialized"
498
+ end
499
+
449
500
  "#<#{self.class} #{inspection}>"
450
501
  end
451
502
 
452
- # Takes a PP and prettily prints this record to it, allowing you to get a nice result from `pp record`
503
+ # Takes a PP and prettily prints this record to it, allowing you to get a nice result from <tt>pp record</tt>
453
504
  # when pp is required.
454
505
  def pretty_print(pp)
506
+ return super if custom_inspect_method_defined?
455
507
  pp.object_address_group(self) do
456
508
  if defined?(@attributes) && @attributes
457
509
  column_names = self.class.column_names.select { |name| has_attribute?(name) || new_record? }
458
- pp.seplist(column_names, proc { pp.text ',' }) do |column_name|
510
+ pp.seplist(column_names, proc { pp.text "," }) do |column_name|
459
511
  column_value = read_attribute(column_name)
460
- pp.breakable ' '
512
+ pp.breakable " "
461
513
  pp.group(1) do
462
514
  pp.text column_name
463
- pp.text ':'
515
+ pp.text ":"
464
516
  pp.breakable
465
517
  pp.pp column_value
466
518
  end
467
519
  end
468
520
  else
469
- pp.breakable ' '
470
- pp.text 'not initialized'
521
+ pp.breakable " "
522
+ pp.text "not initialized"
471
523
  end
472
524
  end
473
525
  end
474
526
 
475
527
  # Returns a hash of the given methods with their names as keys and returned values as values.
476
528
  def slice(*methods)
477
- Hash[methods.map! { |method| [method, public_send(method)] }].with_indifferent_access
478
- end
479
-
480
- def set_transaction_state(state) # :nodoc:
481
- @transaction_state = state
482
- end
483
-
484
- def has_transactional_callbacks? # :nodoc:
485
- !_rollback_callbacks.empty? || !_commit_callbacks.empty? || !_create_callbacks.empty?
529
+ Hash[methods.flatten.map! { |method| [method, public_send(method)] }].with_indifferent_access
486
530
  end
487
531
 
488
532
  private
489
533
 
490
- # Updates the attributes on this particular ActiveRecord object so that
491
- # if it is associated with a transaction, then the state of the AR object
492
- # will be updated to reflect the current state of the transaction
493
- #
494
- # The @transaction_state variable stores the states of the associated
495
- # transaction. This relies on the fact that a transaction can only be in
496
- # one rollback or commit (otherwise a list of states would be required)
497
- # Each AR object inside of a transaction carries that transaction's
498
- # TransactionState.
499
- #
500
- # This method checks to see if the ActiveRecord object's state reflects
501
- # the TransactionState, and rolls back or commits the ActiveRecord object
502
- # as appropriate.
503
- #
504
- # Since ActiveRecord objects can be inside multiple transactions, this
505
- # method recursively goes through the parent of the TransactionState and
506
- # checks if the ActiveRecord object reflects the state of the object.
507
- def sync_with_transaction_state
508
- update_attributes_from_transaction_state(@transaction_state, 0)
509
- end
510
-
511
- def update_attributes_from_transaction_state(transaction_state, depth)
512
- if transaction_state && transaction_state.finalized? && !has_transactional_callbacks?
513
- unless @reflects_state[depth]
514
- restore_transaction_record_state if transaction_state.rolledback?
515
- clear_transaction_record_state
516
- @reflects_state[depth] = true
517
- end
518
-
519
- if transaction_state.parent && !@reflects_state[depth+1]
520
- update_attributes_from_transaction_state(transaction_state.parent, depth+1)
521
- end
534
+ # +Array#flatten+ will call +#to_ary+ (recursively) on each of the elements of
535
+ # the array, and then rescues from the possible +NoMethodError+. If those elements are
536
+ # +ActiveRecord::Base+'s, then this triggers the various +method_missing+'s that we have,
537
+ # which significantly impacts upon performance.
538
+ #
539
+ # So we can avoid the +method_missing+ hit by explicitly defining +#to_ary+ as +nil+ here.
540
+ #
541
+ # See also https://tenderlovemaking.com/2011/06/28/til-its-ok-to-return-nil-from-to_ary.html
542
+ def to_ary
543
+ nil
522
544
  end
523
- end
524
545
 
525
- # Under Ruby 1.9, Array#flatten will call #to_ary (recursively) on each of the elements
526
- # of the array, and then rescues from the possible NoMethodError. If those elements are
527
- # ActiveRecord::Base's, then this triggers the various method_missing's that we have,
528
- # which significantly impacts upon performance.
529
- #
530
- # So we can avoid the method_missing hit by explicitly defining #to_ary as nil here.
531
- #
532
- # See also http://tenderlovemaking.com/2011/06/28/til-its-ok-to-return-nil-from-to_ary.html
533
- def to_ary # :nodoc:
534
- nil
535
- end
536
-
537
- def init_internals
538
- @aggregation_cache = {}
539
- @association_cache = {}
540
- @readonly = false
541
- @destroyed = false
542
- @marked_for_destruction = false
543
- @destroyed_by_association = nil
544
- @new_record = true
545
- @txn = nil
546
- @_start_transaction_state = {}
547
- @transaction_state = nil
548
- @reflects_state = [false]
549
- end
546
+ def init_internals
547
+ @readonly = false
548
+ @destroyed = false
549
+ @marked_for_destruction = false
550
+ @destroyed_by_association = nil
551
+ @new_record = true
552
+ @_start_transaction_state = {}
553
+ @transaction_state = nil
554
+ end
550
555
 
551
- def initialize_internals_callback
552
- end
556
+ def initialize_internals_callback
557
+ end
553
558
 
554
- # This method is needed to make protected_attributes gem easier to hook.
555
- # Remove it when we drop support to this gem.
556
- def init_attributes(attributes, options)
557
- assign_attributes(attributes)
558
- end
559
+ def thaw
560
+ if frozen?
561
+ @attributes = @attributes.dup
562
+ end
563
+ end
559
564
 
560
- def thaw
561
- if frozen?
562
- @attributes = @attributes.dup
565
+ def custom_inspect_method_defined?
566
+ self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner
563
567
  end
564
- end
565
568
  end
566
569
  end