activerecord 7.0.8.7 → 7.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (283) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +781 -1777
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +30 -30
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record/aggregations.rb +16 -13
  7. data/lib/active_record/association_relation.rb +2 -2
  8. data/lib/active_record/associations/alias_tracker.rb +31 -23
  9. data/lib/active_record/associations/association.rb +35 -12
  10. data/lib/active_record/associations/association_scope.rb +16 -9
  11. data/lib/active_record/associations/belongs_to_association.rb +40 -9
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
  13. data/lib/active_record/associations/builder/association.rb +3 -3
  14. data/lib/active_record/associations/builder/belongs_to.rb +22 -8
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
  16. data/lib/active_record/associations/builder/has_many.rb +3 -4
  17. data/lib/active_record/associations/builder/has_one.rb +3 -4
  18. data/lib/active_record/associations/builder/singular_association.rb +4 -0
  19. data/lib/active_record/associations/collection_association.rb +35 -21
  20. data/lib/active_record/associations/collection_proxy.rb +29 -11
  21. data/lib/active_record/associations/errors.rb +265 -0
  22. data/lib/active_record/associations/foreign_association.rb +10 -3
  23. data/lib/active_record/associations/has_many_association.rb +21 -14
  24. data/lib/active_record/associations/has_many_through_association.rb +17 -7
  25. data/lib/active_record/associations/has_one_association.rb +10 -3
  26. data/lib/active_record/associations/join_dependency/join_association.rb +4 -3
  27. data/lib/active_record/associations/join_dependency.rb +10 -10
  28. data/lib/active_record/associations/nested_error.rb +47 -0
  29. data/lib/active_record/associations/preloader/association.rb +33 -8
  30. data/lib/active_record/associations/preloader/branch.rb +7 -1
  31. data/lib/active_record/associations/preloader/through_association.rb +1 -3
  32. data/lib/active_record/associations/preloader.rb +13 -10
  33. data/lib/active_record/associations/singular_association.rb +7 -1
  34. data/lib/active_record/associations/through_association.rb +22 -11
  35. data/lib/active_record/associations.rb +354 -485
  36. data/lib/active_record/attribute_assignment.rb +0 -4
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
  38. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  39. data/lib/active_record/attribute_methods/dirty.rb +53 -35
  40. data/lib/active_record/attribute_methods/primary_key.rb +45 -25
  41. data/lib/active_record/attribute_methods/query.rb +28 -16
  42. data/lib/active_record/attribute_methods/read.rb +8 -7
  43. data/lib/active_record/attribute_methods/serialization.rb +131 -32
  44. data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -6
  45. data/lib/active_record/attribute_methods/write.rb +6 -6
  46. data/lib/active_record/attribute_methods.rb +153 -33
  47. data/lib/active_record/attributes.rb +96 -71
  48. data/lib/active_record/autosave_association.rb +81 -39
  49. data/lib/active_record/base.rb +11 -7
  50. data/lib/active_record/callbacks.rb +11 -25
  51. data/lib/active_record/coders/column_serializer.rb +61 -0
  52. data/lib/active_record/coders/json.rb +1 -1
  53. data/lib/active_record/coders/yaml_column.rb +70 -42
  54. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +123 -131
  55. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +4 -1
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +343 -91
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +160 -45
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +229 -64
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +72 -63
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +142 -12
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +310 -129
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +367 -75
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +539 -111
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +289 -128
  69. data/lib/active_record/connection_adapters/column.rb +9 -0
  70. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  71. data/lib/active_record/connection_adapters/mysql/database_statements.rb +26 -139
  72. data/lib/active_record/connection_adapters/mysql/quoting.rb +60 -55
  73. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +6 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
  76. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +25 -13
  77. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
  78. data/lib/active_record/connection_adapters/mysql2_adapter.rb +108 -68
  79. data/lib/active_record/connection_adapters/pool_config.rb +20 -10
  80. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +14 -3
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +100 -43
  83. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
  87. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +1 -1
  88. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
  89. data/lib/active_record/connection_adapters/postgresql/quoting.rb +65 -61
  90. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
  91. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
  92. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -2
  93. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +54 -1
  94. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +371 -64
  95. data/lib/active_record/connection_adapters/postgresql_adapter.rb +374 -203
  96. data/lib/active_record/connection_adapters/schema_cache.rb +302 -79
  97. data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
  98. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +60 -43
  99. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -45
  100. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  101. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +14 -0
  102. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
  103. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +51 -8
  104. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +298 -113
  105. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  106. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  107. data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
  108. data/lib/active_record/connection_adapters.rb +124 -1
  109. data/lib/active_record/connection_handling.rb +101 -105
  110. data/lib/active_record/core.rb +273 -178
  111. data/lib/active_record/counter_cache.rb +69 -35
  112. data/lib/active_record/database_configurations/connection_url_resolver.rb +10 -3
  113. data/lib/active_record/database_configurations/database_config.rb +26 -5
  114. data/lib/active_record/database_configurations/hash_config.rb +52 -34
  115. data/lib/active_record/database_configurations/url_config.rb +37 -12
  116. data/lib/active_record/database_configurations.rb +87 -34
  117. data/lib/active_record/delegated_type.rb +56 -27
  118. data/lib/active_record/deprecator.rb +7 -0
  119. data/lib/active_record/destroy_association_async_job.rb +3 -1
  120. data/lib/active_record/dynamic_matchers.rb +2 -2
  121. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  122. data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
  123. data/lib/active_record/encryption/config.rb +25 -1
  124. data/lib/active_record/encryption/configurable.rb +12 -19
  125. data/lib/active_record/encryption/context.rb +10 -3
  126. data/lib/active_record/encryption/contexts.rb +5 -1
  127. data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
  128. data/lib/active_record/encryption/encryptable_record.rb +46 -22
  129. data/lib/active_record/encryption/encrypted_attribute_type.rb +48 -13
  130. data/lib/active_record/encryption/encryptor.rb +35 -19
  131. data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -69
  132. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +3 -3
  133. data/lib/active_record/encryption/key_generator.rb +12 -1
  134. data/lib/active_record/encryption/key_provider.rb +1 -1
  135. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  136. data/lib/active_record/encryption/message_serializer.rb +6 -0
  137. data/lib/active_record/encryption/null_encryptor.rb +4 -0
  138. data/lib/active_record/encryption/properties.rb +3 -3
  139. data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
  140. data/lib/active_record/encryption/scheme.rb +22 -21
  141. data/lib/active_record/encryption.rb +3 -0
  142. data/lib/active_record/enum.rb +130 -28
  143. data/lib/active_record/errors.rb +154 -34
  144. data/lib/active_record/explain.rb +21 -12
  145. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  146. data/lib/active_record/fixture_set/render_context.rb +2 -0
  147. data/lib/active_record/fixture_set/table_row.rb +48 -10
  148. data/lib/active_record/fixtures.rb +167 -97
  149. data/lib/active_record/future_result.rb +47 -8
  150. data/lib/active_record/gem_version.rb +4 -4
  151. data/lib/active_record/inheritance.rb +34 -18
  152. data/lib/active_record/insert_all.rb +72 -22
  153. data/lib/active_record/integration.rb +11 -8
  154. data/lib/active_record/internal_metadata.rb +124 -20
  155. data/lib/active_record/locking/optimistic.rb +8 -7
  156. data/lib/active_record/locking/pessimistic.rb +5 -2
  157. data/lib/active_record/log_subscriber.rb +18 -22
  158. data/lib/active_record/marshalling.rb +59 -0
  159. data/lib/active_record/message_pack.rb +124 -0
  160. data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
  161. data/lib/active_record/middleware/database_selector.rb +6 -8
  162. data/lib/active_record/middleware/shard_selector.rb +3 -1
  163. data/lib/active_record/migration/command_recorder.rb +106 -8
  164. data/lib/active_record/migration/compatibility.rb +147 -5
  165. data/lib/active_record/migration/default_strategy.rb +22 -0
  166. data/lib/active_record/migration/execution_strategy.rb +19 -0
  167. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  168. data/lib/active_record/migration.rb +236 -118
  169. data/lib/active_record/model_schema.rb +90 -102
  170. data/lib/active_record/nested_attributes.rb +48 -11
  171. data/lib/active_record/normalization.rb +163 -0
  172. data/lib/active_record/persistence.rb +168 -339
  173. data/lib/active_record/promise.rb +84 -0
  174. data/lib/active_record/query_cache.rb +18 -25
  175. data/lib/active_record/query_logs.rb +96 -52
  176. data/lib/active_record/query_logs_formatter.rb +41 -0
  177. data/lib/active_record/querying.rb +35 -10
  178. data/lib/active_record/railtie.rb +131 -87
  179. data/lib/active_record/railties/controller_runtime.rb +22 -7
  180. data/lib/active_record/railties/databases.rake +147 -155
  181. data/lib/active_record/railties/job_runtime.rb +23 -0
  182. data/lib/active_record/readonly_attributes.rb +32 -5
  183. data/lib/active_record/reflection.rb +267 -69
  184. data/lib/active_record/relation/batches/batch_enumerator.rb +20 -5
  185. data/lib/active_record/relation/batches.rb +198 -63
  186. data/lib/active_record/relation/calculations.rb +270 -108
  187. data/lib/active_record/relation/delegation.rb +30 -19
  188. data/lib/active_record/relation/finder_methods.rb +97 -21
  189. data/lib/active_record/relation/merger.rb +6 -6
  190. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  191. data/lib/active_record/relation/predicate_builder/association_query_value.rb +20 -3
  192. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
  193. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  194. data/lib/active_record/relation/predicate_builder.rb +28 -16
  195. data/lib/active_record/relation/query_attribute.rb +3 -2
  196. data/lib/active_record/relation/query_methods.rb +585 -109
  197. data/lib/active_record/relation/record_fetch_warning.rb +3 -0
  198. data/lib/active_record/relation/spawn_methods.rb +5 -4
  199. data/lib/active_record/relation/where_clause.rb +15 -21
  200. data/lib/active_record/relation.rb +592 -92
  201. data/lib/active_record/result.rb +49 -48
  202. data/lib/active_record/runtime_registry.rb +63 -1
  203. data/lib/active_record/sanitization.rb +70 -25
  204. data/lib/active_record/schema.rb +8 -7
  205. data/lib/active_record/schema_dumper.rb +90 -23
  206. data/lib/active_record/schema_migration.rb +75 -24
  207. data/lib/active_record/scoping/default.rb +15 -5
  208. data/lib/active_record/scoping/named.rb +3 -2
  209. data/lib/active_record/scoping.rb +2 -1
  210. data/lib/active_record/secure_password.rb +60 -0
  211. data/lib/active_record/secure_token.rb +21 -3
  212. data/lib/active_record/signed_id.rb +33 -11
  213. data/lib/active_record/statement_cache.rb +7 -7
  214. data/lib/active_record/store.rb +8 -8
  215. data/lib/active_record/suppressor.rb +3 -1
  216. data/lib/active_record/table_metadata.rb +1 -1
  217. data/lib/active_record/tasks/database_tasks.rb +190 -118
  218. data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
  219. data/lib/active_record/tasks/postgresql_database_tasks.rb +23 -13
  220. data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
  221. data/lib/active_record/test_fixtures.rb +170 -155
  222. data/lib/active_record/testing/query_assertions.rb +121 -0
  223. data/lib/active_record/timestamp.rb +31 -17
  224. data/lib/active_record/token_for.rb +123 -0
  225. data/lib/active_record/touch_later.rb +12 -7
  226. data/lib/active_record/transaction.rb +132 -0
  227. data/lib/active_record/transactions.rb +108 -24
  228. data/lib/active_record/translation.rb +0 -2
  229. data/lib/active_record/type/adapter_specific_registry.rb +1 -8
  230. data/lib/active_record/type/internal/timezone.rb +7 -2
  231. data/lib/active_record/type/serialized.rb +1 -3
  232. data/lib/active_record/type/time.rb +4 -0
  233. data/lib/active_record/type_caster/connection.rb +4 -4
  234. data/lib/active_record/validations/absence.rb +1 -1
  235. data/lib/active_record/validations/associated.rb +9 -3
  236. data/lib/active_record/validations/numericality.rb +5 -4
  237. data/lib/active_record/validations/presence.rb +5 -28
  238. data/lib/active_record/validations/uniqueness.rb +61 -11
  239. data/lib/active_record/validations.rb +12 -5
  240. data/lib/active_record/version.rb +1 -1
  241. data/lib/active_record.rb +247 -33
  242. data/lib/arel/alias_predication.rb +1 -1
  243. data/lib/arel/collectors/bind.rb +3 -1
  244. data/lib/arel/collectors/composite.rb +7 -0
  245. data/lib/arel/collectors/sql_string.rb +1 -1
  246. data/lib/arel/collectors/substitute_binds.rb +1 -1
  247. data/lib/arel/crud.rb +2 -0
  248. data/lib/arel/delete_manager.rb +5 -0
  249. data/lib/arel/errors.rb +10 -0
  250. data/lib/arel/factory_methods.rb +4 -0
  251. data/lib/arel/nodes/binary.rb +6 -7
  252. data/lib/arel/nodes/bound_sql_literal.rb +65 -0
  253. data/lib/arel/nodes/cte.rb +36 -0
  254. data/lib/arel/nodes/delete_statement.rb +4 -2
  255. data/lib/arel/nodes/fragments.rb +35 -0
  256. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  257. data/lib/arel/nodes/leading_join.rb +8 -0
  258. data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
  259. data/lib/arel/nodes/node.rb +115 -5
  260. data/lib/arel/nodes/sql_literal.rb +13 -0
  261. data/lib/arel/nodes/table_alias.rb +4 -0
  262. data/lib/arel/nodes/update_statement.rb +4 -2
  263. data/lib/arel/nodes.rb +6 -2
  264. data/lib/arel/predications.rb +3 -1
  265. data/lib/arel/select_manager.rb +7 -3
  266. data/lib/arel/table.rb +9 -5
  267. data/lib/arel/tree_manager.rb +8 -3
  268. data/lib/arel/update_manager.rb +7 -1
  269. data/lib/arel/visitors/dot.rb +3 -0
  270. data/lib/arel/visitors/mysql.rb +17 -5
  271. data/lib/arel/visitors/postgresql.rb +1 -12
  272. data/lib/arel/visitors/sqlite.rb +25 -0
  273. data/lib/arel/visitors/to_sql.rb +114 -34
  274. data/lib/arel/visitors/visitor.rb +2 -2
  275. data/lib/arel.rb +21 -3
  276. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  277. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
  278. data/lib/rails/generators/active_record/migration.rb +3 -1
  279. data/lib/rails/generators/active_record/model/USAGE +113 -0
  280. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  281. metadata +56 -17
  282. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  283. data/lib/active_record/null_relation.rb +0 -63
