activerecord 6.0.0 → 6.1.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 (270) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1178 -600
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  5. data/lib/active_record/aggregations.rb +5 -6
  6. data/lib/active_record/association_relation.rb +30 -10
  7. data/lib/active_record/associations/alias_tracker.rb +19 -16
  8. data/lib/active_record/associations/association.rb +55 -29
  9. data/lib/active_record/associations/association_scope.rb +19 -15
  10. data/lib/active_record/associations/belongs_to_association.rb +23 -10
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
  12. data/lib/active_record/associations/builder/association.rb +32 -5
  13. data/lib/active_record/associations/builder/belongs_to.rb +10 -7
  14. data/lib/active_record/associations/builder/collection_association.rb +5 -4
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -3
  16. data/lib/active_record/associations/builder/has_many.rb +6 -2
  17. data/lib/active_record/associations/builder/has_one.rb +11 -14
  18. data/lib/active_record/associations/builder/singular_association.rb +1 -1
  19. data/lib/active_record/associations/collection_association.rb +25 -8
  20. data/lib/active_record/associations/collection_proxy.rb +14 -7
  21. data/lib/active_record/associations/foreign_association.rb +13 -0
  22. data/lib/active_record/associations/has_many_association.rb +24 -3
  23. data/lib/active_record/associations/has_many_through_association.rb +10 -4
  24. data/lib/active_record/associations/has_one_association.rb +15 -1
  25. data/lib/active_record/associations/join_dependency/join_association.rb +39 -16
  26. data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
  27. data/lib/active_record/associations/join_dependency.rb +77 -42
  28. data/lib/active_record/associations/preloader/association.rb +51 -25
  29. data/lib/active_record/associations/preloader/through_association.rb +2 -2
  30. data/lib/active_record/associations/preloader.rb +13 -8
  31. data/lib/active_record/associations/singular_association.rb +1 -1
  32. data/lib/active_record/associations/through_association.rb +1 -1
  33. data/lib/active_record/associations.rb +120 -13
  34. data/lib/active_record/attribute_assignment.rb +10 -9
  35. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
  36. data/lib/active_record/attribute_methods/dirty.rb +3 -13
  37. data/lib/active_record/attribute_methods/primary_key.rb +6 -4
  38. data/lib/active_record/attribute_methods/query.rb +3 -6
  39. data/lib/active_record/attribute_methods/read.rb +8 -12
  40. data/lib/active_record/attribute_methods/serialization.rb +11 -6
  41. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
  42. data/lib/active_record/attribute_methods/write.rb +12 -21
  43. data/lib/active_record/attribute_methods.rb +64 -54
  44. data/lib/active_record/attributes.rb +33 -9
  45. data/lib/active_record/autosave_association.rb +63 -44
  46. data/lib/active_record/base.rb +2 -14
  47. data/lib/active_record/callbacks.rb +153 -24
  48. data/lib/active_record/coders/yaml_column.rb +12 -3
  49. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +202 -138
  50. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  51. data/lib/active_record/connection_adapters/abstract/database_statements.rb +87 -38
  52. data/lib/active_record/connection_adapters/abstract/query_cache.rb +5 -10
  53. data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
  54. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +152 -116
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +141 -52
  57. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  58. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +267 -105
  59. data/lib/active_record/connection_adapters/abstract/transaction.rb +94 -36
  60. data/lib/active_record/connection_adapters/abstract_adapter.rb +76 -79
  61. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -115
  62. data/lib/active_record/connection_adapters/column.rb +15 -1
  63. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  64. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  65. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  66. data/lib/active_record/connection_adapters/mysql/database_statements.rb +30 -36
  67. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  68. data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
  69. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
  70. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  71. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
  72. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +17 -13
  73. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  74. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
  75. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  76. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  77. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  78. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +21 -56
  79. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
  80. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  81. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
  83. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
  87. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
  91. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
  92. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  96. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
  97. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
  101. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  102. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  103. data/lib/active_record/connection_adapters/postgresql_adapter.rb +83 -65
  104. data/lib/active_record/connection_adapters/schema_cache.rb +106 -15
  105. data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
  106. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +38 -12
  107. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
  108. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  109. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
  110. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -57
  111. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  112. data/lib/active_record/connection_adapters.rb +52 -0
  113. data/lib/active_record/connection_handling.rb +219 -81
  114. data/lib/active_record/core.rb +268 -71
  115. data/lib/active_record/counter_cache.rb +4 -1
  116. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  117. data/lib/active_record/database_configurations/database_config.rb +52 -9
  118. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  119. data/lib/active_record/database_configurations/url_config.rb +15 -41
  120. data/lib/active_record/database_configurations.rb +124 -85
  121. data/lib/active_record/delegated_type.rb +209 -0
  122. data/lib/active_record/destroy_association_async_job.rb +36 -0
  123. data/lib/active_record/dynamic_matchers.rb +2 -3
  124. data/lib/active_record/enum.rb +80 -38
  125. data/lib/active_record/errors.rb +47 -12
  126. data/lib/active_record/explain.rb +9 -5
  127. data/lib/active_record/explain_subscriber.rb +1 -1
  128. data/lib/active_record/fixture_set/file.rb +10 -17
  129. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  130. data/lib/active_record/fixture_set/render_context.rb +1 -1
  131. data/lib/active_record/fixture_set/table_row.rb +2 -3
  132. data/lib/active_record/fixture_set/table_rows.rb +0 -1
  133. data/lib/active_record/fixtures.rb +58 -12
  134. data/lib/active_record/gem_version.rb +2 -2
  135. data/lib/active_record/inheritance.rb +40 -21
  136. data/lib/active_record/insert_all.rb +43 -10
  137. data/lib/active_record/integration.rb +3 -5
  138. data/lib/active_record/internal_metadata.rb +16 -7
  139. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  140. data/lib/active_record/locking/optimistic.rb +33 -18
  141. data/lib/active_record/locking/pessimistic.rb +6 -2
  142. data/lib/active_record/log_subscriber.rb +28 -9
  143. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  144. data/lib/active_record/middleware/database_selector/resolver.rb +14 -14
  145. data/lib/active_record/middleware/database_selector.rb +4 -2
  146. data/lib/active_record/migration/command_recorder.rb +53 -45
  147. data/lib/active_record/migration/compatibility.rb +71 -20
  148. data/lib/active_record/migration/join_table.rb +0 -1
  149. data/lib/active_record/migration.rb +115 -85
  150. data/lib/active_record/model_schema.rb +120 -15
  151. data/lib/active_record/nested_attributes.rb +2 -5
  152. data/lib/active_record/no_touching.rb +1 -1
  153. data/lib/active_record/null_relation.rb +0 -1
  154. data/lib/active_record/persistence.rb +50 -46
  155. data/lib/active_record/query_cache.rb +15 -5
  156. data/lib/active_record/querying.rb +12 -7
  157. data/lib/active_record/railtie.rb +65 -45
  158. data/lib/active_record/railties/console_sandbox.rb +2 -4
  159. data/lib/active_record/railties/databases.rake +280 -99
  160. data/lib/active_record/readonly_attributes.rb +4 -0
  161. data/lib/active_record/reflection.rb +77 -63
  162. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  163. data/lib/active_record/relation/batches.rb +38 -32
  164. data/lib/active_record/relation/calculations.rb +106 -45
  165. data/lib/active_record/relation/delegation.rb +9 -7
  166. data/lib/active_record/relation/finder_methods.rb +55 -17
  167. data/lib/active_record/relation/from_clause.rb +5 -1
  168. data/lib/active_record/relation/merger.rb +27 -26
  169. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  170. data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
  171. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
  172. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  173. data/lib/active_record/relation/predicate_builder.rb +59 -40
  174. data/lib/active_record/relation/query_methods.rb +344 -181
  175. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  176. data/lib/active_record/relation/spawn_methods.rb +8 -8
  177. data/lib/active_record/relation/where_clause.rb +111 -62
  178. data/lib/active_record/relation.rb +116 -82
  179. data/lib/active_record/result.rb +41 -34
  180. data/lib/active_record/runtime_registry.rb +2 -2
  181. data/lib/active_record/sanitization.rb +6 -17
  182. data/lib/active_record/schema_dumper.rb +34 -4
  183. data/lib/active_record/schema_migration.rb +2 -8
  184. data/lib/active_record/scoping/default.rb +1 -4
  185. data/lib/active_record/scoping/named.rb +7 -18
  186. data/lib/active_record/scoping.rb +0 -1
  187. data/lib/active_record/secure_token.rb +16 -8
  188. data/lib/active_record/serialization.rb +5 -3
  189. data/lib/active_record/signed_id.rb +116 -0
  190. data/lib/active_record/statement_cache.rb +20 -4
  191. data/lib/active_record/store.rb +3 -3
  192. data/lib/active_record/suppressor.rb +2 -2
  193. data/lib/active_record/table_metadata.rb +42 -36
  194. data/lib/active_record/tasks/database_tasks.rb +140 -113
  195. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
  196. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
  197. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
  198. data/lib/active_record/test_databases.rb +5 -4
  199. data/lib/active_record/test_fixtures.rb +79 -16
  200. data/lib/active_record/timestamp.rb +4 -7
  201. data/lib/active_record/touch_later.rb +20 -21
  202. data/lib/active_record/transactions.rb +26 -73
  203. data/lib/active_record/type/adapter_specific_registry.rb +2 -5
  204. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  205. data/lib/active_record/type/serialized.rb +6 -3
  206. data/lib/active_record/type/time.rb +10 -0
  207. data/lib/active_record/type/type_map.rb +0 -1
  208. data/lib/active_record/type/unsigned_integer.rb +0 -1
  209. data/lib/active_record/type.rb +8 -2
  210. data/lib/active_record/type_caster/connection.rb +0 -1
  211. data/lib/active_record/type_caster/map.rb +8 -5
  212. data/lib/active_record/validations/associated.rb +1 -2
  213. data/lib/active_record/validations/numericality.rb +35 -0
  214. data/lib/active_record/validations/uniqueness.rb +24 -4
  215. data/lib/active_record/validations.rb +3 -3
  216. data/lib/active_record.rb +7 -13
  217. data/lib/arel/attributes/attribute.rb +4 -0
  218. data/lib/arel/collectors/bind.rb +5 -0
  219. data/lib/arel/collectors/composite.rb +8 -0
  220. data/lib/arel/collectors/sql_string.rb +7 -0
  221. data/lib/arel/collectors/substitute_binds.rb +7 -0
  222. data/lib/arel/nodes/binary.rb +82 -8
  223. data/lib/arel/nodes/bind_param.rb +8 -0
  224. data/lib/arel/nodes/casted.rb +21 -9
  225. data/lib/arel/nodes/equality.rb +6 -9
  226. data/lib/arel/nodes/grouping.rb +3 -0
  227. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  228. data/lib/arel/nodes/in.rb +8 -1
  229. data/lib/arel/nodes/infix_operation.rb +13 -1
  230. data/lib/arel/nodes/join_source.rb +1 -1
  231. data/lib/arel/nodes/node.rb +7 -6
  232. data/lib/arel/nodes/ordering.rb +27 -0
  233. data/lib/arel/nodes/sql_literal.rb +3 -0
  234. data/lib/arel/nodes/table_alias.rb +7 -3
  235. data/lib/arel/nodes/unary.rb +0 -1
  236. data/lib/arel/nodes.rb +3 -1
  237. data/lib/arel/predications.rb +17 -24
  238. data/lib/arel/select_manager.rb +1 -2
  239. data/lib/arel/table.rb +13 -5
  240. data/lib/arel/visitors/dot.rb +14 -3
  241. data/lib/arel/visitors/mysql.rb +11 -1
  242. data/lib/arel/visitors/postgresql.rb +15 -5
  243. data/lib/arel/visitors/sqlite.rb +0 -1
  244. data/lib/arel/visitors/to_sql.rb +89 -79
  245. data/lib/arel/visitors/visitor.rb +0 -1
  246. data/lib/arel/visitors.rb +0 -7
  247. data/lib/arel.rb +15 -12
  248. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  249. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  250. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  251. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
  252. data/lib/rails/generators/active_record/migration.rb +6 -2
  253. data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
  254. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  255. metadata +27 -24
  256. data/lib/active_record/attribute_decorators.rb +0 -90
  257. data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
  258. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  259. data/lib/active_record/define_callbacks.rb +0 -22
  260. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  261. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  262. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  263. data/lib/arel/attributes.rb +0 -22
  264. data/lib/arel/visitors/depth_first.rb +0 -204
  265. data/lib/arel/visitors/ibm_db.rb +0 -34
  266. data/lib/arel/visitors/informix.rb +0 -62
  267. data/lib/arel/visitors/mssql.rb +0 -157
  268. data/lib/arel/visitors/oracle.rb +0 -159
  269. data/lib/arel/visitors/oracle12.rb +0 -66
  270. data/lib/arel/visitors/where_sql.rb +0 -23
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "erb"
4
- require "yaml"
3
+ require "active_support/configuration_file"
5
4
 
