activerecord 7.0.8 → 7.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (277) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +530 -2004
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +29 -29
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record/aggregations.rb +16 -13
  7. data/lib/active_record/association_relation.rb +2 -2
  8. data/lib/active_record/associations/alias_tracker.rb +25 -19
  9. data/lib/active_record/associations/association.rb +35 -12
  10. data/lib/active_record/associations/association_scope.rb +16 -9
  11. data/lib/active_record/associations/belongs_to_association.rb +23 -8
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
  13. data/lib/active_record/associations/builder/association.rb +3 -3
  14. data/lib/active_record/associations/builder/belongs_to.rb +22 -8
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
  16. data/lib/active_record/associations/builder/has_many.rb +3 -4
  17. data/lib/active_record/associations/builder/has_one.rb +3 -4
  18. data/lib/active_record/associations/builder/singular_association.rb +4 -0
  19. data/lib/active_record/associations/collection_association.rb +26 -14
  20. data/lib/active_record/associations/collection_proxy.rb +29 -11
  21. data/lib/active_record/associations/errors.rb +265 -0
  22. data/lib/active_record/associations/foreign_association.rb +10 -3
  23. data/lib/active_record/associations/has_many_association.rb +21 -14
  24. data/lib/active_record/associations/has_many_through_association.rb +10 -6
  25. data/lib/active_record/associations/has_one_association.rb +10 -3
  26. data/lib/active_record/associations/join_dependency/join_association.rb +27 -25
  27. data/lib/active_record/associations/join_dependency.rb +5 -5
  28. data/lib/active_record/associations/nested_error.rb +47 -0
  29. data/lib/active_record/associations/preloader/association.rb +33 -8
  30. data/lib/active_record/associations/preloader/branch.rb +7 -1
  31. data/lib/active_record/associations/preloader/through_association.rb +1 -3
  32. data/lib/active_record/associations/preloader.rb +13 -10
  33. data/lib/active_record/associations/singular_association.rb +7 -1
  34. data/lib/active_record/associations/through_association.rb +22 -11
  35. data/lib/active_record/associations.rb +328 -471
  36. data/lib/active_record/attribute_assignment.rb +1 -13
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
  38. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  39. data/lib/active_record/attribute_methods/dirty.rb +53 -35
  40. data/lib/active_record/attribute_methods/primary_key.rb +45 -25
  41. data/lib/active_record/attribute_methods/query.rb +28 -16
  42. data/lib/active_record/attribute_methods/read.rb +8 -7
  43. data/lib/active_record/attribute_methods/serialization.rb +131 -32
  44. data/lib/active_record/attribute_methods/time_zone_conversion.rb +7 -6
  45. data/lib/active_record/attribute_methods/write.rb +6 -6
  46. data/lib/active_record/attribute_methods.rb +148 -33
  47. data/lib/active_record/attributes.rb +58 -45
  48. data/lib/active_record/autosave_association.rb +69 -37
  49. data/lib/active_record/base.rb +9 -5
  50. data/lib/active_record/callbacks.rb +10 -24
  51. data/lib/active_record/coders/column_serializer.rb +61 -0
  52. data/lib/active_record/coders/json.rb +1 -1
  53. data/lib/active_record/coders/yaml_column.rb +70 -42
  54. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +123 -131
  55. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +4 -1
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +317 -88
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +160 -45
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +188 -63
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +72 -63
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -11
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +306 -128
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +367 -75
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +510 -111
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +274 -125
  69. data/lib/active_record/connection_adapters/column.rb +9 -0
  70. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  71. data/lib/active_record/connection_adapters/mysql/database_statements.rb +26 -139
  72. data/lib/active_record/connection_adapters/mysql/quoting.rb +53 -54
  73. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +6 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
  76. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +25 -13
  77. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
  78. data/lib/active_record/connection_adapters/mysql2_adapter.rb +101 -68
  79. data/lib/active_record/connection_adapters/pool_config.rb +20 -10
  80. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +14 -3
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +100 -43
  83. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
  87. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +1 -1
  88. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
  89. data/lib/active_record/connection_adapters/postgresql/quoting.rb +65 -61
  90. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
  91. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
  92. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +151 -2
  93. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
  94. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +368 -63
  95. data/lib/active_record/connection_adapters/postgresql_adapter.rb +364 -198
  96. data/lib/active_record/connection_adapters/schema_cache.rb +302 -79
  97. data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
  98. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +60 -43
  99. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +45 -46
  100. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  101. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +14 -0
  102. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
  103. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +50 -8
  104. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +290 -110
  105. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  106. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  107. data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
  108. data/lib/active_record/connection_adapters.rb +124 -1
  109. data/lib/active_record/connection_handling.rb +96 -104
  110. data/lib/active_record/core.rb +217 -174
  111. data/lib/active_record/counter_cache.rb +68 -34
  112. data/lib/active_record/database_configurations/connection_url_resolver.rb +7 -2
  113. data/lib/active_record/database_configurations/database_config.rb +26 -5
  114. data/lib/active_record/database_configurations/hash_config.rb +52 -34
  115. data/lib/active_record/database_configurations/url_config.rb +37 -12
  116. data/lib/active_record/database_configurations.rb +87 -34
  117. data/lib/active_record/delegated_type.rb +39 -10
  118. data/lib/active_record/deprecator.rb +7 -0
  119. data/lib/active_record/destroy_association_async_job.rb +3 -1
  120. data/lib/active_record/dynamic_matchers.rb +2 -2
  121. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  122. data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
  123. data/lib/active_record/encryption/config.rb +25 -1
  124. data/lib/active_record/encryption/configurable.rb +12 -19
  125. data/lib/active_record/encryption/context.rb +10 -3
  126. data/lib/active_record/encryption/contexts.rb +5 -1
  127. data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
  128. data/lib/active_record/encryption/encryptable_record.rb +44 -20
  129. data/lib/active_record/encryption/encrypted_attribute_type.rb +45 -10
  130. data/lib/active_record/encryption/encryptor.rb +17 -2
  131. data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -69
  132. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +3 -3
  133. data/lib/active_record/encryption/key_generator.rb +12 -1
  134. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  135. data/lib/active_record/encryption/message_serializer.rb +6 -0
  136. data/lib/active_record/encryption/null_encryptor.rb +4 -0
  137. data/lib/active_record/encryption/properties.rb +3 -3
  138. data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
  139. data/lib/active_record/encryption/scheme.rb +22 -21
  140. data/lib/active_record/encryption.rb +1 -0
  141. data/lib/active_record/enum.rb +122 -29
  142. data/lib/active_record/errors.rb +151 -31
  143. data/lib/active_record/explain.rb +21 -12
  144. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  145. data/lib/active_record/fixture_set/render_context.rb +2 -0
  146. data/lib/active_record/fixture_set/table_row.rb +29 -8
  147. data/lib/active_record/fixtures.rb +167 -97
  148. data/lib/active_record/future_result.rb +47 -8
  149. data/lib/active_record/gem_version.rb +3 -3
  150. data/lib/active_record/inheritance.rb +34 -18
  151. data/lib/active_record/insert_all.rb +72 -22
  152. data/lib/active_record/integration.rb +11 -8
  153. data/lib/active_record/internal_metadata.rb +124 -20
  154. data/lib/active_record/locking/optimistic.rb +8 -7
  155. data/lib/active_record/locking/pessimistic.rb +5 -2
  156. data/lib/active_record/log_subscriber.rb +18 -22
  157. data/lib/active_record/marshalling.rb +56 -0
  158. data/lib/active_record/message_pack.rb +124 -0
  159. data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
  160. data/lib/active_record/middleware/database_selector.rb +6 -8
  161. data/lib/active_record/middleware/shard_selector.rb +3 -1
  162. data/lib/active_record/migration/command_recorder.rb +106 -8
  163. data/lib/active_record/migration/compatibility.rb +147 -5
  164. data/lib/active_record/migration/default_strategy.rb +22 -0
  165. data/lib/active_record/migration/execution_strategy.rb +19 -0
  166. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  167. data/lib/active_record/migration.rb +234 -117
  168. data/lib/active_record/model_schema.rb +88 -103
  169. data/lib/active_record/nested_attributes.rb +35 -9
  170. data/lib/active_record/normalization.rb +163 -0
  171. data/lib/active_record/persistence.rb +168 -339
  172. data/lib/active_record/promise.rb +84 -0
  173. data/lib/active_record/query_cache.rb +19 -25
  174. data/lib/active_record/query_logs.rb +92 -52
  175. data/lib/active_record/query_logs_formatter.rb +41 -0
  176. data/lib/active_record/querying.rb +33 -8
  177. data/lib/active_record/railtie.rb +135 -86
  178. data/lib/active_record/railties/controller_runtime.rb +22 -7
  179. data/lib/active_record/railties/databases.rake +145 -154
  180. data/lib/active_record/railties/job_runtime.rb +23 -0
  181. data/lib/active_record/readonly_attributes.rb +32 -5
  182. data/lib/active_record/reflection.rb +259 -68
  183. data/lib/active_record/relation/batches/batch_enumerator.rb +20 -5
  184. data/lib/active_record/relation/batches.rb +196 -61
  185. data/lib/active_record/relation/calculations.rb +249 -92
  186. data/lib/active_record/relation/delegation.rb +30 -19
  187. data/lib/active_record/relation/finder_methods.rb +93 -18
  188. data/lib/active_record/relation/merger.rb +6 -6
  189. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  190. data/lib/active_record/relation/predicate_builder/association_query_value.rb +18 -3
  191. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
  192. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  193. data/lib/active_record/relation/predicate_builder.rb +28 -16
  194. data/lib/active_record/relation/query_attribute.rb +2 -1
  195. data/lib/active_record/relation/query_methods.rb +548 -94
  196. data/lib/active_record/relation/record_fetch_warning.rb +3 -0
  197. data/lib/active_record/relation/spawn_methods.rb +5 -4
  198. data/lib/active_record/relation/where_clause.rb +7 -19
  199. data/lib/active_record/relation.rb +580 -90
  200. data/lib/active_record/result.rb +49 -48
  201. data/lib/active_record/runtime_registry.rb +63 -1
  202. data/lib/active_record/sanitization.rb +70 -25
  203. data/lib/active_record/schema.rb +8 -7
  204. data/lib/active_record/schema_dumper.rb +63 -14
  205. data/lib/active_record/schema_migration.rb +75 -24
  206. data/lib/active_record/scoping/default.rb +15 -5
  207. data/lib/active_record/scoping/named.rb +2 -2
  208. data/lib/active_record/scoping.rb +2 -1
  209. data/lib/active_record/secure_password.rb +60 -0
  210. data/lib/active_record/secure_token.rb +21 -3
  211. data/lib/active_record/signed_id.rb +27 -6
  212. data/lib/active_record/statement_cache.rb +7 -7
  213. data/lib/active_record/store.rb +8 -8
  214. data/lib/active_record/suppressor.rb +3 -1
  215. data/lib/active_record/table_metadata.rb +1 -1
  216. data/lib/active_record/tasks/database_tasks.rb +180 -119
  217. data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
  218. data/lib/active_record/tasks/postgresql_database_tasks.rb +16 -13
  219. data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
  220. data/lib/active_record/test_fixtures.rb +170 -155
  221. data/lib/active_record/testing/query_assertions.rb +121 -0
  222. data/lib/active_record/timestamp.rb +31 -17
  223. data/lib/active_record/token_for.rb +123 -0
  224. data/lib/active_record/touch_later.rb +12 -7
  225. data/lib/active_record/transaction.rb +132 -0
  226. data/lib/active_record/transactions.rb +106 -24
  227. data/lib/active_record/translation.rb +0 -2
  228. data/lib/active_record/type/adapter_specific_registry.rb +1 -8
  229. data/lib/active_record/type/internal/timezone.rb +7 -2
  230. data/lib/active_record/type/serialized.rb +1 -3
  231. data/lib/active_record/type/time.rb +4 -0
  232. data/lib/active_record/type_caster/connection.rb +4 -4
  233. data/lib/active_record/validations/absence.rb +1 -1
  234. data/lib/active_record/validations/associated.rb +9 -3
  235. data/lib/active_record/validations/numericality.rb +5 -4
  236. data/lib/active_record/validations/presence.rb +5 -28
  237. data/lib/active_record/validations/uniqueness.rb +60 -11
  238. data/lib/active_record/validations.rb +12 -5
  239. data/lib/active_record/version.rb +1 -1
  240. data/lib/active_record.rb +247 -33
  241. data/lib/arel/alias_predication.rb +1 -1
  242. data/lib/arel/collectors/bind.rb +2 -0
  243. data/lib/arel/collectors/composite.rb +7 -0
  244. data/lib/arel/collectors/sql_string.rb +1 -1
  245. data/lib/arel/collectors/substitute_binds.rb +1 -1
  246. data/lib/arel/errors.rb +10 -0
  247. data/lib/arel/factory_methods.rb +4 -0
  248. data/lib/arel/nodes/binary.rb +6 -7
  249. data/lib/arel/nodes/bound_sql_literal.rb +65 -0
  250. data/lib/arel/nodes/cte.rb +36 -0
  251. data/lib/arel/nodes/fragments.rb +35 -0
  252. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  253. data/lib/arel/nodes/leading_join.rb +8 -0
  254. data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
  255. data/lib/arel/nodes/node.rb +115 -5
  256. data/lib/arel/nodes/sql_literal.rb +13 -0
  257. data/lib/arel/nodes/table_alias.rb +4 -0
  258. data/lib/arel/nodes.rb +6 -2
  259. data/lib/arel/predications.rb +3 -1
  260. data/lib/arel/select_manager.rb +1 -1
  261. data/lib/arel/table.rb +9 -5
  262. data/lib/arel/tree_manager.rb +8 -3
  263. data/lib/arel/update_manager.rb +2 -1
  264. data/lib/arel/visitors/dot.rb +1 -0
  265. data/lib/arel/visitors/mysql.rb +17 -5
  266. data/lib/arel/visitors/postgresql.rb +1 -12
  267. data/lib/arel/visitors/to_sql.rb +112 -34
  268. data/lib/arel/visitors/visitor.rb +2 -2
  269. data/lib/arel.rb +21 -3
  270. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  271. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
  272. data/lib/rails/generators/active_record/migration.rb +3 -1
  273. data/lib/rails/generators/active_record/model/USAGE +113 -0
  274. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  275. metadata +56 -14
  276. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  277. data/lib/active_record/null_relation.rb +0 -63
