activerecord 5.2.4.4 → 6.0.3.4

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 (292) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +777 -552
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +5 -3
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record.rb +10 -2
  7. data/lib/active_record/advisory_lock_base.rb +18 -0
  8. data/lib/active_record/aggregations.rb +4 -3
  9. data/lib/active_record/association_relation.rb +10 -8
  10. data/lib/active_record/associations.rb +21 -16
  11. data/lib/active_record/associations/alias_tracker.rb +0 -1
  12. data/lib/active_record/associations/association.rb +56 -19
  13. data/lib/active_record/associations/association_scope.rb +4 -6
  14. data/lib/active_record/associations/belongs_to_association.rb +36 -42
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
  16. data/lib/active_record/associations/builder/association.rb +14 -18
  17. data/lib/active_record/associations/builder/belongs_to.rb +19 -52
  18. data/lib/active_record/associations/builder/collection_association.rb +3 -13
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -40
  20. data/lib/active_record/associations/builder/has_many.rb +2 -0
  21. data/lib/active_record/associations/builder/has_one.rb +35 -1
  22. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  23. data/lib/active_record/associations/collection_association.rb +12 -23
  24. data/lib/active_record/associations/collection_proxy.rb +13 -17
  25. data/lib/active_record/associations/foreign_association.rb +7 -0
  26. data/lib/active_record/associations/has_many_association.rb +2 -11
  27. data/lib/active_record/associations/has_many_through_association.rb +14 -14
  28. data/lib/active_record/associations/has_one_association.rb +28 -30
  29. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  30. data/lib/active_record/associations/join_dependency.rb +37 -28
  31. data/lib/active_record/associations/join_dependency/join_association.rb +9 -10
  32. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  33. data/lib/active_record/associations/preloader.rb +39 -32
  34. data/lib/active_record/associations/preloader/association.rb +38 -36
  35. data/lib/active_record/associations/preloader/through_association.rb +48 -39
  36. data/lib/active_record/associations/singular_association.rb +2 -16
  37. data/lib/active_record/attribute_assignment.rb +7 -11
  38. data/lib/active_record/attribute_decorators.rb +0 -2
  39. data/lib/active_record/attribute_methods.rb +28 -100
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -2
  41. data/lib/active_record/attribute_methods/dirty.rb +111 -40
  42. data/lib/active_record/attribute_methods/primary_key.rb +15 -24
  43. data/lib/active_record/attribute_methods/query.rb +2 -3
  44. data/lib/active_record/attribute_methods/read.rb +15 -54
  45. data/lib/active_record/attribute_methods/serialization.rb +1 -2
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -3
  47. data/lib/active_record/attribute_methods/write.rb +17 -25
  48. data/lib/active_record/attributes.rb +13 -1
  49. data/lib/active_record/autosave_association.rb +3 -5
  50. data/lib/active_record/base.rb +2 -3
  51. data/lib/active_record/callbacks.rb +6 -21
  52. data/lib/active_record/coders/yaml_column.rb +0 -1
  53. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +103 -18
  54. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
  55. data/lib/active_record/connection_adapters/abstract/database_statements.rb +102 -124
  56. data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -9
  57. data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
  58. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +20 -14
  59. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +100 -72
  60. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
  61. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +175 -79
  62. data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -57
  63. data/lib/active_record/connection_adapters/abstract_adapter.rb +191 -43
  64. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +142 -215
  65. data/lib/active_record/connection_adapters/column.rb +17 -13
  66. data/lib/active_record/connection_adapters/connection_specification.rb +54 -45
  67. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
  68. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  69. data/lib/active_record/connection_adapters/mysql/database_statements.rb +70 -14
  70. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +0 -1
  71. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  72. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +4 -6
  73. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
  74. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
  75. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +132 -16
  76. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  77. data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -10
  78. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
  79. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +26 -1
  80. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  81. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  82. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  83. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
  84. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  91. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
  92. data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
  93. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  94. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -3
  95. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  96. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  97. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +63 -75
  98. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
  99. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  100. data/lib/active_record/connection_adapters/postgresql_adapter.rb +168 -75
  101. data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
  102. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  103. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +119 -0
  104. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
  105. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -12
  106. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +135 -146
  107. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  108. data/lib/active_record/connection_handling.rb +139 -26
  109. data/lib/active_record/core.rb +103 -61
  110. data/lib/active_record/counter_cache.rb +8 -30
  111. data/lib/active_record/database_configurations.rb +233 -0
  112. data/lib/active_record/database_configurations/database_config.rb +37 -0
  113. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  114. data/lib/active_record/database_configurations/url_config.rb +78 -0
  115. data/lib/active_record/dynamic_matchers.rb +3 -4
  116. data/lib/active_record/enum.rb +37 -7
  117. data/lib/active_record/errors.rb +15 -7
  118. data/lib/active_record/explain.rb +1 -2
  119. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  120. data/lib/active_record/fixture_set/render_context.rb +17 -0
  121. data/lib/active_record/fixture_set/table_row.rb +152 -0
  122. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  123. data/lib/active_record/fixtures.rb +144 -474
  124. data/lib/active_record/gem_version.rb +3 -3
  125. data/lib/active_record/inheritance.rb +13 -6
  126. data/lib/active_record/insert_all.rb +179 -0
  127. data/lib/active_record/integration.rb +68 -16
  128. data/lib/active_record/internal_metadata.rb +11 -3
  129. data/lib/active_record/locking/optimistic.rb +5 -7
  130. data/lib/active_record/locking/pessimistic.rb +3 -3
  131. data/lib/active_record/log_subscriber.rb +8 -27
  132. data/lib/active_record/middleware/database_selector.rb +74 -0
  133. data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
  134. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  135. data/lib/active_record/migration.rb +104 -85
  136. data/lib/active_record/migration/command_recorder.rb +54 -22
  137. data/lib/active_record/migration/compatibility.rb +79 -52
  138. data/lib/active_record/migration/join_table.rb +0 -1
  139. data/lib/active_record/model_schema.rb +33 -11
  140. data/lib/active_record/nested_attributes.rb +2 -4
  141. data/lib/active_record/no_touching.rb +9 -2
  142. data/lib/active_record/null_relation.rb +0 -1
  143. data/lib/active_record/persistence.rb +232 -29
  144. data/lib/active_record/query_cache.rb +11 -4
  145. data/lib/active_record/querying.rb +33 -21
  146. data/lib/active_record/railtie.rb +80 -43
  147. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  148. data/lib/active_record/railties/controller_runtime.rb +30 -35
  149. data/lib/active_record/railties/databases.rake +199 -46
  150. data/lib/active_record/reflection.rb +40 -38
  151. data/lib/active_record/relation.rb +322 -80
  152. data/lib/active_record/relation/batches.rb +13 -11
  153. data/lib/active_record/relation/calculations.rb +54 -48
  154. data/lib/active_record/relation/delegation.rb +33 -49
  155. data/lib/active_record/relation/finder_methods.rb +23 -28
  156. data/lib/active_record/relation/from_clause.rb +4 -0
  157. data/lib/active_record/relation/merger.rb +11 -21
  158. data/lib/active_record/relation/predicate_builder.rb +5 -11
  159. data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
  160. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
  161. data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
  162. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  163. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
  164. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  165. data/lib/active_record/relation/query_attribute.rb +13 -8
  166. data/lib/active_record/relation/query_methods.rb +221 -70
  167. data/lib/active_record/relation/spawn_methods.rb +1 -2
  168. data/lib/active_record/relation/where_clause.rb +14 -11
  169. data/lib/active_record/relation/where_clause_factory.rb +1 -2
  170. data/lib/active_record/result.rb +30 -12
  171. data/lib/active_record/sanitization.rb +32 -40
  172. data/lib/active_record/schema.rb +2 -11
  173. data/lib/active_record/schema_dumper.rb +22 -7
  174. data/lib/active_record/schema_migration.rb +6 -2
  175. data/lib/active_record/scoping.rb +8 -9
  176. data/lib/active_record/scoping/default.rb +4 -6
  177. data/lib/active_record/scoping/named.rb +21 -17
  178. data/lib/active_record/statement_cache.rb +30 -3
  179. data/lib/active_record/store.rb +87 -8
  180. data/lib/active_record/suppressor.rb +2 -2
  181. data/lib/active_record/table_metadata.rb +23 -15
  182. data/lib/active_record/tasks/database_tasks.rb +194 -25
  183. data/lib/active_record/tasks/mysql_database_tasks.rb +5 -6
  184. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -8
  185. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -9
  186. data/lib/active_record/test_databases.rb +23 -0
  187. data/lib/active_record/test_fixtures.rb +225 -0
  188. data/lib/active_record/timestamp.rb +39 -26
  189. data/lib/active_record/touch_later.rb +5 -4
  190. data/lib/active_record/transactions.rb +64 -73
  191. data/lib/active_record/translation.rb +1 -1
  192. data/lib/active_record/type.rb +3 -5
  193. data/lib/active_record/type/adapter_specific_registry.rb +3 -13
  194. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  195. data/lib/active_record/type/serialized.rb +0 -1
  196. data/lib/active_record/type/type_map.rb +0 -1
  197. data/lib/active_record/type/unsigned_integer.rb +0 -1
  198. data/lib/active_record/type_caster/connection.rb +15 -14
  199. data/lib/active_record/type_caster/map.rb +1 -4
  200. data/lib/active_record/validations.rb +3 -3
  201. data/lib/active_record/validations/associated.rb +1 -2
  202. data/lib/active_record/validations/uniqueness.rb +15 -27
  203. data/lib/arel.rb +62 -0
  204. data/lib/arel/alias_predication.rb +9 -0
  205. data/lib/arel/attributes.rb +22 -0
  206. data/lib/arel/attributes/attribute.rb +37 -0
  207. data/lib/arel/collectors/bind.rb +24 -0
  208. data/lib/arel/collectors/composite.rb +31 -0
  209. data/lib/arel/collectors/plain_string.rb +20 -0
  210. data/lib/arel/collectors/sql_string.rb +20 -0
  211. data/lib/arel/collectors/substitute_binds.rb +28 -0
  212. data/lib/arel/crud.rb +42 -0
  213. data/lib/arel/delete_manager.rb +18 -0
  214. data/lib/arel/errors.rb +9 -0
  215. data/lib/arel/expressions.rb +29 -0
  216. data/lib/arel/factory_methods.rb +49 -0
  217. data/lib/arel/insert_manager.rb +49 -0
  218. data/lib/arel/math.rb +45 -0
  219. data/lib/arel/nodes.rb +68 -0
  220. data/lib/arel/nodes/and.rb +32 -0
  221. data/lib/arel/nodes/ascending.rb +23 -0
  222. data/lib/arel/nodes/binary.rb +52 -0
  223. data/lib/arel/nodes/bind_param.rb +36 -0
  224. data/lib/arel/nodes/case.rb +55 -0
  225. data/lib/arel/nodes/casted.rb +50 -0
  226. data/lib/arel/nodes/comment.rb +29 -0
  227. data/lib/arel/nodes/count.rb +12 -0
  228. data/lib/arel/nodes/delete_statement.rb +45 -0
  229. data/lib/arel/nodes/descending.rb +23 -0
  230. data/lib/arel/nodes/equality.rb +18 -0
  231. data/lib/arel/nodes/extract.rb +24 -0
  232. data/lib/arel/nodes/false.rb +16 -0
  233. data/lib/arel/nodes/full_outer_join.rb +8 -0
  234. data/lib/arel/nodes/function.rb +44 -0
  235. data/lib/arel/nodes/grouping.rb +8 -0
  236. data/lib/arel/nodes/in.rb +8 -0
  237. data/lib/arel/nodes/infix_operation.rb +80 -0
  238. data/lib/arel/nodes/inner_join.rb +8 -0
  239. data/lib/arel/nodes/insert_statement.rb +37 -0
  240. data/lib/arel/nodes/join_source.rb +20 -0
  241. data/lib/arel/nodes/matches.rb +18 -0
  242. data/lib/arel/nodes/named_function.rb +23 -0
  243. data/lib/arel/nodes/node.rb +50 -0
  244. data/lib/arel/nodes/node_expression.rb +13 -0
  245. data/lib/arel/nodes/outer_join.rb +8 -0
  246. data/lib/arel/nodes/over.rb +15 -0
  247. data/lib/arel/nodes/regexp.rb +16 -0
  248. data/lib/arel/nodes/right_outer_join.rb +8 -0
  249. data/lib/arel/nodes/select_core.rb +67 -0
  250. data/lib/arel/nodes/select_statement.rb +41 -0
  251. data/lib/arel/nodes/sql_literal.rb +16 -0
  252. data/lib/arel/nodes/string_join.rb +11 -0
  253. data/lib/arel/nodes/table_alias.rb +27 -0
  254. data/lib/arel/nodes/terminal.rb +16 -0
  255. data/lib/arel/nodes/true.rb +16 -0
  256. data/lib/arel/nodes/unary.rb +45 -0
  257. data/lib/arel/nodes/unary_operation.rb +20 -0
  258. data/lib/arel/nodes/unqualified_column.rb +22 -0
  259. data/lib/arel/nodes/update_statement.rb +41 -0
  260. data/lib/arel/nodes/values_list.rb +9 -0
  261. data/lib/arel/nodes/window.rb +126 -0
  262. data/lib/arel/nodes/with.rb +11 -0
  263. data/lib/arel/order_predications.rb +13 -0
  264. data/lib/arel/predications.rb +256 -0
  265. data/lib/arel/select_manager.rb +271 -0
  266. data/lib/arel/table.rb +110 -0
  267. data/lib/arel/tree_manager.rb +72 -0
  268. data/lib/arel/update_manager.rb +34 -0
  269. data/lib/arel/visitors.rb +20 -0
  270. data/lib/arel/visitors/depth_first.rb +203 -0
  271. data/lib/arel/visitors/dot.rb +296 -0
  272. data/lib/arel/visitors/ibm_db.rb +34 -0
  273. data/lib/arel/visitors/informix.rb +62 -0
  274. data/lib/arel/visitors/mssql.rb +156 -0
  275. data/lib/arel/visitors/mysql.rb +83 -0
  276. data/lib/arel/visitors/oracle.rb +158 -0
  277. data/lib/arel/visitors/oracle12.rb +65 -0
  278. data/lib/arel/visitors/postgresql.rb +109 -0
  279. data/lib/arel/visitors/sqlite.rb +38 -0
  280. data/lib/arel/visitors/to_sql.rb +888 -0
  281. data/lib/arel/visitors/visitor.rb +45 -0
  282. data/lib/arel/visitors/where_sql.rb +22 -0
  283. data/lib/arel/window_predications.rb +9 -0
  284. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  285. data/lib/rails/generators/active_record/migration.rb +14 -2
  286. data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
  287. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  288. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  289. data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
  290. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  291. metadata +115 -29
  292. data/lib/active_record/collection_cache_key.rb +0 -53