@@ -1,29 +1,50 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/enumerable"
4
- require "active_support/core_ext/hash/indifferent_access"
5
- require "active_support/core_ext/string/filters"
4
+ require "active_support/core_ext/module/delegation"
6
5
  require "active_support/parameter_filter"
7
6
  require "concurrent/map"
8
7
 
9
8
  module ActiveRecord
9
+ # = Active Record \Core
10
10
  module Core
11
11
  extend ActiveSupport::Concern
12
+ include ActiveModel::Access
12
13
 
13
14
  included do
14
15
  ##
15
16
  # :singleton-method:
16
17
  #
17
- # Accepts a logger conforming to the interface of Log4r which is then
18
- # passed on to any new database connections made and which can be
19
- # retrieved on both a class and instance level by calling +logger+.
18
+ # Accepts a logger conforming to the interface of Log4r or the default
19
+ # Ruby +Logger+ class, which is then passed on to any new database
20
+ # connections made. You can retrieve this logger by calling +logger+ on
21
+ # either an Active Record model class or an Active Record model instance.
20
22
  class_attribute :logger, instance_writer: false
21
23
 
24
+ class_attribute :_destroy_association_async_job, instance_accessor: false, default: "ActiveRecord::DestroyAssociationAsyncJob"
25
+
26
+ # The job class used to destroy associations in the background.
27
+ def self.destroy_association_async_job
28
+ if _destroy_association_async_job.is_a?(String)
29
+ self._destroy_association_async_job = _destroy_association_async_job.constantize
30
+ end
31
+ _destroy_association_async_job
32
+ rescue NameError => error
33
+ raise NameError, "Unable to load destroy_association_async_job: #{error.message}"
34
+ end
35
+
36
+ singleton_class.alias_method :destroy_association_async_job=, :_destroy_association_async_job=
37
+ delegate :destroy_association_async_job, to: :class
38
+
22
39
  ##