@@ -16,17 +16,18 @@ module ActiveRecord
16
16
 
17
17
  # Makes the adapter execute EXPLAIN for the tuples of queries and bindings.
18
18
  # Returns a formatted string ready to be logged.
19
- def exec_explain(queries) # :nodoc:
20
- str = queries.map do |sql, binds|
21
- msg = +"EXPLAIN for: #{sql}"
22
- unless binds.empty?
23
- msg << " "
24
- msg << binds.map { |attr| render_bind(attr) }.inspect
25
- end
26
- msg << "\n"
27
- msg << connection.explain(sql, binds)
28
- end.join("\n")
29
-
19
+ def exec_explain(queries, options = []) # :nodoc:
20
+ str = with_connection do |c|
21
+ queries.map do |sql, binds|
22
+ msg = +"#{build_explain_clause(c, options)} #{sql}"
23
+ unless binds.empty?
24
+ msg << " "
25
+ msg << binds.map { |attr| render_bind(c, attr) }.inspect
26
+ end
27
+ msg << "\n"
28
+ msg << c.explain(sql, binds, options)
29
+ end.join("\n")
30
+ end
30
31
  # Overriding inspect to be more human readable, especially in the console.
31
32
  def str.inspect
32
33
  self
@@ -36,7 +37,7 @@ module ActiveRecord
36
37
  end