@@ -14,45 +14,37 @@ module ActiveRecord
14
14
  [key] if key
15
15
  end
16
16
 
17
- # Returns the primary key value.
17
+ # Returns the primary key column's value.
18
18
  def id
19
- sync_with_transaction_state
20
- primary_key = self.class.primary_key
21
- _read_attribute(primary_key) if primary_key
19
+ _read_attribute(@primary_key)
22
20
  end
23
21
 
24
- # Sets the primary key value.
22
+ # Sets the primary key column's value.
25
23
  def id=(value)
26
- sync_with_transaction_state
27
- primary_key = self.class.primary_key
28
- _write_attribute(primary_key, value) if primary_key
24
+ _write_attribute(@primary_key, value)
29
25
  end
30
26
 
31
- # Queries the primary key value.
27
+ # Queries the primary key column's value.
32
28
  def id?
33
- sync_with_transaction_state
34
- query_attribute(self.class.primary_key)
29
+ query_attribute(@primary_key)
35
30
  end
36
31
 
37
- # Returns the primary key value before type cast.
32
+ # Returns the primary key column's value before type cast.
38
33
  def id_before_type_cast
39
- sync_with_transaction_state
40
- read_attribute_before_type_cast(self.class.primary_key)
34
+ read_attribute_before_type_cast(@primary_key)
41
35
  end