23
40
  # :singleton-method:
24
41
  #
25
- # Specifies the job used to destroy associations in the background
26
- class_attribute :destroy_association_async_job, instance_writer: false, instance_predicate: false, default: false
42
+ # Specifies the maximum number of records that will be destroyed in a
43
+ # single background job by the <tt>dependent: :destroy_async</tt>
44
+ # association option. When +nil+ (default), all dependent records will be
45
+ # destroyed in a single background job. If specified, the records to be
46
+ # destroyed will be split into multiple background jobs.
47
+ class_attribute :destroy_association_async_batch_size, instance_writer: false, instance_predicate: false, default: nil
27
48
 
28
49
  ##
29
50
  # Contains the database configuration - as is typically stored in config/database.yml -
@@ -33,26 +54,26 @@ module ActiveRecord
33
54
  #
34
55
  # development:
35
56
  # adapter: sqlite3
36
- # database: db/development.sqlite3
57
+ # database: storage/development.sqlite3
37
58
  #
38
59
  # production:
39
60
  # adapter: sqlite3
40
- # database: db/production.sqlite3
61
+ # database: storage/production.sqlite3
41
62
  #
42
63
  # ...would result in ActiveRecord::Base.configurations to look like this:
43
64
  #
44
65
  # #<ActiveRecord::DatabaseConfigurations:0x00007fd1acbdf800 @configurations=[