37
38
 
38
39
  private
39
- def render_bind(attr)
40
+ def render_bind(connection, attr)
40
41
  if ActiveModel::Attribute === attr
41
42
  value = if attr.type.binary? && attr.value
42
43
  "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
@@ -50,5 +51,13 @@ module ActiveRecord
50
51
 
51
52
  [attr&.name, value]
52
53
  end
54
+
55
+ def build_explain_clause(connection, options = [])
56
+ if connection.respond_to?(:build_explain_clause, true)
57
+ connection.build_explain_clause(options)
58
+ else
59
+ "EXPLAIN for:"
60
+ end
61
+ end
53
62
  end
54
63
  end
@@ -12,12 +12,22 @@ module ActiveRecord
12
12
  end
13
13
 
14
14
  def primary_key_type
15
- @primary_key_type ||= @model_class && @model_class.type_for_attribute(@model_class.primary_key).type
15
+ @primary_key_type ||= @model_class && column_type(@model_class.primary_key)
16
16
  end
17
17
 
18
- def has_primary_key_column?
19
- @has_primary_key_column ||= primary_key_name &&
20
- @model_class.columns.any? { |col| col.name == primary_key_name }
18
+ def column_type(column_name)
19
+ @column_type ||= {}
20
+ return @column_type[column_name] if @column_type.key?(column_name)
21
+
22
+ @column_type[column_name] = @model_class && @model_class.type_for_attribute(column_name).type
23
+ end
24
+
25
+ def has_column?(column_name)
26
+ column_names.include?(column_name)
27
+ end
28
+
29
+ def column_names
30
+ @column_names ||= @model_class ? @model_class.columns.map(&:name).to_set : Set.new
21
31
  end