42
36
 
43
- # Returns the primary key previous value.
37
+ # Returns the primary key column's previous value.
44
38
  def id_was
45
- sync_with_transaction_state
46
- attribute_was(self.class.primary_key)
39
+ attribute_was(@primary_key)
47
40
  end
48
41
 
42
+ # Returns the primary key column's value from the database.
49
43
  def id_in_database
50
- sync_with_transaction_state
51
- attribute_in_database(self.class.primary_key)
44
+ attribute_in_database(@primary_key)
52
45
  end
53
46
 
54
47
  private
55
-
56
48
  def attribute_method?(attr_name)
57
49
  attr_name == "id" || super
58
50
  end
@@ -83,7 +75,7 @@ module ActiveRecord
83
75
  end
84
76
 
85
77
  def reset_primary_key #:nodoc:
86
- if self == base_class
78
+ if base_class?
87
79
  self.primary_key = get_primary_key(base_class.name)
88
80
  else
89
81
  self.primary_key = base_class.primary_key
@@ -121,17 +113,16 @@ module ActiveRecord
121
113
  #
122
114
  # Project.primary_key # => "foo_id"
123
115
  def primary_key=(value)
124
- @primary_key = value && value.to_s
116
+ @primary_key = value && -value.to_s
125
117
  @quoted_primary_key = nil