6
5
  module ActiveRecord
7
6
  class FixtureSet
@@ -29,6 +28,10 @@ module ActiveRecord
29
28
  config_row["model_class"]
30
29
  end
31
30
 
31
+ def ignored_fixtures
32
+ config_row["ignore"]
33
+ end
34
+
32
35
  private
33
36
  def rows
34
37
  @rows ||= raw_rows.reject { |fixture_name, _| fixture_name == "_fixture" }
@@ -40,31 +43,21 @@ module ActiveRecord
40
43
  if row
41
44
  row.last
42
45
  else
43
- { 'model_class': nil }
46
+ { 'model_class': nil, 'ignore': nil }
44
47
  end
45
48
  end
46
49
  end
47
50
 
48
51
  def raw_rows
49
52
  @raw_rows ||= begin
50
- data = YAML.load(render(IO.read(@file)))
53
+ data = ActiveSupport::ConfigurationFile.parse(@file, context:
54
+ ActiveRecord::FixtureSet::RenderContext.create_subclass.new.get_binding)
51
55
  data ? validate(data).to_a : []
52
- rescue ArgumentError, Psych::SyntaxError => error
53
- raise Fixture::FormatError, "a YAML error occurred parsing #{@file}. Please note that YAML must be consistently indented using spaces. Tabs are not allowed. Please have a look at http://www.yaml.org/faq.html\nThe exact error was:\n #{error.class}: #{error}", error.backtrace
56
+ rescue RuntimeError => error
57
+ raise Fixture::FormatError, error.message
54
58
  end
