activerecord 5.2.8.1 → 6.1.6.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 (316) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1255 -596
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +7 -5
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/aggregations.rb +9 -8
  7. data/lib/active_record/association_relation.rb +30 -10
  8. data/lib/active_record/associations/alias_tracker.rb +19 -16
  9. data/lib/active_record/associations/association.rb +100 -41
  10. data/lib/active_record/associations/association_scope.rb +23 -21
  11. data/lib/active_record/associations/belongs_to_association.rb +55 -48
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -6
  13. data/lib/active_record/associations/builder/association.rb +45 -22
  14. data/lib/active_record/associations/builder/belongs_to.rb +29 -59
  15. data/lib/active_record/associations/builder/collection_association.rb +8 -17
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
  17. data/lib/active_record/associations/builder/has_many.rb +8 -2
  18. data/lib/active_record/associations/builder/has_one.rb +33 -2
  19. data/lib/active_record/associations/builder/singular_association.rb +3 -1
  20. data/lib/active_record/associations/collection_association.rb +44 -34
  21. data/lib/active_record/associations/collection_proxy.rb +25 -21
  22. data/lib/active_record/associations/foreign_association.rb +20 -0
  23. data/lib/active_record/associations/has_many_association.rb +26 -13
  24. data/lib/active_record/associations/has_many_through_association.rb +24 -18
  25. data/lib/active_record/associations/has_one_association.rb +43 -31
  26. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  27. data/lib/active_record/associations/join_dependency/join_association.rb +44 -22
  28. data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
  29. data/lib/active_record/associations/join_dependency.rb +91 -60
  30. data/lib/active_record/associations/preloader/association.rb +69 -43
  31. data/lib/active_record/associations/preloader/through_association.rb +49 -40
  32. data/lib/active_record/associations/preloader.rb +47 -34
  33. data/lib/active_record/associations/singular_association.rb +3 -17
  34. data/lib/active_record/associations/through_association.rb +1 -1
  35. data/lib/active_record/associations.rb +137 -25
  36. data/lib/active_record/attribute_assignment.rb +17 -19
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -7
  38. data/lib/active_record/attribute_methods/dirty.rb +101 -40
  39. data/lib/active_record/attribute_methods/primary_key.rb +20 -25
  40. data/lib/active_record/attribute_methods/query.rb +4 -8
  41. data/lib/active_record/attribute_methods/read.rb +14 -56
  42. data/lib/active_record/attribute_methods/serialization.rb +12 -7
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
  44. data/lib/active_record/attribute_methods/write.rb +18 -34
  45. data/lib/active_record/attribute_methods.rb +81 -143
  46. data/lib/active_record/attributes.rb +46 -9
  47. data/lib/active_record/autosave_association.rb +57 -42
  48. data/lib/active_record/base.rb +4 -17
  49. data/lib/active_record/callbacks.rb +158 -43
  50. data/lib/active_record/coders/yaml_column.rb +1 -2
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +272 -130
  52. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -36
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -146
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -14
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +98 -47
  56. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -110
  58. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +211 -90
  59. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -4
  60. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +385 -144
  61. data/lib/active_record/connection_adapters/abstract/transaction.rb +167 -69
  62. data/lib/active_record/connection_adapters/abstract_adapter.rb +229 -99
  63. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +243 -275
  64. data/lib/active_record/connection_adapters/column.rb +30 -12
  65. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  66. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  67. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  68. data/lib/active_record/connection_adapters/mysql/database_statements.rb +88 -32
  69. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  70. data/lib/active_record/connection_adapters/mysql/quoting.rb +59 -7
  71. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
  72. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
  73. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +18 -7
  74. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +142 -19
  75. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
  76. data/lib/active_record/connection_adapters/mysql2_adapter.rb +53 -18
  77. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  78. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  79. data/lib/active_record/connection_adapters/postgresql/column.rb +37 -28
  80. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -54
  81. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  83. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  84. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
  90. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
  93. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
  94. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  96. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
  97. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/quoting.rb +47 -10
  99. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
  100. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +19 -4
  101. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  102. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  103. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +120 -100
  104. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
  105. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  106. data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -120
  107. data/lib/active_record/connection_adapters/schema_cache.rb +159 -21
  108. data/lib/active_record/connection_adapters/sql_type_metadata.rb +17 -6
  109. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +146 -0
  110. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
  111. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  112. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +77 -13
  113. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +174 -186
  114. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  115. data/lib/active_record/connection_adapters.rb +52 -0
  116. data/lib/active_record/connection_handling.rb +293 -33
  117. data/lib/active_record/core.rb +333 -98
  118. data/lib/active_record/counter_cache.rb +8 -30
  119. data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
  120. data/lib/active_record/database_configurations/database_config.rb +80 -0
  121. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  122. data/lib/active_record/database_configurations/url_config.rb +53 -0
  123. data/lib/active_record/database_configurations.rb +273 -0
  124. data/lib/active_record/delegated_type.rb +209 -0
  125. data/lib/active_record/destroy_association_async_job.rb +36 -0
  126. data/lib/active_record/dynamic_matchers.rb +3 -4
  127. data/lib/active_record/enum.rb +108 -36
  128. data/lib/active_record/errors.rb +62 -19
  129. data/lib/active_record/explain.rb +10 -6
  130. data/lib/active_record/explain_subscriber.rb +1 -1
  131. data/lib/active_record/fixture_set/file.rb +10 -17
  132. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  133. data/lib/active_record/fixture_set/render_context.rb +17 -0
  134. data/lib/active_record/fixture_set/table_row.rb +152 -0
  135. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  136. data/lib/active_record/fixtures.rb +200 -481
  137. data/lib/active_record/gem_version.rb +3 -3
  138. data/lib/active_record/inheritance.rb +53 -24
  139. data/lib/active_record/insert_all.rb +212 -0
  140. data/lib/active_record/integration.rb +67 -17
  141. data/lib/active_record/internal_metadata.rb +28 -9
  142. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  143. data/lib/active_record/locking/optimistic.rb +37 -23
  144. data/lib/active_record/locking/pessimistic.rb +9 -5
  145. data/lib/active_record/log_subscriber.rb +35 -35
  146. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  147. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  148. data/lib/active_record/middleware/database_selector.rb +77 -0
  149. data/lib/active_record/migration/command_recorder.rb +96 -44
  150. data/lib/active_record/migration/compatibility.rb +145 -64
  151. data/lib/active_record/migration/join_table.rb +0 -1
  152. data/lib/active_record/migration.rb +206 -157
  153. data/lib/active_record/model_schema.rb +148 -22
  154. data/lib/active_record/nested_attributes.rb +4 -7
  155. data/lib/active_record/no_touching.rb +8 -1
  156. data/lib/active_record/null_relation.rb +0 -1
  157. data/lib/active_record/persistence.rb +267 -59
  158. data/lib/active_record/query_cache.rb +21 -4
  159. data/lib/active_record/querying.rb +40 -23
  160. data/lib/active_record/railtie.rb +116 -59
  161. data/lib/active_record/railties/console_sandbox.rb +2 -4
  162. data/lib/active_record/railties/controller_runtime.rb +30 -35
  163. data/lib/active_record/railties/databases.rake +411 -80
  164. data/lib/active_record/readonly_attributes.rb +4 -0
  165. data/lib/active_record/reflection.rb +109 -93
  166. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  167. data/lib/active_record/relation/batches.rb +44 -35
  168. data/lib/active_record/relation/calculations.rb +157 -90
  169. data/lib/active_record/relation/delegation.rb +35 -50
  170. data/lib/active_record/relation/finder_methods.rb +64 -39
  171. data/lib/active_record/relation/from_clause.rb +5 -1
  172. data/lib/active_record/relation/merger.rb +32 -40
  173. data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
  174. data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
  175. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  176. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +11 -10
  177. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  178. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  179. data/lib/active_record/relation/predicate_builder.rb +62 -45
  180. data/lib/active_record/relation/query_attribute.rb +13 -8
  181. data/lib/active_record/relation/query_methods.rb +476 -187
  182. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  183. data/lib/active_record/relation/spawn_methods.rb +9 -9
  184. data/lib/active_record/relation/where_clause.rb +115 -62
  185. data/lib/active_record/relation.rb +379 -115
  186. data/lib/active_record/result.rb +64 -38
  187. data/lib/active_record/runtime_registry.rb +2 -2
  188. data/lib/active_record/sanitization.rb +22 -41
  189. data/lib/active_record/schema.rb +2 -11
  190. data/lib/active_record/schema_dumper.rb +54 -9
  191. data/lib/active_record/schema_migration.rb +7 -9
  192. data/lib/active_record/scoping/default.rb +4 -8
  193. data/lib/active_record/scoping/named.rb +17 -24
  194. data/lib/active_record/scoping.rb +8 -9
  195. data/lib/active_record/secure_token.rb +16 -8
  196. data/lib/active_record/serialization.rb +5 -3
  197. data/lib/active_record/signed_id.rb +116 -0
  198. data/lib/active_record/statement_cache.rb +49 -6
  199. data/lib/active_record/store.rb +88 -9
  200. data/lib/active_record/suppressor.rb +2 -2
  201. data/lib/active_record/table_metadata.rb +42 -43
  202. data/lib/active_record/tasks/database_tasks.rb +277 -81
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +27 -32
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
  206. data/lib/active_record/test_databases.rb +24 -0
  207. data/lib/active_record/test_fixtures.rb +287 -0
  208. data/lib/active_record/timestamp.rb +43 -32
  209. data/lib/active_record/touch_later.rb +23 -22
  210. data/lib/active_record/transactions.rb +62 -118
  211. data/lib/active_record/translation.rb +1 -1
  212. data/lib/active_record/type/adapter_specific_registry.rb +3 -13
  213. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  214. data/lib/active_record/type/serialized.rb +6 -3
  215. data/lib/active_record/type/time.rb +10 -0
  216. data/lib/active_record/type/type_map.rb +0 -1
  217. data/lib/active_record/type/unsigned_integer.rb +0 -1
  218. data/lib/active_record/type.rb +10 -5
  219. data/lib/active_record/type_caster/connection.rb +15 -15
  220. data/lib/active_record/type_caster/map.rb +8 -8
  221. data/lib/active_record/validations/associated.rb +1 -2
  222. data/lib/active_record/validations/numericality.rb +35 -0
  223. data/lib/active_record/validations/uniqueness.rb +38 -30
  224. data/lib/active_record/validations.rb +4 -3
  225. data/lib/active_record.rb +13 -12
  226. data/lib/arel/alias_predication.rb +9 -0
  227. data/lib/arel/attributes/attribute.rb +41 -0
  228. data/lib/arel/collectors/bind.rb +29 -0
  229. data/lib/arel/collectors/composite.rb +39 -0
  230. data/lib/arel/collectors/plain_string.rb +20 -0
  231. data/lib/arel/collectors/sql_string.rb +27 -0
  232. data/lib/arel/collectors/substitute_binds.rb +35 -0
  233. data/lib/arel/crud.rb +42 -0
  234. data/lib/arel/delete_manager.rb +18 -0
  235. data/lib/arel/errors.rb +9 -0
  236. data/lib/arel/expressions.rb +29 -0
  237. data/lib/arel/factory_methods.rb +49 -0
  238. data/lib/arel/insert_manager.rb +49 -0
  239. data/lib/arel/math.rb +45 -0
  240. data/lib/arel/nodes/and.rb +32 -0
  241. data/lib/arel/nodes/ascending.rb +23 -0
  242. data/lib/arel/nodes/binary.rb +126 -0
  243. data/lib/arel/nodes/bind_param.rb +44 -0
  244. data/lib/arel/nodes/case.rb +55 -0
  245. data/lib/arel/nodes/casted.rb +62 -0
  246. data/lib/arel/nodes/comment.rb +29 -0
  247. data/lib/arel/nodes/count.rb +12 -0
  248. data/lib/arel/nodes/delete_statement.rb +45 -0
  249. data/lib/arel/nodes/descending.rb +23 -0
  250. data/lib/arel/nodes/equality.rb +15 -0
  251. data/lib/arel/nodes/extract.rb +24 -0
  252. data/lib/arel/nodes/false.rb +16 -0
  253. data/lib/arel/nodes/full_outer_join.rb +8 -0
  254. data/lib/arel/nodes/function.rb +44 -0
  255. data/lib/arel/nodes/grouping.rb +11 -0
  256. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  257. data/lib/arel/nodes/in.rb +15 -0
  258. data/lib/arel/nodes/infix_operation.rb +92 -0
  259. data/lib/arel/nodes/inner_join.rb +8 -0
  260. data/lib/arel/nodes/insert_statement.rb +37 -0
  261. data/lib/arel/nodes/join_source.rb +20 -0
  262. data/lib/arel/nodes/matches.rb +18 -0
  263. data/lib/arel/nodes/named_function.rb +23 -0
  264. data/lib/arel/nodes/node.rb +51 -0
  265. data/lib/arel/nodes/node_expression.rb +13 -0
  266. data/lib/arel/nodes/ordering.rb +27 -0
  267. data/lib/arel/nodes/outer_join.rb +8 -0
  268. data/lib/arel/nodes/over.rb +15 -0
  269. data/lib/arel/nodes/regexp.rb +16 -0
  270. data/lib/arel/nodes/right_outer_join.rb +8 -0
  271. data/lib/arel/nodes/select_core.rb +67 -0
  272. data/lib/arel/nodes/select_statement.rb +41 -0
  273. data/lib/arel/nodes/sql_literal.rb +19 -0
  274. data/lib/arel/nodes/string_join.rb +11 -0
  275. data/lib/arel/nodes/table_alias.rb +31 -0
  276. data/lib/arel/nodes/terminal.rb +16 -0
  277. data/lib/arel/nodes/true.rb +16 -0
  278. data/lib/arel/nodes/unary.rb +44 -0
  279. data/lib/arel/nodes/unary_operation.rb +20 -0
  280. data/lib/arel/nodes/unqualified_column.rb +22 -0
  281. data/lib/arel/nodes/update_statement.rb +41 -0
  282. data/lib/arel/nodes/values_list.rb +9 -0
  283. data/lib/arel/nodes/window.rb +126 -0
  284. data/lib/arel/nodes/with.rb +11 -0
  285. data/lib/arel/nodes.rb +70 -0
  286. data/lib/arel/order_predications.rb +13 -0
  287. data/lib/arel/predications.rb +250 -0
  288. data/lib/arel/select_manager.rb +270 -0
  289. data/lib/arel/table.rb +118 -0
  290. data/lib/arel/tree_manager.rb +72 -0
  291. data/lib/arel/update_manager.rb +34 -0
  292. data/lib/arel/visitors/dot.rb +308 -0
  293. data/lib/arel/visitors/mysql.rb +93 -0
  294. data/lib/arel/visitors/postgresql.rb +120 -0
  295. data/lib/arel/visitors/sqlite.rb +38 -0
  296. data/lib/arel/visitors/to_sql.rb +899 -0
  297. data/lib/arel/visitors/visitor.rb +45 -0
  298. data/lib/arel/visitors.rb +13 -0
  299. data/lib/arel/window_predications.rb +9 -0
  300. data/lib/arel.rb +54 -0
  301. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  302. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
  303. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
  304. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
  305. data/lib/rails/generators/active_record/migration.rb +19 -2
  306. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  307. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  308. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  309. metadata +116 -30
  310. data/lib/active_record/attribute_decorators.rb +0 -90
  311. data/lib/active_record/collection_cache_key.rb +0 -53
  312. data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
  313. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
  314. data/lib/active_record/define_callbacks.rb +0 -22
  315. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
  316. data/lib/active_record/relation/where_clause_factory.rb +0 -34