126
118
  @attributes_builder = nil
127
119
  end
128
120
 
129
121
  private
130
-
131
122
  def suppress_composite_primary_key(pk)
132
123
  return pk unless pk.is_a?(Array)
133
124
 
134
- warn <<-WARNING.strip_heredoc
125
+ warn <<~WARNING
135
126
  WARNING: Active Record does not support composite primary key.
136
127
 
137
128
  #{table_name} has composite primary key. Composite primary key is ignored.
@@ -16,8 +16,7 @@ module ActiveRecord
16
16
  when true then true
17
17
  when false, nil then false
18
18
  else
19
- column = self.class.columns_hash[attr_name]
20
- if column.nil?
19
+ if !type_for_attribute(attr_name) { false }
21
20
  if Numeric === value || value !~ /[^0-9]/
22
21
  !value.to_i.zero?
23
22
  else
@@ -33,7 +32,7 @@ module ActiveRecord
33
32
  end
34
33
 
35
34
  private
36
- # Handle *? for method_missing.
35
+ # Dispatch target for <tt>*?</tt> attribute methods.
37
36
  def attribute?(attribute_name)
38
37
  query_attribute(attribute_name)
39
38
  end
@@ -7,43 +7,16 @@ module ActiveRecord
7
7
 
8
8
  module ClassMethods # :nodoc:
9
9
  private
10
-
11
- # We want to generate the methods via module_eval rather than
12
- # define_method, because define_method is slower on dispatch.
13
- # Evaluating many similar methods may use more memory as the instruction
14
- # sequences are duplicated and cached (in MRI). define_method may
15
- # be slower on dispatch, but if you're careful about the closure
16
- # created, then define_method will consume much less memory.
17
- #
18
- # But sometimes the database might return columns with
19
- # characters that are not allowed in normal method names (like
20
- # 'my_column(omg)'. So to work around this we first define with
21
- # the __temp__ identifier, and then use alias method to rename
22
- # it to what we want.
23
- #
24
- # We are also defining a constant to hold the frozen string of
25
- # the attribute name. Using a constant means that we do not have
26
- # to allocate an object on each call to the attribute method.
27
- # Making it frozen means that it doesn't get duped when used to
28
- # key the @attributes in read_attribute.
29
10
  def define_method_attribute(name)
30
- safe_name = name.unpack("h*".freeze).first
31
- temp_method = "__temp__#{safe_name}"
32
-
33
- ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
34
- sync_with_transaction_state = "sync_with_transaction_state" if name == primary_key
35
-
36
- generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
37
- def #{temp_method}
38
- #{sync_with_transaction_state}
39
- name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
40
- _read_attribute(name) { |n| missing_attribute(n, caller) }
41
- end
42
- STR
43
-
44
- generated_attribute_methods.module_eval do
45
- alias_method name, temp_method
46
- undef_method temp_method
11
+ ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
12
+ generated_attribute_methods, name
13
+ ) do |temp_method_name, attr_name_expr|
14
+ generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
15
+ def #{temp_method_name}
16
+ name = #{attr_name_expr}
17
+ _read_attribute(name) { |n| missing_attribute(n, caller) }
18
+ end
19
+ RUBY
47
20
  end
48
21
  end
49
22
  end
@@ -52,30 +25,18 @@ module ActiveRecord
52
25
  # it has been typecast (for example, "2004-12-12" in a date column is cast
53
26
  # to a date object, like Date.new(2004, 12, 12)).
54
27
  def read_attribute(attr_name, &block)
55
- name = if self.class.attribute_alias?(attr_name)
56
- self.class.attribute_alias(attr_name).to_s
57
- else
58
- attr_name.to_s
59
- end
28
+ name = attr_name.to_s
29
+ name = self.class.attribute_aliases[name] || name
60
30
 
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
31
+ name = @primary_key if name == "id" && @primary_key
64
32
  _read_attribute(name, &block)