22
32
 
23
33
  def timestamp_column_names
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "base64"
4
+
3
5
  # NOTE: This class has to be defined in compact style in
4
6
  # order for rendering context subclassing to work correctly.
5
7
  class ActiveRecord::FixtureSet::RenderContext # :nodoc:
@@ -87,7 +87,7 @@ module ActiveRecord
87
87
  return unless model_class
88
88
  fill_timestamps
89
89
  interpolate_label
90
- generate_primary_key
90
+ model_class.composite_primary_key? ? generate_composite_primary_key : generate_primary_key
91
91
  resolve_enums
92
92
  resolve_sti_reflections
93
93
  end
@@ -117,14 +117,26 @@ module ActiveRecord
117
117
  end
118
118
 
119
119
  def generate_primary_key
120
- # generate a primary key if necessary
121
- if model_metadata.has_primary_key_column? && !@row.include?(model_metadata.primary_key_name)
122
- @row[model_metadata.primary_key_name] = ActiveRecord::FixtureSet.identify(
123
- @label, model_metadata.primary_key_type
124
- )
120
+ pk = model_metadata.primary_key_name
121
+
122
+ unless column_defined?(pk)
123
+ @row[pk] = ActiveRecord::FixtureSet.identify(@label, model_metadata.column_type(pk))
124
+ end
125
+ end
126
+
127
+ def generate_composite_primary_key
128
+ composite_key = ActiveRecord::FixtureSet.composite_identify(@label, model_metadata.primary_key_name)
129
+ composite_key.each do |column, value|
130
+ next if column_defined?(column)
131
+
132
+ @row[column] = value
125
133
  end
126
134
  end
127
135
 
136
+ def column_defined?(col)
137
+ !model_metadata.has_column?(col) || @row.include?(col)
138
+ end
139
+
128
140
  def resolve_enums
129
141
  reflection_class.defined_enums.each do |name, values|
130
142
  if @row.include?(name)
@@ -151,8 +163,17 @@ module ActiveRecord
151
163
  raise PrimaryKeyError.new(@label, association, value)
152
164
  end
153
165
 
154
- fk_type = reflection_class.type_for_attribute(fk_name).type
155
- @row[fk_name] = ActiveRecord::FixtureSet.identify(value, fk_type)
166
+ if fk_name.is_a?(Array)
167
+ composite_key = ActiveRecord::FixtureSet.composite_identify(value, fk_name)
168
+ composite_key.each do |column, value|
169
+ next if column_defined?(column)
170
+
171
+ @row[column] = value
172
+ end
173
+ else
174
+ fk_type = reflection_class.type_for_attribute(fk_name).type
175
+ @row[fk_name] = ActiveRecord::FixtureSet.identify(value, fk_type)
176
+ end
156
177
  end
157
178
  when :has_many
158
179
  if association.options[:through]