@@ -11,21 +11,15 @@ module ActiveRecord
11
11
 
12
12
  module ClassMethods # :nodoc:
13
13
  private
14
-
15
- 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
14
+ def define_method_attribute=(name, owner:)
15
+ ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
16
+ owner, name, writer: true,
17
+ ) do |temp_method_name, attr_name_expr|
18
+ owner <<
19
+ "def #{temp_method_name}(value)" <<
20
+ " _write_attribute(#{attr_name_expr}, value)" <<
21
+ "end"
22
+ end
29
23
  end
30
24
  end
31
25
 
@@ -33,35 +27,25 @@ module ActiveRecord
33
27
  # specified +value+. Empty strings for Integer and Float columns are
34
28
  # turned into +nil+.
35
29
  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
30
+ name = attr_name.to_s
31
+ name = self.class.attribute_aliases[name] || name
41
32
 
42
- primary_key = self.class.primary_key
43
- name = primary_key if name == "id".freeze && primary_key
44
- sync_with_transaction_state if name == primary_key
45
- _write_attribute(name, value)
33
+ name = @primary_key if name == "id" && @primary_key
34
+ @attributes.write_from_user(name, value)
46
35
  end
47
36
 
48
37
  # This method exists to avoid the expensive primary_key check internally, without
49
38
  # breaking compatibility with the write_attribute API