55
59
  end
56
60
 
57
- def prepare_erb(content)
58
- erb = ERB.new(content)
59
- erb.filename = @file
60
- erb
61
- end
62
-
63
- def render(content)
64
- context = ActiveRecord::FixtureSet::RenderContext.create_subclass.new
65
- prepare_erb(content).result(context.get_binding)
66
- end
67
-
68
61
  # Validate our unmarshalled data.
69
62
  def validate(data)
70
63
  unless Hash === data || YAML::Omap === data
@@ -21,8 +21,7 @@ module ActiveRecord
21
21
  end
22
22
 
23
23
  def timestamp_column_names
24
- @timestamp_column_names ||=
25
- %w(created_at created_on updated_at updated_on) & @model_class.column_names
24
+ @model_class.all_timestamp_attributes_in_model
26
25
  end
27
26
 
28
27
  def inheritance_column_name
@@ -10,7 +10,7 @@ class ActiveRecord::FixtureSet::RenderContext # :nodoc:
10
10
  end
11
11
 
12
12
  def binary(path)
13
- %(!!binary "#{Base64.strict_encode64(File.read(path))}")
13
+ %(!!binary "#{Base64.strict_encode64(File.binread(path))}")
14
14
  end
15
15
  end
16
16
  end
@@ -48,7 +48,6 @@ module ActiveRecord
48
48
  end