45
66
  # #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",
46
- # @name="primary", @config={adapter: "sqlite3", database: "db/development.sqlite3"}>,
67
+ # @name="primary", @config={adapter: "sqlite3", database: "storage/development.sqlite3"}>,
47
68
  # #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbdea90 @env_name="production",
48
- # @name="primary", @config={adapter: "sqlite3", database: "db/production.sqlite3"}>
69
+ # @name="primary", @config={adapter: "sqlite3", database: "storage/production.sqlite3"}>
49
70
  # ]>
50
71
  def self.configurations=(config)
51
72
  @@configurations = ActiveRecord::DatabaseConfigurations.new(config)
52
73
  end
53
74
  self.configurations = {}
54
75
 
55
- # Returns fully resolved ActiveRecord::DatabaseConfigurations object
76
+ # Returns a fully resolved ActiveRecord::DatabaseConfigurations object.
56
77
  def self.configurations
57
78
  @@configurations
58
79
  end
@@ -71,6 +92,8 @@ module ActiveRecord
71
92
 
72
93
  class_attribute :has_many_inversing, instance_accessor: false, default: false
73
94
 
95
+ class_attribute :run_commit_callbacks_on_first_saved_instances_in_transaction, instance_accessor: false, default: true
96
+
74
97
  class_attribute :default_connection_handler, instance_writer: false
75
98
 
76
99
  class_attribute :default_role, instance_writer: false
@@ -79,6 +102,21 @@ module ActiveRecord
79
102
 
80
103
  class_attribute :shard_selector, instance_accessor: false, default: nil
81
104
 
105
+ ##
106
+ # :singleton-method:
107
+ #
108
+ # Specifies the attributes that will be included in the output of the
109
+ # #inspect method:
110
+ #
111
+ # Post.attributes_for_inspect = [:id, :title]
112
+ # Post.first.inspect #=> "#<Post id: 1, title: "Hello, World!">"
113
+ #
114
+ # When set to `:all` inspect will list all the record's attributes:
115
+ #
116
+ # Post.attributes_for_inspect = :all
117
+ # Post.first.inspect #=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"
118
+ class_attribute :attributes_for_inspect, instance_accessor: false, default: :all
119
+
82
120
  def self.application_record_class? # :nodoc:
83
121
  if ActiveRecord.application_record_class
84
122
  self == ActiveRecord.application_record_class
@@ -99,33 +137,6 @@ module ActiveRecord
99
137
  ActiveSupport::IsolatedExecutionState[:active_record_connection_handler] = handler
100
138
  end
101
139
 
102
- def self.connection_handlers
103
- if ActiveRecord.legacy_connection_handling
104
- else
105
- raise NotImplementedError, "The new connection handling does not support accessing multiple connection handlers."
106
- end
107
-
108
- @@connection_handlers ||= {}
109
- end
110
-
111
- def self.connection_handlers=(handlers)
112
- if ActiveRecord.legacy_connection_handling
113
- ActiveSupport::Deprecation.warn(<<~MSG)
114
- Using legacy connection handling is deprecated. Please set
115
- `legacy_connection_handling` to `false` in your application.
116
-
117
- The new connection handling does not support `connection_handlers`
118
- getter and setter.
119
-
120
- Read more about how to migrate at: https://guides.rubyonrails.org/active_record_multiple_databases.html#migrate-to-the-new-connection-handling
121
- MSG
122
- else
123
- raise NotImplementedError, "The new connection handling does not support multiple connection handlers."
124
- end
125
-
126
- @@connection_handlers = handlers
127
- end
128
-
129
140
  def self.asynchronous_queries_session # :nodoc:
130
141
  asynchronous_queries_tracker.current_session
131
142
  end
@@ -145,16 +156,12 @@ module ActiveRecord
145
156
  # ActiveRecord::Base.current_role #=> :reading
146
157
  # end