50
39
  def _write_attribute(attr_name, value) # :nodoc:
51
- @attributes.write_from_user(attr_name.to_s, value)
52
- value
40
+ @attributes.write_from_user(attr_name, value)
53
41
  end
54
42
 
43
+ alias :attribute= :_write_attribute
44
+ private :attribute=
45
+
55
46
  private
56
47
  def write_attribute_without_type_cast(attr_name, value)
57
- name = attr_name.to_s
58
- @attributes.write_cast_value(name, value)
59
- value
60
- end
61
-
62
- # Handle *= for method_missing.
63
- def attribute=(attribute_name, value)
64
- _write_attribute(attribute_name, value)
48
+ @attributes.write_cast_value(attr_name, value)
65
49
  end
66
50
  end
67
51
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "mutex_m"
4
+ require "active_support/core_ext/enumerable"
4
5
 
5
6
  module ActiveRecord
6
7
  # = Active Record Attribute Methods
@@ -18,25 +19,25 @@ module ActiveRecord
18
19
  include TimeZoneConversion
19
20
  include Dirty
20
21
  include Serialization
21
-
22
- delegate :column_for_attribute, to: :class
23
22
  end
24
23
 
25
- AttrNames = Module.new {
26
- def self.set_name_cache(name, value)
27
- const_name = "ATTR_#{name}"
28
- unless const_defined? const_name
29
- const_set const_name, value.dup.freeze
30
- end
31
- end
32
- }
33
-
34
- BLACKLISTED_CLASS_METHODS = %w(private public protected allocate new name parent superclass)
24
+ RESTRICTED_CLASS_METHODS = %w(private public protected allocate new name parent superclass)
35
25
 