49
49
 
50
50
  private
51
-
52
51
  def model_metadata
53
52
  @table_rows.model_metadata
54
53
  end
@@ -113,12 +112,12 @@ module ActiveRecord
113
112
  case association.macro
114
113
  when :belongs_to
115
114
  # Do not replace association name with association foreign key if they are named the same
116
- fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
115
+ fk_name = association.join_foreign_key
117
116
 
118
117
  if association.name.to_s != fk_name && value = @row.delete(association.name.to_s)
119
118
  if association.polymorphic? && value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
120
119
  # support polymorphic belongs_to as "label (Type)"
121
- @row[association.foreign_type] = $1
120
+ @row[association.join_foreign_type] = $1
122
121
  end
123
122
 
124
123
  fk_type = reflection_class.type_for_attribute(fk_name).type
@@ -29,7 +29,6 @@ module ActiveRecord
29
29
  end
30
30
 
31
31
  private
32
-
33
32
  def build_table_rows_from(table_name, fixtures, config)
34
33
  now = config.default_timezone == :utc ? Time.now.utc : Time.now
35
34
 
@@ -10,7 +10,6 @@ require "active_record/fixture_set/file"
10
10
  require "active_record/fixture_set/render_context"
11
11
  require "active_record/fixture_set/table_rows"
12
12
  require "active_record/test_fixtures"
13
- require "active_record/errors"
14
13
 
15
14
  module ActiveRecord
16
15
  class FixtureClassNotFound < ActiveRecord::ActiveRecordError #:nodoc:
@@ -41,7 +40,7 @@ module ActiveRecord
41
40
  # separated by a blank line for your viewing pleasure.
42
41
  #
43
42
  # Note: Fixtures are unordered. If you want ordered fixtures, use the omap YAML type.
44
- # See http://yaml.org/type/omap.html
43
+ # See https://yaml.org/type/omap.html
45
44
  # for the specification. You will need ordered fixtures when you have foreign key constraints
46
45
  # on keys in the same table. This is commonly needed for tree structures. Example:
47
46
  #
@@ -60,7 +59,7 @@ module ActiveRecord
60
59
  # Since fixtures are a testing construct, we use them in our unit and functional tests. There
61
60
  # are two ways to use the fixtures, but first let's take a look at a sample unit test:
62
61
  #
63
- # require 'test_helper'
62
+ # require "test_helper"
64
63
  #
65
64
  # class WebSiteTest < ActiveSupport::TestCase
66
65
  # test "web_site_count" do
@@ -182,7 +181,7 @@ module ActiveRecord
182
181
  # end
183
182
  # end
184
183
  #
185
- # If you preload your test database with all fixture data (probably by running `rails db:fixtures:load`)
184
+ # If you preload your test database with all fixture data (probably by running <tt>bin/rails db:fixtures:load</tt>)
186
185
  # and use transactional tests, then you may omit all fixtures declarations in your test cases since
187
186
  # all the data's already there and every case rolls back its changes.
188
187
  #
@@ -420,12 +419,35 @@ module ActiveRecord
420
419
  #
421
420
  # Any fixture labeled "DEFAULTS" is safely ignored.
422
421
  #
422
+ # Besides using "DEFAULTS", you can also specify what fixtures will
423
+ # be ignored by setting "ignore" in "_fixture" section.
424
+ #
425
+ # # users.yml
426
+ # _fixture:
427
+ # ignore:
428
+ # - base
429
+ # # or use "ignore: base" when there is only one fixture needs to be ignored.
430
+ #
431
+ # base: &base
432
+ # admin: false
433
+ # introduction: "This is a default description"
434
+ #
435
+ # admin:
436
+ # <<: *base
437
+ # admin: true
438
+ #
439
+ # visitor:
440
+ # <<: *base
441
+ #
442
+ # In the above example, 'base' will be ignored when creating fixtures.
443
+ # This can be used for common attributes inheriting.
444
+ #
423
445
  # == Configure the fixture model class