147
158
  def self.current_role
148
- if ActiveRecord.legacy_connection_handling
149
- connection_handlers.key(connection_handler) || default_role
150
- else
151
- connected_to_stack.reverse_each do |hash|
152
- return hash[:role] if hash[:role] && hash[:klasses].include?(Base)
153
- return hash[:role] if hash[:role] && hash[:klasses].include?(connection_class_for_self)
154
- end
155
-
156
- default_role
159
+ connected_to_stack.reverse_each do |hash|
160
+ return hash[:role] if hash[:role] && hash[:klasses].include?(Base)
161
+ return hash[:role] if hash[:role] && hash[:klasses].include?(connection_class_for_self)
157
162
  end
163
+
164
+ default_role
158
165
  end
159
166
 
160
167
  # Returns the symbol representing the current connected shard.
@@ -186,16 +193,12 @@ module ActiveRecord
186
193
  # ActiveRecord::Base.current_preventing_writes #=> false
187
194
  # end
188
195
  def self.current_preventing_writes
189
- if ActiveRecord.legacy_connection_handling
190
- connection_handler.prevent_writes
191
- else
192
- connected_to_stack.reverse_each do |hash|
193
- return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base)
194
- return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(connection_class_for_self)
195
- end
196
-
197
- false
196
+ connected_to_stack.reverse_each do |hash|
197
+ return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base)
198
+ return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(connection_class_for_self)
198
199
  end
200
+
201
+ false
199
202
  end
200
203
 
201
204
  def self.connected_to_stack # :nodoc:
@@ -252,19 +255,6 @@ module ActiveRecord
252
255
  @find_by_statement_cache = { true => Concurrent::Map.new, false => Concurrent::Map.new }
253
256
  end
254
257
 
255
- def inherited(child_class) # :nodoc:
256
- # initialize cache at class definition for thread safety
257
- child_class.initialize_find_by_cache
258
- unless child_class.base_class?
259
- klass = self
260
- until klass.base_class?
261
- klass.initialize_find_by_cache
262
- klass = klass.superclass
263
- end
264
- end
265
- super
266
- end
267
-
268
258
  def find(*ids) # :nodoc:
269
259
  # We don't have cache keys for this stuff yet
270
260
  return super unless ids.length == 1
@@ -274,14 +264,8 @@ module ActiveRecord
274
264
 
275
265
  return super if StatementCache.unsupported_value?(id)
276
266
 
277
- key = primary_key
278
-
279
- statement = cached_find_by_statement(key) { |params|
280
- where(key => params.bind).limit(1)
281
- }
282
-
283
- statement.execute([id], connection).first ||
284
- raise(RecordNotFound.new("Couldn't find #{name} with '#{key}'=#{id}", name, key, id))
267
+ cached_find_by([primary_key], [id]) ||
268
+ raise(RecordNotFound.new("Couldn't find #{name} with '#{primary_key}'=#{id.inspect}", name, primary_key, id))
285
269
  end
286
270
 
287
271
  def find_by(*args) # :nodoc:
@@ -303,58 +287,38 @@ module ActiveRecord
303
287
  elsif reflection.belongs_to? && !reflection.polymorphic?
304
288
  key = reflection.join_foreign_key
305
289
  pkey = reflection.join_primary_key
306
- value = value.public_send(pkey) if value.respond_to?(pkey)
290
+
291
+ if pkey.is_a?(Array)
292
+ if pkey.all? { |attribute| value.respond_to?(attribute) }
293
+ value = pkey.map do |attribute|
294
+ if attribute == "id"
295
+ value.id_value
296
+ else
297
+ value.public_send(attribute)
298
+ end
299
+ end
300
+ composite_primary_key = true
301
+ end
302
+ else
303
+ value = value.public_send(pkey) if value.respond_to?(pkey)
304
+ end
307
305
  end
308
306
 
309
- if !columns_hash.key?(key) || StatementCache.unsupported_value?(value)
307
+ if !composite_primary_key &&
308
+ (!columns_hash.key?(key) || StatementCache.unsupported_value?(value))
310
309
  return super
311
310
  end
312
311
 
313
312
  h[key] = value
314
313
  end
315
314
 
316
- keys = hash.keys
317
- statement = cached_find_by_statement(keys) { |params|
318
- wheres = keys.index_with { params.bind }
319
- where(wheres).limit(1)
320
- }
321
-
322
- begin
323
- statement.execute(hash.values, connection).first
324
- rescue TypeError
325
- raise ActiveRecord::StatementInvalid
326
- end
315
+ cached_find_by(hash.keys, hash.values)
327
316
  end
328
317
 
329
318
  def find_by!(*args) # :nodoc:
330
319
  find_by(*args) || where(*args).raise_record_not_found_exception!
331
320
  end
332
321
 
333
- %w(
334
- reading_role writing_role legacy_connection_handling default_timezone index_nested_attribute_errors
335
- verbose_query_logs queues warn_on_records_fetched_greater_than maintain_test_schema
336
- application_record_class action_on_strict_loading_violation schema_format error_on_ignored_order
337
- timestamped_migrations dump_schema_after_migration dump_schemas suppress_multiple_database_warning
338
- ).each do |attr|
339
- module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
340
- def #{attr}
341
- ActiveSupport::Deprecation.warn(<<~MSG)
342
- ActiveRecord::Base.#{attr} is deprecated and will be removed in Rails 7.1.
343
- Use `ActiveRecord.#{attr}` instead.
344
- MSG
345
- ActiveRecord.#{attr}
346
- end
347
-
348
- def #{attr}=(value)
349
- ActiveSupport::Deprecation.warn(<<~MSG)
350
- ActiveRecord::Base.#{attr}= is deprecated and will be removed in Rails 7.1.
351
- Use `ActiveRecord.#{attr}=` instead.
352
- MSG
353
- ActiveRecord.#{attr} = value
354
- end
355
- RUBY
356
- end
357
-
358
322
  def initialize_generated_modules # :nodoc:
359
323
  generated_association_methods
360
324
  end
@@ -371,10 +335,10 @@ module ActiveRecord
371
335
 
372
336
  # Returns columns which shouldn't be exposed while calling +#inspect+.
373
337
  def filter_attributes
374
- if defined?(@filter_attributes)
375
- @filter_attributes
376
- else
338
+ if @filter_attributes.nil?
377
339
  superclass.filter_attributes
340
+ else
341
+ @filter_attributes
378
342
  end
379
343
  end
380
344
 
@@ -385,24 +349,24 @@ module ActiveRecord
385
349
  end
386
350
 
387
351
  def inspection_filter # :nodoc:
388
- if defined?(@filter_attributes)
352
+ if @filter_attributes.nil?
353
+ superclass.inspection_filter
354
+ else
389
355
  @inspection_filter ||= begin
390
356
  mask = InspectionMask.new(ActiveSupport::ParameterFilter::FILTERED)
391
357
  ActiveSupport::ParameterFilter.new(@filter_attributes, mask: mask)
392
358
  end
393
- else
394
- superclass.inspection_filter
395
359
  end
396
360
  end
397
361
 
398
362
  # Returns a string like 'Post(id:integer, title:string, body:text)'
399
363
  def inspect # :nodoc:
400
- if self == Base
364
+ if self == Base || singleton_class?
401
365
  super
402
366
  elsif abstract_class?
403
367
  "#{super}(abstract)"
404
- elsif !connected?
405
- "#{super} (call '#{super}.connection' to establish a connection)"
368
+ elsif !schema_loaded? && !connected?
369
+ "#{super} (call '#{super}.load_schema' to load schema informations)"
406
370
  elsif table_exists?
407
371
  attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } * ", "
408
372
  "#{super}(#{attr_list})"
@@ -411,12 +375,7 @@ module ActiveRecord
411
375
  end
412
376
  end
413
377
 
414
- # Override the default class equality method to provide support for decorated models.
415
- def ===(object) # :nodoc:
416
- object.is_a?(self)
417
- end
418
-
419
- # Returns an instance of <tt>Arel::Table</tt> loaded with the current table name.
378
+ # Returns an instance of +Arel::Table+ loaded with the current table name.
420
379
  def arel_table # :nodoc:
421
380
  @arel_table ||= Arel::Table.new(table_name, klass: self)
422
381
  end
@@ -429,12 +388,34 @@ module ActiveRecord
429
388
  TypeCaster::Map.new(self)
430
389
  end
431
390
 
432
- def cached_find_by_statement(key, &block) # :nodoc:
391
+ def cached_find_by_statement(connection, key, &block) # :nodoc:
433
392
  cache = @find_by_statement_cache[connection.prepared_statements]
434
393
  cache.compute_if_absent(key) { StatementCache.create(connection, &block) }
435
394
  end
436
395
 
437
396
  private
397
+ def inherited(subclass)
398
+ super
399
+
400
+ # initialize cache at class definition for thread safety
401
+ subclass.initialize_find_by_cache
402
+ unless subclass.base_class?
403
+ klass = self
404
+ until klass.base_class?
405
+ klass.initialize_find_by_cache
406
+ klass = klass.superclass
407
+ end
408
+ end
409
+
410
+ subclass.class_eval do
411
+ @arel_table = nil
412
+ @predicate_builder = nil
413
+ @inspection_filter = nil
414
+ @filter_attributes ||= nil
415
+ @generated_association_methods ||= nil
416
+ end
417
+ end
418
+
438
419
  def relation
439
420
  relation = Relation.create(self)
440
421
 
@@ -448,6 +429,27 @@ module ActiveRecord
448
429
  def table_metadata
449
430
  TableMetadata.new(self, arel_table)
450
431
  end
432
+
433
+ def cached_find_by(keys, values)
434
+ with_connection do |connection|
435
+ statement = cached_find_by_statement(connection, keys) { |params|
436
+ wheres = keys.index_with do |key|
437
+ if key.is_a?(Array)
438
+ [key.map { params.bind }]
439
+ else
440
+ params.bind
441
+ end
442
+ end
443
+ where(wheres).limit(1)
444
+ }
445
+
446
+ begin
447
+ statement.execute(values.flatten, connection, allow_retry: true).first
448
+ rescue TypeError
449
+ raise ActiveRecord::StatementInvalid
450
+ end
451
+ end
452
+ end
451
453
  end
452
454
 
453
455
  # New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
@@ -455,7 +457,7 @@ module ActiveRecord
455
457
  # In both instances, valid attribute keys are determined by the column names of the associated table --
456
458
  # hence you can't have attributes that aren't part of the table columns.
457
459
  #
458
- # ==== Example:
460
+ # ==== Example
459
461
  # # Instantiates a single new object
460
462
  # User.new(first_name: 'Jamie')
461
463
  def initialize(attributes = nil)
@@ -465,7 +467,7 @@ module ActiveRecord
465
467
  init_internals
466
468
  initialize_internals_callback
467
469
 
468
- assign_attributes(attributes) if attributes
470
+ super
469
471
 
470
472
  yield self if block_given?