36
26
  class GeneratedAttributeMethods < Module #:nodoc:
37
27
  include Mutex_m
38
28
  end
39
29
 
30
+ class << self
31
+ def dangerous_attribute_methods # :nodoc:
32
+ @dangerous_attribute_methods ||= (
33
+ Base.instance_methods +
34
+ Base.private_instance_methods -
35
+ Base.superclass.instance_methods -
36
+ Base.superclass.private_instance_methods
37
+ ).map { |m| -m.to_s }.to_set.freeze
38
+ end
39
+ end
40
+
40
41
  module ClassMethods
41
42
  def inherited(child_class) #:nodoc:
42
43
  child_class.initialize_generated_modules
@@ -44,7 +45,8 @@ module ActiveRecord
44
45
  end
45
46
 
46
47
  def initialize_generated_modules # :nodoc:
47
- @generated_attribute_methods = GeneratedAttributeMethods.new
48
+ @generated_attribute_methods = const_set(:GeneratedAttributeMethods, GeneratedAttributeMethods.new)
49
+ private_constant :GeneratedAttributeMethods
48
50
  @attribute_methods_generated = false
49
51
  include @generated_attribute_methods
50
52
 
@@ -59,7 +61,7 @@ module ActiveRecord
59
61
  # attribute methods.