424
446
  #
425
447
  # It's possible to set the fixture's model class directly in the YAML file.
426
448
  # This is helpful when fixtures are loaded outside tests and
427
449
  # +set_fixture_class+ is not available (e.g.
428
- # when running <tt>rails db:fixtures:load</tt>).
450
+ # when running <tt>bin/rails db:fixtures:load</tt>).
429
451
  #
430
452
  # _fixture:
431
453
  # model_class: User
@@ -464,7 +486,6 @@ module ActiveRecord
464
486
  end
465
487
 
466
488
  private
467
-
468
489
  def insert_class(class_names, name, klass)
469
490
  # We only want to deal with AR objects.
470
491
  if klass && klass < ActiveRecord::Base
@@ -564,13 +585,20 @@ module ActiveRecord
564
585
  end
565
586
  end
566
587
 
588
+ def signed_global_id(fixture_set_name, label, column_type: :integer, **options)
589
+ identifier = identify(label, column_type)
590
+ model_name = default_fixture_model_name(fixture_set_name)
591
+ uri = URI::GID.build([GlobalID.app, model_name, identifier, {}])
592
+
593
+ SignedGlobalID.new(uri, **options)
594
+ end
595
+
567
596
  # Superclass for the evaluation contexts used by ERB fixtures.
568
597
  def context_class
569
598
  @context_class ||= Class.new
570
599
  end
571
600
 
572
601
  private
573
-
574
602
  def read_and_insert(fixtures_directory, fixture_files, class_names, connection) # :nodoc:
575
603
  fixtures_map = {}
576
604
  fixture_sets = fixture_files.map do |fixture_set_name|
@@ -621,7 +649,7 @@ module ActiveRecord
621
649
  end
622
650
  end
623
651
 
624
- attr_reader :table_name, :name, :fixtures, :model_class, :config
652
+ attr_reader :table_name, :name, :fixtures, :model_class, :ignored_fixtures, :config
625
653
 
626
654
  def initialize(_, name, class_name, path, config = ActiveRecord::Base)
627
655
  @name = name
@@ -654,8 +682,8 @@ module ActiveRecord
654
682
  # Returns a hash of rows to be inserted. The key is the table, the value is
655
683
  # a list of rows to insert to that table.
656
684
  def table_rows
657
- # allow a standard key to be used for doing defaults in YAML
658
- fixtures.delete("DEFAULTS")
685
+ # allow specifying fixtures to be ignored by setting `ignore` in `_fixture` section
686
+ fixtures.except!(*ignored_fixtures)
659
687
 