65
33
  end
66
34
 
67
35
  # This method exists to avoid the expensive primary_key check internally, without
68
36
  # breaking compatibility with the read_attribute API
69
- if defined?(JRUBY_VERSION)
70
- # This form is significantly faster on JRuby, and this is one of our biggest hotspots.
71
- # https://github.com/jruby/jruby/pull/2562
72
- def _read_attribute(attr_name, &block) # :nodoc:
73
- @attributes.fetch_value(attr_name.to_s, &block)
74
- end
75
- else
76
- def _read_attribute(attr_name) # :nodoc:
77
- @attributes.fetch_value(attr_name.to_s) { |n| yield n if block_given? }
78
- end
37
+ def _read_attribute(attr_name, &block) # :nodoc
38
+ sync_with_transaction_state if @transaction_state&.finalized?
39
+ @attributes.fetch_value(attr_name.to_s, &block)
79
40
  end
80
41
 
81
42
  alias :attribute :_read_attribute
@@ -7,7 +7,7 @@ module ActiveRecord
7
7
 
8
8
  class ColumnNotSerializableError < StandardError
9
9
  def initialize(name, type)
10
- super <<-EOS.strip_heredoc
10
+ super <<~EOS
11
11
  Column `#{name}` of type #{type.class} does not support `serialize` feature.
12
12
  Usually it means that you are trying to use `serialize`
13
13
  on a column that already implements serialization natively.
@@ -79,7 +79,6 @@ module ActiveRecord
79
79
  end
80
80
 
81
81
  private
82
-
83
82
  def type_incompatible_with_serialize?(type, class_name)
84
83
  type.is_a?(ActiveRecord::Type::Json) && class_name == ::JSON ||
85
84
  type.respond_to?(:type_cast_array, true) && class_name == ::Array
@@ -25,7 +25,6 @@ module ActiveRecord
25
25
  end
26
26
 
27
27
  private
28
-
29
28
  def convert_time_to_time_zone(value)
30
29
  return if value.nil?
31
30
 
@@ -64,7 +63,6 @@ module ActiveRecord
64
63
 
65
64
  module ClassMethods # :nodoc:
66
65
  private
67
-
68
66
  def inherited(subclass)
69
67
  super
70
68
  # We need to apply this decorator here, rather than on module inclusion. The closure
@@ -73,7 +71,7 @@ module ActiveRecord
73
71
  # `skip_time_zone_conversion_for_attributes` would not be picked up.
74
72
  subclass.class_eval do
75
73
  matcher = ->(name, type) { create_time_zone_conversion_attribute?(name, type) }
76
- decorate_matching_attribute_types(matcher, :_time_zone_conversion) do |type|
74
+ decorate_matching_attribute_types(matcher, "_time_zone_conversion") do |type|
77
75
  TimeZoneConverter.new(type)
78
76
  end
79
77
  end
@@ -11,21 +11,17 @@ module ActiveRecord
11
11
 
12
12
  module ClassMethods # :nodoc:
13
13
  private
14
-
15
14
  def define_method_attribute=(name)
16
- safe_name = name.unpack("h*".freeze).first
17
- ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
18
- sync_with_transaction_state = "sync_with_transaction_state" if name == primary_key
19
-
20
- generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
21
- def __temp__#{safe_name}=(value)
22
- name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
23
- #{sync_with_transaction_state}
24
- _write_attribute(name, value)
25
- end
26
- alias_method #{(name + '=').inspect}, :__temp__#{safe_name}=
27
- undef_method :__temp__#{safe_name}=
28
- STR
15
+ ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
16
+ generated_attribute_methods, name, writer: true,
17
+ ) do |temp_method_name, attr_name_expr|
18
+ generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
19
+ def #{temp_method_name}(value)
20
+ name = #{attr_name_expr}
21
+ _write_attribute(name, value)
22
+ end
23
+ RUBY
24
+ end
29
25
  end
30
26
  end
31
27
 
@@ -33,33 +29,29 @@ module ActiveRecord
33
29
  # specified +value+. Empty strings for Integer and Float columns are
34
30
  # turned into +nil+.
35
31
  def write_attribute(attr_name, value)