60
62
  generated_attribute_methods.synchronize do
61
63
  return false if @attribute_methods_generated
62
- superclass.define_attribute_methods unless self == base_class
64
+ superclass.define_attribute_methods unless base_class?
63
65
  super(attribute_names)
64
66
  @attribute_methods_generated = true
65
67
  end
@@ -105,7 +107,7 @@ module ActiveRecord
105
107
  # A method name is 'dangerous' if it is already (re)defined by Active Record, but
106
108
  # not by any ancestors. (So 'puts' is not dangerous but 'save' is.)
107
109
  def dangerous_attribute_method?(name) # :nodoc:
108
- method_defined_within?(name, Base)
110
+ ::ActiveRecord::AttributeMethods.dangerous_attribute_methods.include?(name.to_s)
109
111
  end
110
112
 
111
113
  def method_defined_within?(name, klass, superklass = klass.superclass) # :nodoc:
@@ -123,13 +125,11 @@ module ActiveRecord
123
125
  # A class method is 'dangerous' if it is already (re)defined by Active Record, but
124
126
  # not by any ancestors. (So 'puts' is not dangerous but 'new' is.)
125
127
  def dangerous_class_method?(method_name)
126
- BLACKLISTED_CLASS_METHODS.include?(method_name.to_s) || class_method_defined_within?(method_name, Base)
127
- end
128
+ return true if RESTRICTED_CLASS_METHODS.include?(method_name.to_s)
128
129
 
129
- def class_method_defined_within?(name, klass, superklass = klass.superclass) # :nodoc:
130
- if klass.respond_to?(name, true)
131
- if superklass.respond_to?(name, true)
132
- klass.method(name).owner != superklass.method(name).owner
130
+ if Base.respond_to?(method_name, true)
131
+ if Object.respond_to?(method_name, true)
132
+ Base.method(method_name).owner != Object.method(method_name).owner
133
133
  else
134
134
  true
135
135
  end
@@ -148,7 +148,7 @@ module ActiveRecord
148
148
  # Person.attribute_method?(:age=) # => true
149
149
  # Person.attribute_method?(:nothing) # => false
150
150
  def attribute_method?(attribute)
151
- super || (table_exists? && column_names.include?(attribute.to_s.sub(/=$/, "")))
151
+ super || (table_exists? && column_names.include?(attribute.to_s.delete_suffix("=")))
152
152
  end
153
153
 
154
154
  # Returns an array of column names as strings if it's not an abstract class and
@@ -164,90 +164,27 @@ module ActiveRecord
164
164
  attribute_types.keys
165
165
  else
166
166
  []