660
688
  TableRows.new(
661
689
  table_name,
@@ -666,7 +694,6 @@ module ActiveRecord
666
694
  end
667
695
 
668
696
  private
669
-
670
697
  def model_class=(class_name)
671
698
  if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any?
672
699
  @model_class = class_name
@@ -675,6 +702,21 @@ module ActiveRecord
675
702
  end
676
703
  end
677
704
 
705
+ def ignored_fixtures=(base)
706
+ @ignored_fixtures =
707
+ case base
708
+ when Array
709
+ base
710
+ when String
711
+ [base]
712
+ else
713
+ []
714
+ end
715
+
716
+ @ignored_fixtures << "DEFAULTS" unless @ignored_fixtures.include?("DEFAULTS")
717
+ @ignored_fixtures.compact
718
+ end
719
+
678
720
  # Loads the fixtures from the YAML file at +path+.
679
721
  # If the file sets the +model_class+ and current instance value is not set,
680
722
  # it uses the file value.
@@ -686,6 +728,7 @@ module ActiveRecord
686
728
  yaml_files.each_with_object({}) do |file, fixtures|
687
729
  FixtureSet::File.open(file) do |fh|
688
730
  self.model_class ||= fh.model_class if fh.model_class
731
+ self.ignored_fixtures ||= fh.ignored_fixtures
689
732
  fh.each do |fixture_name, row|
690
733
  fixtures[fixture_name] = ActiveRecord::Fixture.new(row, model_class)
691
734
  end
@@ -730,9 +773,12 @@ module ActiveRecord
730
773
 
731
774
  def find
732
775
  raise FixtureClassNotFound, "No class attached to find." unless model_class
733
- model_class.unscoped do
776
+ object = model_class.unscoped do
734
777
  model_class.find(fixture[model_class.primary_key])
735
778
  end
779
+ # Fixtures can't be eagerly loaded
780
+ object.instance_variable_set(:@strict_loading, false)
781
+ object
736
782
  end
737
783
  end
738
784
  end
@@ -8,8 +8,8 @@ module ActiveRecord
8
8
 
9
9
  module VERSION
10
10
  MAJOR = 6
11
- MINOR = 0
12
- TINY = 0
11
+ MINOR = 1
12
+ TINY = 4
13
13
  PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -38,6 +38,8 @@ module ActiveRecord
38
38
  extend ActiveSupport::Concern
39
39
 
40
40
  included do
41
+ class_attribute :store_full_class_name, instance_writer: false, default: true
42
+
41
43
  # Determines whether to store the full constant name including namespace when using STI.
42
44
  # This is true, by default.
43
45
  class_attribute :store_full_sti_class, instance_writer: false, default: true
@@ -52,7 +54,7 @@ module ActiveRecord
52
54
  raise NotImplementedError, "#{self} is an abstract class and cannot be instantiated."
53
55
  end
54
56
 
55
- if has_attribute?(inheritance_column)
57
+ if _has_attribute?(inheritance_column)
56
58
  subclass = subclass_from_attributes(attributes)
57
59
 
58
60
  if subclass.nil? && scope_attributes = current_scope&.scope_for_create
@@ -162,12 +164,42 @@ module ActiveRecord
162
164
  defined?(@abstract_class) && @abstract_class == true
163
165
  end
164
166
 
167
+ # Returns the value to be stored in the inheritance column for STI.
165
168
  def sti_name
166
- store_full_sti_class ? name : name.demodulize
169
+ store_full_sti_class && store_full_class_name ? name : name.demodulize
167
170
  end
168
171
 
172
+ # Returns the class for the provided +type_name+.
173
+ #
174
+ # It is used to find the class correspondent to the value stored in the inheritance column.
175
+ def sti_class_for(type_name)
176
+ if store_full_sti_class && store_full_class_name
177
+ ActiveSupport::Dependencies.constantize(type_name)
178
+ else
179
+ compute_type(type_name)
180
+ end
181
+ rescue NameError
182
+ raise SubclassNotFound,
183
+ "The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " \
184
+ "This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " \
185
+ "Please rename this column if you didn't intend it to be used for storing the inheritance class " \
186
+ "or overwrite #{name}.inheritance_column to use another column for that information."
187
+ end
188
+
189
+ # Returns the value to be stored in the polymorphic type column for Polymorphic Associations.
169
190
  def polymorphic_name
170
- base_class.name
191
+ store_full_class_name ? base_class.name : base_class.name.demodulize
192
+ end
193
+
194
+ # Returns the class for the provided +name+.
195
+ #
196
+ # It is used to find the class correspondent to the value stored in the polymorphic type column.
197
+ def polymorphic_class_for(name)
198
+ if store_full_class_name
199
+ ActiveSupport::Dependencies.constantize(name)
200
+ else
201
+ compute_type(name)
202
+ end
171
203
  end
172
204
 
173
205
  def inherited(subclass)
@@ -176,7 +208,6 @@ module ActiveRecord
176
208
  end
177
209
 
178
210
  protected
179
-
180
211
  # Returns the class type of the record using the current module as a prefix. So descendants of
181
212
  # MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
182
213
  def compute_type(type_name)
@@ -208,7 +239,6 @@ module ActiveRecord
208
239
  end
209
240
 
210
241
  private
211
-
212
242
  # Called by +instantiate+ to decide which class to use for a new
213
243
  # record instance. For single-table inheritance, we check the record
214
244
  # for a +type+ column and return the corresponding class.
@@ -221,32 +251,22 @@ module ActiveRecord
221
251
  end
222
252
 
223
253
  def using_single_table_inheritance?(record)
224
- record[inheritance_column].present? && has_attribute?(inheritance_column)
254
+ record[inheritance_column].present? && _has_attribute?(inheritance_column)
225
255
  end
226
256
 
227
257
  def find_sti_class(type_name)
228
258
  type_name = base_class.type_for_attribute(inheritance_column).cast(type_name)
229
- subclass = begin
230
- if store_full_sti_class
231
- ActiveSupport::Dependencies.constantize(type_name)
232
- else
233
- compute_type(type_name)
234
- end
235
- rescue NameError
236
- raise SubclassNotFound,
237
- "The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " \
238
- "This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " \
239
- "Please rename this column if you didn't intend it to be used for storing the inheritance class " \
240
- "or overwrite #{name}.inheritance_column to use another column for that information."
241
- end
259
+ subclass = sti_class_for(type_name)
260
+
242
261
  unless subclass == self || descendants.include?(subclass)
243
262
  raise SubclassNotFound, "Invalid single-table inheritance type: #{subclass.name} is not a subclass of #{name}"
244
263
  end
264
+
245
265
  subclass
246
266
  end
247
267
 
248
268
  def type_condition(table = arel_table)
249
- sti_column = arel_attribute(inheritance_column, table)
269
+ sti_column = table[inheritance_column]
250
270
  sti_names = ([self] + descendants).map(&:sti_name)
251
271
 
252
272
  predicate_builder.build(sti_column, sti_names)
@@ -272,7 +292,6 @@ module ActiveRecord
272
292
  end
273
293
 
274
294
  private
275
-
276
295
  def initialize_internals_callback
277
296
  super
278
297
  ensure_proper_type
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/enumerable"
4
+
3
5
  module ActiveRecord
4
6
  class InsertAll # :nodoc:
5
7
  attr_reader :model, :connection, :inserts, :keys
@@ -8,13 +10,19 @@ module ActiveRecord
8
10
  def initialize(model, inserts, on_duplicate:, returning: nil, unique_by: nil)
9
11
  raise ArgumentError, "Empty list of attributes passed" if inserts.blank?
10
12
 
11
- @model, @connection, @inserts, @keys = model, model.connection, inserts, inserts.first.keys.map(&:to_s).to_set
13
+ @model, @connection, @inserts, @keys = model, model.connection, inserts, inserts.first.keys.map(&:to_s)
12
14
  @on_duplicate, @returning, @unique_by = on_duplicate, returning, unique_by
13
15
 
16
+ if model.scope_attributes?
17
+ @scope_attributes = model.scope_attributes
18
+ @keys |= @scope_attributes.keys
19
+ end
20
+ @keys = @keys.to_set
21
+
14
22
  @returning = (connection.supports_insert_returning? ? primary_keys : false) if @returning.nil?
15
23
  @returning = false if @returning == []
16
24
 
17
- @unique_by = find_unique_index_for(unique_by) if unique_by
25
+ @unique_by = find_unique_index_for(unique_by)
18
26
  @on_duplicate = :skip if @on_duplicate == :update && updatable_columns.empty?
19
27
 
20
28
  ensure_valid_options_for_connection!
@@ -24,7 +32,7 @@ module ActiveRecord
24
32
  message = +"#{model} "
25
33
  message << "Bulk " if inserts.many?
26
34
  message << (on_duplicate == :update ? "Upsert" : "Insert")
27
- connection.exec_query to_sql, message
35
+ connection.exec_insert_all to_sql, message
28
36
  end
29
37
 
30
38
  def updatable_columns
@@ -32,7 +40,7 @@ module ActiveRecord
32
40
  end
33
41
 
34
42
  def primary_keys
35
- Array(model.primary_key)
43
+ Array(connection.schema_cache.primary_keys(model.table_name))
36
44
  end
37
45
 
38
46
 
@@ -47,6 +55,8 @@ module ActiveRecord
47
55
  def map_key_with_value
48
56
  inserts.map do |attributes|
49
57
  attributes = attributes.stringify_keys
58
+ attributes.merge!(scope_attributes) if scope_attributes
59
+
50
60
  verify_attributes(attributes)
51
61
 
52
62
  keys.map do |key|
@@ -56,13 +66,24 @@ module ActiveRecord
56
66
  end
57
67
 
58
68
  private
69
+ attr_reader :scope_attributes
70
+
59
71
  def find_unique_index_for(unique_by)
60
- match = Array(unique_by).map(&:to_s)
72
+ if !connection.supports_insert_conflict_target?
73
+ return if unique_by.nil?
74
+
75
+ raise ArgumentError, "#{connection.class} does not support :unique_by"
76
+ end
77
+
78
+ name_or_columns = unique_by || model.primary_key
79
+ match = Array(name_or_columns).map(&:to_s)
61
80
 
62
81
  if index = unique_indexes.find { |i| match.include?(i.name) || i.columns == match }
63
82
  index
83
+ elsif match == primary_keys
84
+ unique_by.nil? ? nil : ActiveRecord::ConnectionAdapters::IndexDefinition.new(model.table_name, "#{model.table_name}_primary_key", true, match)
64
85
  else
65
- raise ArgumentError, "No unique index found for #{unique_by}"
86
+ raise ArgumentError, "No unique index found for #{name_or_columns}"
66
87
  end
67
88
  end
68
89
 
@@ -120,7 +141,7 @@ module ActiveRecord
120
141
  end
121
142
 
122
143
  def into
123
- "INTO #{model.quoted_table_name}(#{columns_list})"
144
+ "INTO #{model.quoted_table_name} (#{columns_list})"
124
145
  end
125
146
 
126
147
  def values_list
@@ -130,7 +151,7 @@ module ActiveRecord
130
151
  connection.with_yaml_fallback(types[key].serialize(value))
131
152
  end
132
153
 
133
- Arel::InsertManager.new.create_values_list(values_list).to_sql
154
+ connection.visitor.compile(Arel::Nodes::ValuesList.new(values_list))
134
155
  end
135
156
 
136
157
  def returning
@@ -151,9 +172,21 @@ module ActiveRecord
151
172
  quote_columns(insert_all.updatable_columns)
152
173
  end
153
174
 
175
+ def touch_model_timestamps_unless(&block)
176
+ model.send(:timestamp_attributes_for_update_in_model).map do |column_name|
177
+ if touch_timestamp_attribute?(column_name)
178
+ "#{column_name}=(CASE WHEN (#{updatable_columns.map(&block).join(" AND ")}) THEN #{model.quoted_table_name}.#{column_name} ELSE CURRENT_TIMESTAMP END),"
179
+ end
180
+ end.compact.join
181
+ end
182
+
154
183
  private
155
184
  attr_reader :connection, :insert_all
156
185
 
186
+ def touch_timestamp_attribute?(column_name)
187
+ update_duplicates? && !insert_all.updatable_columns.include?(column_name)
188
+ end
189
+
157
190
  def columns_list
158
191
  format_columns(insert_all.keys)
159
192
  end
@@ -164,11 +197,11 @@ module ActiveRecord
164
197
  unknown_column = (keys - columns.keys).first
165
198
  raise UnknownAttributeError.new(model.new, unknown_column) if unknown_column
166
199
 
167
- keys.map { |key| [ key, connection.lookup_cast_type_from_column(columns[key]) ] }.to_h
200
+ keys.index_with { |key| model.type_for_attribute(key) }
168
201
  end
169
202
 
170
203
  def format_columns(columns)
171
- quote_columns(columns).join(",")
204
+ columns.respond_to?(:map) ? quote_columns(columns).join(",") : columns
172
205
  end
173
206
 
174
207
  def quote_columns(columns)
@@ -93,7 +93,7 @@ module ActiveRecord
93
93
  # cache_version, but this method can be overwritten to return something else.
94
94
  #
95
95
  # Note, this method will return nil if ActiveRecord::Base.cache_versioning is set to
96
- # +false+ (which it is by default until Rails 6.0).
96
+ # +false+.
97
97
  def cache_version
98
98
  return unless cache_versioning
99
99
 
@@ -104,10 +104,8 @@ module ActiveRecord
104
104
  elsif timestamp = updated_at
105
105
  timestamp.utc.to_s(cache_timestamp_format)
106
106
  end
107
- else
108
- if self.class.has_attribute?("updated_at")
109
- raise ActiveModel::MissingAttributeError, "missing attribute: updated_at"
110
- end
107
+ elsif self.class.has_attribute?("updated_at")
108
+ raise ActiveModel::MissingAttributeError, "missing attribute: updated_at"
111
109
  end
112
110
  end
113
111
 
@@ -6,8 +6,15 @@ require "active_record/scoping/named"
6
6
  module ActiveRecord
7
7
  # This class is used to create a table that keeps track of values and keys such
8
8
  # as which environment migrations were run in.
9
+ #
10
+ # This is enabled by default. To disable this functionality set
11
+ # `use_metadata_table` to false in your database configuration.
9
12
  class InternalMetadata < ActiveRecord::Base # :nodoc:
10
13
  class << self
14
+ def enabled?
15
+ ActiveRecord::Base.connection.use_metadata_table?
16
+ end
17
+
11
18
  def _internal?
12
19
  true
13
20
  end
@@ -21,24 +28,24 @@ module ActiveRecord
21
28
  end
22
29
 
23
30
  def []=(key, value)
31
+ return unless enabled?
32
+
24
33
  find_or_initialize_by(key: key).update!(value: value)
25
34
  end
26
35
 
27
36
  def [](key)
28
- where(key: key).pluck(:value).first
29
- end
37
+ return unless enabled?
30
38
 
31
- def table_exists?
32
- connection.table_exists?(table_name)
39
+ where(key: key).pluck(:value).first
33
40
  end
34
41
 
35
42
  # Creates an internal metadata table with columns +key+ and +value+
36
43
  def create_table
37
- unless table_exists?
38
- key_options = connection.internal_string_options_for_primary_key
44
+ return unless enabled?
39
45
 
46
+ unless connection.table_exists?(table_name)
40
47
  connection.create_table(table_name, id: false) do |t|
41
- t.string :key, key_options
48
+ t.string :key, **connection.internal_string_options_for_primary_key
42
49
  t.string :value
43
50
  t.timestamps
44
51
  end
@@ -46,6 +53,8 @@ module ActiveRecord
46
53
  end
47
54
 
48
55
  def drop_table
56
+ return unless enabled?
57
+
49
58
  connection.drop_table table_name, if_exists: true
50
59
  end
51
60
  end
@@ -1,13 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
- module LegacyYamlAdapter
4
+ module LegacyYamlAdapter # :nodoc:
5
5
  def self.convert(klass, coder)
6
6
  return coder unless coder.is_a?(Psych::Coder)
7
7
 
8
8
  case coder["active_record_yaml_version"]
9
9
  when 1, 2 then coder
10
10
  else
11
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
12
+ YAML loading from legacy format older than Rails 5.0 is deprecated
13
+ and will be removed in Rails 6.2.
14
+ MSG
11
15
  if coder["attributes"].is_a?(ActiveModel::AttributeSet)
12
16
  Rails420.convert(klass, coder)
13
17
  else
@@ -16,7 +20,7 @@ module ActiveRecord
16
20
  end
17
21
  end
18
22
 
19
- module Rails420
23
+ module Rails420 # :nodoc:
20
24
  def self.convert(klass, coder)
21
25
  attribute_set = coder["attributes"]
22
26
 
@@ -32,7 +36,7 @@ module ActiveRecord
32
36
  end
33
37
  end
34
38
 
35
- module Rails41
39
+ module Rails41 # :nodoc:
36
40
  def self.convert(klass, coder)
37
41
  attributes = klass.attributes_builder
38
42
  .build_from_database(coder["attributes"])