471
473
  _run_initialize_callbacks
@@ -533,12 +535,17 @@ module ActiveRecord
533
535
  # only, not its associations. The extent of a "deep" copy is application
534
536
  # specific and is therefore left to the application to implement according
535
537
  # to its need.
536
- # The dup method does not preserve the timestamps (created|updated)_(at|on).
538
+ # The dup method does not preserve the timestamps (created|updated)_(at|on)
539
+ # and locking column.
537
540
 
538
541
  ##
539
542
  def initialize_dup(other) # :nodoc:
540
543
  @attributes = @attributes.deep_dup
541
- @attributes.reset(@primary_key)
544
+ if self.class.composite_primary_key?
545
+ @primary_key.each { |key| @attributes.reset(key) }
546
+ else
547
+ @attributes.reset(@primary_key)
548
+ end
542
549
 
543
550
  _run_initialize_callbacks
544
551
 
@@ -568,6 +575,35 @@ module ActiveRecord
568
575
  coder["active_record_yaml_version"] = 2
569
576
  end
570
577
 
578
+ ##
579
+ # :method: slice
580
+ #
581
+ # :call-seq: slice(*methods)
582
+ #
583
+ # Returns a hash of the given methods with their names as keys and returned
584
+ # values as values.
585
+ #
586
+ # topic = Topic.new(title: "Budget", author_name: "Jason")
587
+ # topic.slice(:title, :author_name)
588
+ # # => { "title" => "Budget", "author_name" => "Jason" }
589
+ #
590
+ #--
591
+ # Implemented by ActiveModel::Access#slice.
592
+
593
+ ##
594
+ # :method: values_at
595
+ #
596
+ # :call-seq: values_at(*methods)
597
+ #
598
+ # Returns an array of the values returned by the given methods.
599
+ #
600
+ # topic = Topic.new(title: "Budget", author_name: "Jason")
601
+ # topic.values_at(:title, :author_name)
602
+ # # => ["Budget", "Jason"]
603
+ #
604
+ #--
605
+ # Implemented by ActiveModel::Access#values_at.
606
+
571
607
  # Returns true if +comparison_object+ is the same exact object, or +comparison_object+
572
608
  # is of the same type and +self+ has an ID and it is equal to +comparison_object.id+.
573
609
  #
@@ -580,7 +616,7 @@ module ActiveRecord
580
616
  def ==(comparison_object)
581
617
  super ||
582
618
  comparison_object.instance_of?(self.class) &&
583
- !id.nil? &&
619
+ primary_key_values_present? &&
584
620
  comparison_object.id == id
585
621
  end
586
622
  alias :eql? :==
@@ -590,7 +626,7 @@ module ActiveRecord
590
626
  def hash
591
627
  id = self.id
592
628
 
593
- if id
629
+ if primary_key_values_present?
594
630
  self.class.hash ^ id.hash
595
631
  else
596
632
  super
@@ -640,27 +676,37 @@ module ActiveRecord
640
676
  # Sets the record to strict_loading mode. This will raise an error
641
677
  # if the record tries to lazily load an association.
642
678
  #
679
+ # NOTE: Strict loading is disabled during validation in order to let the record validate its association.
680
+ #
643
681
  # user = User.first
644
682
  # user.strict_loading! # => true
645
- # user.comments
646
- # => ActiveRecord::StrictLoadingViolationError
683
+ # user.address.city
684
+ # # => ActiveRecord::StrictLoadingViolationError
685
+ # user.comments.to_a
686
+ # # => ActiveRecord::StrictLoadingViolationError
647
687
  #
648
- # === Parameters:
688
+ # ==== Parameters
649
689
  #
650
- # * value - Boolean specifying whether to enable or disable strict loading.
651
- # * mode - Symbol specifying strict loading mode. Defaults to :all. Using
652
- # :n_plus_one_only mode will only raise an error if an association
653
- # that will lead to an n plus one query is lazily loaded.
690
+ # * +value+ - Boolean specifying whether to enable or disable strict loading.
691
+ # * <tt>:mode</tt> - Symbol specifying strict loading mode. Defaults to :all. Using
692
+ # :n_plus_one_only mode will only raise an error if an association that
693
+ # will lead to an n plus one query is lazily loaded.
654
694
  #
655
- # === Example:
695
+ # ==== Examples
656
696
  #
657
697
  # user = User.first
658
698
  # user.strict_loading!(false) # => false
659
- # user.comments
660
- # => #<ActiveRecord::Associations::CollectionProxy>
699
+ # user.address.city # => "Tatooine"
700
+ # user.comments.to_a # => [#<Comment:0x00...]
701
+ #
702
+ # user.strict_loading!(mode: :n_plus_one_only)
703
+ # user.address.city # => "Tatooine"
704
+ # user.comments.to_a # => [#<Comment:0x00...]
705
+ # user.comments.first.ratings.to_a
706
+ # # => ActiveRecord::StrictLoadingViolationError
661
707
  def strict_loading!(value = true, mode: :all)
662
708
  unless [:all, :n_plus_one_only].include?(mode)
663
- raise ArgumentError, "The :mode option must be one of [:all, :n_plus_one_only]."
709
+ raise ArgumentError, "The :mode option must be one of [:all, :n_plus_one_only] but #{mode.inspect} was provided."
664
710
  end
665
711
 
666
712
  @strict_loading_mode = mode
@@ -674,7 +720,34 @@ module ActiveRecord
674
720
  @strict_loading_mode == :n_plus_one_only
675
721
  end
676
722
 