167
- end
168
- end
169
-
170
- # Regexp whitelist. Matches the following:
171
- # "#{table_name}.#{column_name}"
172
- # "#{column_name}"
173
- COLUMN_NAME_WHITELIST = /\A(?:\w+\.)?\w+\z/i
174
-
175
- # Regexp whitelist. Matches the following:
176
- # "#{table_name}.#{column_name}"
177
- # "#{table_name}.#{column_name} #{direction}"
178
- # "#{table_name}.#{column_name} #{direction} NULLS FIRST"
179
- # "#{table_name}.#{column_name} NULLS LAST"
180
- # "#{column_name}"
181
- # "#{column_name} #{direction}"
182
- # "#{column_name} #{direction} NULLS FIRST"
183
- # "#{column_name} NULLS LAST"
184
- COLUMN_NAME_ORDER_WHITELIST = /
185
- \A
186
- (?:\w+\.)?
187
- \w+
188
- (?:\s+asc|\s+desc)?
189
- (?:\s+nulls\s+(?:first|last))?
190
- \z
191
- /ix
192
-
193
- def enforce_raw_sql_whitelist(args, whitelist: COLUMN_NAME_WHITELIST) # :nodoc:
194
- unexpected = args.reject do |arg|
195
- arg.kind_of?(Arel::Node) ||
196
- arg.is_a?(Arel::Nodes::SqlLiteral) ||
197
- arg.is_a?(Arel::Attributes::Attribute) ||
198
- arg.to_s.split(/\s*,\s*/).all? { |part| whitelist.match?(part) }
199
- end
200
-
201
- return if unexpected.none?
202
-
203
- if allow_unsafe_raw_sql == :deprecated
204
- ActiveSupport::Deprecation.warn(
205
- "Dangerous query method (method whose arguments are used as raw " \
206
- "SQL) called with non-attribute argument(s): " \
207
- "#{unexpected.map(&:inspect).join(", ")}. Non-attribute " \
208
- "arguments will be disallowed in Rails 6.0. This method should " \
209
- "not be called with user-provided values, such as request " \
210
- "parameters or model attributes. Known-safe values can be passed " \
211
- "by wrapping them in Arel.sql()."
212
- )
213
- else
214
- raise(ActiveRecord::UnknownAttributeReference,
215
- "Query method called with non-attribute argument(s): " +
216
- unexpected.map(&:inspect).join(", ")
217
- )
218
- end
167
+ end.freeze
219
168
  end
220
169
 
221
170
  # Returns true if the given attribute exists, otherwise false.
222
171
  #
223
172
  # class Person < ActiveRecord::Base
173
+ # alias_attribute :new_name, :name
224
174
  # end
225
175
  #
226
- # Person.has_attribute?('name') # => true
227
- # Person.has_attribute?(:age) # => true
228
- # Person.has_attribute?(:nothing) # => false
176
+ # Person.has_attribute?('name') # => true
177
+ # Person.has_attribute?('new_name') # => true
178
+ # Person.has_attribute?(:age) # => true
179
+ # Person.has_attribute?(:nothing) # => false
229
180
  def has_attribute?(attr_name)
230
- attribute_types.key?(attr_name.to_s)
181
+ attr_name = attr_name.to_s
182
+ attr_name = attribute_aliases[attr_name] || attr_name
183
+ attribute_types.key?(attr_name)
231
184
  end
232
185
 
233
- # Returns the column object for the named attribute.
234
- # Returns a +ActiveRecord::ConnectionAdapters::NullColumn+ if the
235
- # named attribute does not exist.
236
- #
237
- # class Person < ActiveRecord::Base
238
- # end
239
- #
240
- # person = Person.new
241
- # person.column_for_attribute(:name) # the result depends on the ConnectionAdapter
242
- # # => #<ActiveRecord::ConnectionAdapters::Column:0x007ff4ab083980 @name="name", @sql_type="varchar(255)", @null=true, ...>
243
- #
244
- # person.column_for_attribute(:nothing)
245
- # # => #<ActiveRecord::ConnectionAdapters::NullColumn:0xXXX @name=nil, @sql_type=nil, @cast_type=#<Type::Value>, ...>
246
- def column_for_attribute(name)
247
- name = name.to_s
248
- columns_hash.fetch(name) do
249
- ConnectionAdapters::NullColumn.new(name)
250
- end
186
+ def _has_attribute?(attr_name) # :nodoc:
187
+ attribute_types.key?(attr_name)
251
188
  end
252
189
  end
253
190
 
@@ -270,21 +207,14 @@ module ActiveRecord
270
207
  def respond_to?(name, include_private = false)
271
208
  return false unless super
272
209
 
273
- case name
274
- when :to_partial_path
275
- name = "to_partial_path".freeze
276
- when :to_model
277
- name = "to_model".freeze
278
- else
279
- name = name.to_s
280
- end
281
-
282
210
  # If the result is true then check for the select case.
283
211
  # For queries selecting a subset of columns, return false for unselected columns.
284
212
  # We check defined?(@attributes) not to issue warnings if called on objects that
285
213
  # have been allocated but not yet initialized.
286
- if defined?(@attributes) && self.class.column_names.include?(name)
287
- return has_attribute?(name)
214
+ if defined?(@attributes)
215
+ if name = self.class.symbol_column_to_string(name.to_sym)
216
+ return _has_attribute?(name)
217
+ end
288
218
  end
289
219
 
290
220
  true
@@ -293,14 +223,22 @@ module ActiveRecord
293
223
  # Returns +true+ if the given attribute is in the attributes hash, otherwise +false+.
294
224
  #
295
225
  # class Person < ActiveRecord::Base
226
+ # alias_attribute :new_name, :name
296
227
  # end
297
228
  #
298
229
  # person = Person.new