36
- name = if self.class.attribute_alias?(attr_name)
37
- self.class.attribute_alias(attr_name).to_s
38
- else
39
- attr_name.to_s
40
- end
32
+ name = attr_name.to_s
33
+ name = self.class.attribute_aliases[name] || name
41
34
 
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
35
+ name = @primary_key if name == "id" && @primary_key
45
36
  _write_attribute(name, value)
46
37
  end
47
38
 
48
39
  # This method exists to avoid the expensive primary_key check internally, without
49
40
  # breaking compatibility with the write_attribute API
50
41
  def _write_attribute(attr_name, value) # :nodoc:
42
+ sync_with_transaction_state if @transaction_state&.finalized?
51
43
  @attributes.write_from_user(attr_name.to_s, value)
52
44
  value
53
45
  end
54
46
 
55
47
  private
56
48
  def write_attribute_without_type_cast(attr_name, value)
57
- name = attr_name.to_s
58
- @attributes.write_cast_value(name, value)
49
+ sync_with_transaction_state if @transaction_state&.finalized?
50
+ @attributes.write_cast_value(attr_name.to_s, value)
59
51
  value
60
52
  end
61
53
 
62
- # Handle *= for method_missing.
54
+ # Dispatch target for <tt>*=</tt> attribute methods.
63
55
  def attribute=(attribute_name, value)
64
56
  _write_attribute(attribute_name, value)
65
57
  end
@@ -41,6 +41,9 @@ module ActiveRecord
41
41
  # +range+ (PostgreSQL only) specifies that the type should be a range (see the
42
42
  # examples below).
43
43
  #
44
+ # When using a symbol for +cast_type+, extra options are forwarded to the
45
+ # constructor of the type object.
46
+ #
44
47
  # ==== Examples
45
48
  #
46
49
  # The type detected by Active Record can be overridden.
@@ -112,6 +115,16 @@ module ActiveRecord
112
115
  # my_float_range: 1.0..3.5
113
116
  # }
114
117
  #
118
+ # Passing options to the type constructor
119
+ #
120
+ # # app/models/my_model.rb
121
+ # class MyModel < ActiveRecord::Base
122
+ # attribute :small_int, :integer, limit: 2
123
+ # end
124
+ #
125
+ # MyModel.create(small_int: 65537)
126
+ # # => Error: 65537 is out of range for the limit of two bytes
127
+ #
115
128
  # ==== Creating Custom Types
116
129
  #
117
130
  # Users may also define their own custom types, as long as they respond
@@ -242,7 +255,6 @@ module ActiveRecord
242
255
  end
243
256
 
244
257
  private
245
-
246
258
  NO_DEFAULT_PROVIDED = Object.new # :nodoc:
247
259
  private_constant :NO_DEFAULT_PROVIDED
248
260
 
@@ -147,9 +147,8 @@ module ActiveRecord
147
147
 
148
148
  module ClassMethods # :nodoc:
149
149
  private
150
-
151
150
  def define_non_cyclic_method(name, &block)
152
- return if method_defined?(name)
151
+ return if instance_methods(false).include?(name)
153
152
  define_method(name) do |*args|
154
153
  result = true; @_already_called ||= {}
155
154
  # Loop prevention for validation of associations
@@ -267,7 +266,6 @@ module ActiveRecord
267
266
  end
268
267
 
269
268
  private
270
-
271
269
  # Returns the record for an association collection that should be validated
272
270
  # or saved. If +autosave+ is +false+ only new records will be returned,
273
271
  # unless the parent is/was a new record itself.
@@ -363,7 +361,7 @@ module ActiveRecord
363
361
  # Is used as a before_save callback to check while saving a collection
364
362
  # association whether or not the parent was a new record before saving.
365
363
  def before_save_collection_association
366
- @new_record_before_save = new_record?
364
+ @new_record_before_save ||= new_record?
367
365
  end
368
366
 
369
367
  def after_save_collection_association
@@ -416,7 +414,7 @@ module ActiveRecord
416
414
  saved = record.save(validate: false)
417
415
  end
418
416
 
419
- raise ActiveRecord::Rollback unless saved
417
+ raise(RecordInvalid.new(association.owner)) unless saved
420
418
  end
421
419
  end
422
420
  end
@@ -9,7 +9,6 @@ require "active_support/core_ext/module/attribute_accessors"
9
9
  require "active_support/core_ext/array/extract_options"