677
- # Marks this record as read only.
723
+ # Returns +true+ if the record uses strict_loading with +:all+ mode enabled.
724
+ def strict_loading_all?
725
+ @strict_loading_mode == :all
726
+ end
727
+
728
+ # Prevents records from being written to the database:
729
+ #
730
+ # customer = Customer.new
731
+ # customer.readonly!
732
+ # customer.save # raises ActiveRecord::ReadOnlyRecord
733
+ #
734
+ # customer = Customer.first
735
+ # customer.readonly!
736
+ # customer.update(name: 'New Name') # raises ActiveRecord::ReadOnlyRecord
737
+ #
738
+ # Read-only records cannot be deleted from the database either:
739
+ #
740
+ # customer = Customer.first
741
+ # customer.readonly!
742
+ # customer.destroy # raises ActiveRecord::ReadOnlyRecord
743
+ #
744
+ # Please, note that the objects themselves are still mutable in memory:
745
+ #
746
+ # customer = Customer.new
747
+ # customer.readonly!
748
+ # customer.name = 'New Name' # OK
749
+ #
750
+ # but you won't be able to persist the changes.
678
751
  def readonly!
679
752
  @readonly = true
680
753
  end
@@ -683,21 +756,28 @@ module ActiveRecord
683
756
  self.class.connection_handler
684
757
  end
685
758
 
686
- # Returns the contents of the record as a nicely formatted string.
759
+ # Returns the attributes of the record as a nicely formatted string.
760
+ #
761
+ # Post.first.inspect
762
+ # #=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"
763
+ #
764
+ # The attributes can be limited by setting <tt>.attributes_for_inspect</tt>.
765
+ #
766
+ # Post.attributes_for_inspect = [:id, :title]
767
+ # Post.first.inspect
768
+ # #=> "#<Post id: 1, title: "Hello, World!">"
687
769
  def inspect
688
- # We check defined?(@attributes) not to issue warnings if the object is
689
- # allocated but not initialized.
690
- inspection = if defined?(@attributes) && @attributes
691
- self.class.attribute_names.filter_map do |name|
692
- if _has_attribute?(name)
693
- "#{name}: #{attribute_for_inspect(name)}"
694
- end
695
- end.join(", ")
696
- else
697
- "not initialized"
698
- end
770
+ inspect_with_attributes(attributes_for_inspect)
771
+ end
699
772
 
700
- "#<#{self.class} #{inspection}>"
773
+ # Returns all attributes of the record as a nicely formatted string,
774
+ # ignoring <tt>.attributes_for_inspect</tt>.
775
+ #
776
+ # Post.first.full_inspect
777
+ # #=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"
778
+ #
779
+ def full_inspect
780
+ inspect_with_attributes(all_attributes_for_inspect)
701
781
  end
702
782
 
703
783
  # Takes a PP and prettily prints this record to it, allowing you to get a nice result from <tt>pp record</tt>
@@ -705,17 +785,17 @@ module ActiveRecord
705
785
  def pretty_print(pp)
706
786
  return super if custom_inspect_method_defined?
707
787
  pp.object_address_group(self) do
708
- if defined?(@attributes) && @attributes
709
- attr_names = self.class.attribute_names.select { |name| _has_attribute?(name) }
788
+ if @attributes
789
+ attr_names = attributes_for_inspect.select { |name| _has_attribute?(name.to_s) }
710
790
  pp.seplist(attr_names, proc { pp.text "," }) do |attr_name|
791
+ attr_name = attr_name.to_s
711
792
  pp.breakable " "
712
793
  pp.group(1) do
713
794
  pp.text attr_name
714
795
  pp.text ":"
715
796
  pp.breakable
716
- value = _read_attribute(attr_name)
717
- value = inspection_filter.filter_param(attr_name, value) unless value.nil?
718
- pp.pp value
797
+ value = attribute_for_inspect(attr_name)
798
+ pp.text value
719
799
  end
720
800
  end
721
801
  else
@@ -725,16 +805,6 @@ module ActiveRecord
725
805
  end
726
806
  end
727
807
 
728
- # Returns a hash of the given methods with their names as keys and returned values as values.
729
- def slice(*methods)
730
- methods.flatten.index_with { |method| public_send(method) }.with_indifferent_access
731
- end
732
-
733
- # Returns an array of the values returned by the given methods.
734
- def values_at(*methods)
735
- methods.flatten.map! { |method| public_send(method) }
736
- end
737
-
738
808
  private
739
809
  # +Array#flatten+ will call +#to_ary+ (recursively) on each of the elements of
740
810
  # the array, and then rescues from the possible +NoMethodError+. If those elements are
@@ -782,5 +852,30 @@ module ActiveRecord
782
852
  def inspection_filter
783
853
  self.class.inspection_filter
784
854
  end
855
+
856
+ def inspect_with_attributes(attributes_to_list)
857
+ inspection = if @attributes
858
+ attributes_to_list.filter_map do |name|
859
+ name = name.to_s
860
+ if _has_attribute?(name)
861
+ "#{name}: #{attribute_for_inspect(name)}"
862
+ end
863
+ end.join(", ")
864
+ else
865
+ "not initialized"
866
+ end
867
+
868
+ "#<#{self.class} #{inspection}>"
869
+ end
870
+
871
+ def attributes_for_inspect
872
+ self.class.attributes_for_inspect == :all ? all_attributes_for_inspect : self.class.attributes_for_inspect
873
+ end
874
+
875
+ def all_attributes_for_inspect
876
+ return [] unless @attributes
877
+
878
+ attribute_names
879
+ end
785
880
  end
786
881
  end