299
- # person.has_attribute?(:name) # => true
300
- # person.has_attribute?('age') # => true
301
- # person.has_attribute?(:nothing) # => false
230
+ # person.has_attribute?(:name) # => true
231
+ # person.has_attribute?(:new_name) # => true
232
+ # person.has_attribute?('age') # => true
233
+ # person.has_attribute?(:nothing) # => false
302
234
  def has_attribute?(attr_name)
303
- @attributes.key?(attr_name.to_s)
235
+ attr_name = attr_name.to_s
236
+ attr_name = self.class.attribute_aliases[attr_name] || attr_name
237
+ @attributes.key?(attr_name)
238
+ end
239
+
240
+ def _has_attribute?(attr_name) # :nodoc:
241
+ @attributes.key?(attr_name)
304
242
  end
305
243
 
306
244
  # Returns an array of names for the attributes available on this object.
@@ -344,15 +282,10 @@ module ActiveRecord
344
282
  # person.attribute_for_inspect(:tag_ids)
345
283
  # # => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]"
346
284
  def attribute_for_inspect(attr_name)
347
- value = read_attribute(attr_name)
348
-
349
- if value.is_a?(String) && value.length > 50
350
- "#{value[0, 50]}...".inspect
351
- elsif value.is_a?(Date) || value.is_a?(Time)
352
- %("#{value.to_s(:db)}")
353
- else
354
- value.inspect
355
- end
285
+ attr_name = attr_name.to_s
286
+ attr_name = self.class.attribute_aliases[attr_name] || attr_name
287
+ value = _read_attribute(attr_name)
288
+ format_for_inspect(attr_name, value)
356
289
  end
357
290
 
358
291
  # Returns +true+ if the specified +attribute+ has been set by the user or by a
@@ -370,8 +303,10 @@ module ActiveRecord
370
303
  # task.is_done = true
371
304
  # task.attribute_present?(:title) # => true
372
305
  # task.attribute_present?(:is_done) # => true
373
- def attribute_present?(attribute)
374
- value = _read_attribute(attribute)
306
+ def attribute_present?(attr_name)
307
+ attr_name = attr_name.to_s
308
+ attr_name = self.class.attribute_aliases[attr_name] || attr_name
309
+ value = _read_attribute(attr_name)
375
310
  !value.nil? && !(value.respond_to?(:empty?) && value.empty?)
376
311
  end
377
312
 
@@ -443,50 +378,53 @@ module ActiveRecord
443
378
  @attributes.accessed
444
379
  end
445
380
 
446
- protected
447
-
448
- def attribute_method?(attr_name) # :nodoc:
381
+ private
382
+ def attribute_method?(attr_name)
449
383
  # We check defined? because Syck calls respond_to? before actually calling initialize.
450
384
  defined?(@attributes) && @attributes.key?(attr_name)
451
385
  end
452
386
 
453
- private
454
-
455
- def attributes_with_values_for_create(attribute_names)
456
- attributes_with_values(attributes_for_create(attribute_names))
457
- end
458
-
459
- def attributes_with_values_for_update(attribute_names)
460
- attributes_with_values(attributes_for_update(attribute_names))
461
- end
462
-
463
387
  def attributes_with_values(attribute_names)
464
- attribute_names.each_with_object({}) do |name, attrs|
465
- attrs[name] = _read_attribute(name)
388
+ attribute_names.index_with do |name|
389
+ _read_attribute(name)
466
390
  end
467
391
  end
468
392
 
469
393
  # Filters the primary keys and readonly attributes from the attribute names.
470
394
  def attributes_for_update(attribute_names)
471
- attribute_names.reject do |name|
472
- readonly_attribute?(name)
395
+ attribute_names &= self.class.column_names
396
+ attribute_names.delete_if do |name|
397
+ self.class.readonly_attribute?(name)
473
398
  end
474
399
  end
475
400
 
476
401
  # Filters out the primary keys, from the attribute names, when the primary
477
402
  # key is to be generated (e.g. the id attribute has no value).
478
403
  def attributes_for_create(attribute_names)
479
- attribute_names.reject do |name|
404
+ attribute_names &= self.class.column_names
405
+ attribute_names.delete_if do |name|
480
406
  pk_attribute?(name) && id.nil?
481
407
  end
482
408
  end
483
409
 
484
- def readonly_attribute?(name)
485
- self.class.readonly_attributes.include?(name)
410
+ def format_for_inspect(name, value)
411
+ if value.nil?
412
+ value.inspect
413
+ else
414
+ inspected_value = if value.is_a?(String) && value.length > 50
415
+ "#{value[0, 50]}...".inspect
416
+ elsif value.is_a?(Date) || value.is_a?(Time)
417
+ %("#{value.to_s(:inspect)}")
418
+ else
419
+ value.inspect
420
+ end
421
+
422
+ inspection_filter.filter_param(name, inspected_value)
423
+ end
486
424
  end