10
10
  require "active_support/core_ext/hash/deep_merge"
11
11
  require "active_support/core_ext/hash/slice"
12
- require "active_support/core_ext/hash/transform_values"
13
12
  require "active_support/core_ext/string/behavior"
14
13
  require "active_support/core_ext/kernel/singleton_class"
15
14
  require "active_support/core_ext/module/introspection"
@@ -23,6 +22,7 @@ require "active_record/explain_subscriber"
23
22
  require "active_record/relation/delegation"
24
23
  require "active_record/attributes"
25
24
  require "active_record/type_caster"
25
+ require "active_record/database_configurations"
26
26
 
27
27
  module ActiveRecord #:nodoc:
28
28
  # = Active Record
@@ -288,7 +288,7 @@ module ActiveRecord #:nodoc:
288
288
  extend Explain
289
289
  extend Enum
290
290
  extend Delegation::DelegateCache
291
- extend CollectionCacheKey
291
+ extend Aggregations::ClassMethods
292
292
 
293
293
  include Core
294
294
  include Persistence
@@ -314,7 +314,6 @@ module ActiveRecord #:nodoc:
314
314
  include ActiveModel::SecurePassword
315
315
  include AutosaveAssociation
316
316
  include NestedAttributes
317
- include Aggregations
318
317
  include Transactions
319
318
  include TouchLater
320
319
  include NoTouching
@@ -75,21 +75,7 @@ module ActiveRecord
75
75
  # end
76
76
  #
77
77
  # Now, when <tt>Topic#destroy</tt> is run only +destroy_author+ is called. When <tt>Reply#destroy</tt> is
78
- # run, both +destroy_author+ and +destroy_readers+ are called. Contrast this to the following situation
79
- # where the +before_destroy+ method is overridden:
80
- #
81
- # class Topic < ActiveRecord::Base
82
- # def before_destroy() destroy_author end
83
- # end
84
- #
85
- # class Reply < Topic
86
- # def before_destroy() destroy_readers end
87
- # end
88
- #
89
- # In that case, <tt>Reply#destroy</tt> would only run +destroy_readers+ and _not_ +destroy_author+.
90
- # So, use the callback macros when you want to ensure that a certain callback is called for the entire
91
- # hierarchy, and use the regular overwritable methods when you want to leave it up to each descendant
92
- # to decide whether they want to call +super+ and trigger the inherited callbacks.
78
+ # run, both +destroy_author+ and +destroy_readers+ are called.
93
79
  #
94
80
  # *IMPORTANT:* In order for inheritance to work for the callback queues, you must specify the
95
81
  # callbacks before specifying the associations. Otherwise, you might trigger the loading of a
@@ -109,7 +95,7 @@ module ActiveRecord
109
95
  #
110
96
  # private
111
97
  # def delete_parents
112
- # self.class.delete_all "parent_id = #{id}"
98
+ # self.class.delete_by(parent_id: id)
113
99
  # end
114
100
  # end
115
101
  #
@@ -142,7 +128,7 @@ module ActiveRecord
142
128
  # end
143
129
  # end
144
130
  #
145
- # So you specify the object you want messaged on a given callback. When that callback is triggered, the object has
131
+ # So you specify the object you want to be messaged on a given callback. When that callback is triggered, the object has
146
132
  # a method by the name of the callback messaged. You can make these callbacks more flexible by passing in other
147
133
  # initialization data such as the name of the attribute to work with:
148
134
  #
@@ -328,7 +314,7 @@ module ActiveRecord
328
314
  @_destroy_callback_already_called = false
329
315
  end
330
316
 
331
- def touch(*) #:nodoc:
317
+ def touch(*, **) #:nodoc:
332
318
  _run_touch_callbacks { super }
333
319
  end
334
320
 
@@ -337,8 +323,7 @@ module ActiveRecord
337
323
  end
338
324
 
339
325
  private
340
-
341
- def create_or_update(*)
326
+ def create_or_update(**)
342
327
  _run_save_callbacks { super }
343
328
  end
344
329
 
@@ -346,7 +331,7 @@ module ActiveRecord
346
331
  _run_create_callbacks { super }
347
332
  end
348
333
 
349
- def _update_record(*)
334
+ def _update_record
350
335
  _run_update_callbacks { super }
351
336
  end
352
337
  end