487
425
 
488
426
  def pk_attribute?(name)
489
- name == self.class.primary_key
427
+ name == @primary_key
490
428
  end
491
429
  end
492
430
  end
@@ -12,6 +12,9 @@ module ActiveRecord
12
12
  end
13
13
 
14
14
  module ClassMethods
15
+ ##
16
+ # :call-seq: attribute(name, cast_type = nil, **options)
17
+ #
15
18
  # Defines an attribute with a type on this model. It will override the
16
19
  # type of existing attributes if needed. This allows control over how
17
20
  # values are converted to and from SQL when assigned to a model. It also
@@ -41,6 +44,9 @@ module ActiveRecord
41
44
  # +range+ (PostgreSQL only) specifies that the type should be a range (see the
42
45
  # examples below).
43
46
  #
47
+ # When using a symbol for +cast_type+, extra options are forwarded to the
48
+ # constructor of the type object.
49
+ #
44
50
  # ==== Examples
45
51
  #
46
52
  # The type detected by Active Record can be overridden.
@@ -112,6 +118,16 @@ module ActiveRecord
112
118
  # my_float_range: 1.0..3.5
113
119
  # }
114
120
  #
121
+ # Passing options to the type constructor
122
+ #
123
+ # # app/models/my_model.rb
124
+ # class MyModel < ActiveRecord::Base
125
+ # attribute :small_int, :integer, limit: 2
126
+ # end
127
+ #
128
+ # MyModel.create(small_int: 65537)
129
+ # # => Error: 65537 is out of range for the limit of two bytes
130
+ #
115
131
  # ==== Creating Custom Types
116
132
  #
117
133
  # Users may also define their own custom types, as long as they respond
@@ -157,7 +173,7 @@ module ActiveRecord
157
173
  # class Money < Struct.new(:amount, :currency)
158
174
  # end
159
175
  #
160
- # class MoneyType < Type::Value
176
+ # class MoneyType < ActiveRecord::Type::Value
161
177
  # def initialize(currency_converter:)
162
178
  # @currency_converter = currency_converter
163
179
  # end
@@ -192,13 +208,13 @@ module ActiveRecord
192
208
  # tracking is performed. The methods +changed?+ and +changed_in_place?+
193
209
  # will be called from ActiveModel::Dirty. See the documentation for those
194
210
  # methods in ActiveModel::Type::Value for more details.
195
- def attribute(name, cast_type = Type::Value.new, **options)
211
+ def attribute(name, cast_type = nil, **options, &block)
196
212
  name = name.to_s
197
213
  reload_schema_from_cache
198
214
 
199
215
  self.attributes_to_define_after_schema_loads =
200
216
  attributes_to_define_after_schema_loads.merge(
201
- name => [cast_type, options]
217
+ name => [cast_type || block, options]
202
218
  )
203
219
  end
204
220
 
@@ -233,16 +249,11 @@ module ActiveRecord
233
249
  def load_schema! # :nodoc:
234
250
  super
235
251
  attributes_to_define_after_schema_loads.each do |name, (type, options)|
236
- if type.is_a?(Symbol)
237
- type = ActiveRecord::Type.lookup(type, **options.except(:default))
238
- end
239
-
240
- define_attribute(name, type, **options.slice(:default))
252
+ define_attribute(name, _lookup_cast_type(name, type, options), **options.slice(:default))
241
253
  end
242
254
  end
243
255
 
244
256
  private
245
-
246
257
  NO_DEFAULT_PROVIDED = Object.new # :nodoc:
247
258
  private_constant :NO_DEFAULT_PROVIDED
248
259
 
@@ -261,6 +272,32 @@ module ActiveRecord
261
272
  end
262
273
  _default_attributes[name] = default_attribute
263
274
  end
275
+
276
+ def decorate_attribute_type(attr_name, **default)
277
+ type, options = attributes_to_define_after_schema_loads[attr_name]
278
+
279
+ default.with_defaults!(default: options[:default]) if options&.key?(:default)
280
+
281
+ attribute(attr_name, **default) do |cast_type|
282
+ if type && !type.is_a?(Proc)
283
+ cast_type = _lookup_cast_type(attr_name, type, options)
284
+ end
285
+
286
+ yield cast_type
287
+ end
288
+ end
289
+
290
+ def _lookup_cast_type(name, type, options)
291
+ case type
292
+ when Symbol
293
+ adapter_name = ActiveRecord::Type.adapter_name_from(self)
294
+ ActiveRecord::Type.lookup(type, **options.except(:default), adapter: adapter_name)
295
+ when Proc
296
+ type[type_for_attribute(name)]
297
+ else
298
+ type || type_for_attribute(name)
299
+ end
300
+ end
264
301
  end
265
302
  end
266
303
  end