activerecord 5.2.6 → 6.0.5

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 (294) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +928 -559
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +5 -3
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/advisory_lock_base.rb +18 -0
  7. data/lib/active_record/aggregations.rb +4 -3
  8. data/lib/active_record/association_relation.rb +10 -8
  9. data/lib/active_record/associations/alias_tracker.rb +0 -1
  10. data/lib/active_record/associations/association.rb +55 -19
  11. data/lib/active_record/associations/association_scope.rb +11 -7
  12. data/lib/active_record/associations/belongs_to_association.rb +36 -42
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
  14. data/lib/active_record/associations/builder/association.rb +14 -18
  15. data/lib/active_record/associations/builder/belongs_to.rb +19 -52
  16. data/lib/active_record/associations/builder/collection_association.rb +3 -13
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -40
  18. data/lib/active_record/associations/builder/has_many.rb +2 -0
  19. data/lib/active_record/associations/builder/has_one.rb +35 -1
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  21. data/lib/active_record/associations/collection_association.rb +19 -23
  22. data/lib/active_record/associations/collection_proxy.rb +14 -17
  23. data/lib/active_record/associations/foreign_association.rb +7 -0
  24. data/lib/active_record/associations/has_many_association.rb +2 -11
  25. data/lib/active_record/associations/has_many_through_association.rb +14 -14
  26. data/lib/active_record/associations/has_one_association.rb +28 -30
  27. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  28. data/lib/active_record/associations/join_dependency/join_association.rb +16 -10
  29. data/lib/active_record/associations/join_dependency/join_part.rb +4 -4
  30. data/lib/active_record/associations/join_dependency.rb +47 -30
  31. data/lib/active_record/associations/preloader/association.rb +61 -41
  32. data/lib/active_record/associations/preloader/through_association.rb +48 -39
  33. data/lib/active_record/associations/preloader.rb +44 -33
  34. data/lib/active_record/associations/singular_association.rb +2 -16
  35. data/lib/active_record/associations/through_association.rb +1 -1
  36. data/lib/active_record/associations.rb +21 -16
  37. data/lib/active_record/attribute_assignment.rb +7 -11
  38. data/lib/active_record/attribute_decorators.rb +0 -2
  39. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -2
  40. data/lib/active_record/attribute_methods/dirty.rb +111 -40
  41. data/lib/active_record/attribute_methods/primary_key.rb +15 -24
  42. data/lib/active_record/attribute_methods/query.rb +2 -3
  43. data/lib/active_record/attribute_methods/read.rb +15 -54
  44. data/lib/active_record/attribute_methods/serialization.rb +1 -2
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -3
  46. data/lib/active_record/attribute_methods/write.rb +17 -25
  47. data/lib/active_record/attribute_methods.rb +28 -100
  48. data/lib/active_record/attributes.rb +13 -1
  49. data/lib/active_record/autosave_association.rb +12 -14
  50. data/lib/active_record/base.rb +2 -3
  51. data/lib/active_record/callbacks.rb +6 -21
  52. data/lib/active_record/coders/yaml_column.rb +0 -1
  53. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +109 -18
  54. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
  55. data/lib/active_record/connection_adapters/abstract/database_statements.rb +102 -124
  56. data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -9
  57. data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
  58. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +20 -14
  59. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +105 -72
  60. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
  61. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +175 -79
  62. data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -57
  63. data/lib/active_record/connection_adapters/abstract_adapter.rb +197 -43
  64. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -217
  65. data/lib/active_record/connection_adapters/column.rb +17 -13
  66. data/lib/active_record/connection_adapters/connection_specification.rb +54 -45
  67. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
  68. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  69. data/lib/active_record/connection_adapters/mysql/database_statements.rb +70 -14
  70. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +0 -1
  71. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  72. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +4 -6
  73. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
  74. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
  75. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +139 -19
  76. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  77. data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -10
  78. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
  79. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +26 -1
  80. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  81. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  82. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +8 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
  89. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  91. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
  92. data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
  93. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  94. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -3
  95. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  96. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  97. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +63 -75
  98. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
  99. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  100. data/lib/active_record/connection_adapters/postgresql_adapter.rb +168 -75
  101. data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
  102. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  103. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +119 -0
  104. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
  105. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -12
  106. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +137 -147
  107. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  108. data/lib/active_record/connection_handling.rb +139 -26
  109. data/lib/active_record/core.rb +107 -66
  110. data/lib/active_record/counter_cache.rb +8 -30
  111. data/lib/active_record/database_configurations/database_config.rb +37 -0
  112. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  113. data/lib/active_record/database_configurations/url_config.rb +78 -0
  114. data/lib/active_record/database_configurations.rb +233 -0
  115. data/lib/active_record/dynamic_matchers.rb +3 -4
  116. data/lib/active_record/enum.rb +44 -7
  117. data/lib/active_record/errors.rb +15 -7
  118. data/lib/active_record/explain.rb +1 -2
  119. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  120. data/lib/active_record/fixture_set/render_context.rb +17 -0
  121. data/lib/active_record/fixture_set/table_row.rb +152 -0
  122. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  123. data/lib/active_record/fixtures.rb +144 -474
  124. data/lib/active_record/gem_version.rb +3 -3
  125. data/lib/active_record/inheritance.rb +13 -6
  126. data/lib/active_record/insert_all.rb +179 -0
  127. data/lib/active_record/integration.rb +68 -16
  128. data/lib/active_record/internal_metadata.rb +11 -3
  129. data/lib/active_record/locking/optimistic.rb +14 -7
  130. data/lib/active_record/locking/pessimistic.rb +3 -3
  131. data/lib/active_record/log_subscriber.rb +8 -27
  132. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  133. data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
  134. data/lib/active_record/middleware/database_selector.rb +74 -0
  135. data/lib/active_record/migration/command_recorder.rb +54 -22
  136. data/lib/active_record/migration/compatibility.rb +79 -52
  137. data/lib/active_record/migration/join_table.rb +0 -1
  138. data/lib/active_record/migration.rb +104 -85
  139. data/lib/active_record/model_schema.rb +62 -11
  140. data/lib/active_record/nested_attributes.rb +2 -4
  141. data/lib/active_record/no_touching.rb +9 -2
  142. data/lib/active_record/null_relation.rb +0 -1
  143. data/lib/active_record/persistence.rb +232 -29
  144. data/lib/active_record/query_cache.rb +11 -4
  145. data/lib/active_record/querying.rb +33 -21
  146. data/lib/active_record/railtie.rb +80 -43
  147. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  148. data/lib/active_record/railties/controller_runtime.rb +30 -35
  149. data/lib/active_record/railties/databases.rake +199 -46
  150. data/lib/active_record/reflection.rb +51 -51
  151. data/lib/active_record/relation/batches.rb +13 -11
  152. data/lib/active_record/relation/calculations.rb +55 -49
  153. data/lib/active_record/relation/delegation.rb +35 -50
  154. data/lib/active_record/relation/finder_methods.rb +23 -28
  155. data/lib/active_record/relation/from_clause.rb +4 -0
  156. data/lib/active_record/relation/merger.rb +12 -17
  157. data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
  158. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
  159. data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
  160. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  161. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
  162. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  163. data/lib/active_record/relation/predicate_builder.rb +5 -11
  164. data/lib/active_record/relation/query_attribute.rb +13 -8
  165. data/lib/active_record/relation/query_methods.rb +232 -69
  166. data/lib/active_record/relation/spawn_methods.rb +1 -2
  167. data/lib/active_record/relation/where_clause.rb +14 -11
  168. data/lib/active_record/relation/where_clause_factory.rb +1 -2
  169. data/lib/active_record/relation.rb +326 -81
  170. data/lib/active_record/result.rb +30 -12
  171. data/lib/active_record/sanitization.rb +32 -40
  172. data/lib/active_record/schema.rb +2 -11
  173. data/lib/active_record/schema_dumper.rb +22 -7
  174. data/lib/active_record/schema_migration.rb +6 -2
  175. data/lib/active_record/scoping/default.rb +4 -6
  176. data/lib/active_record/scoping/named.rb +25 -16
  177. data/lib/active_record/scoping.rb +8 -9
  178. data/lib/active_record/statement_cache.rb +30 -3
  179. data/lib/active_record/store.rb +87 -8
  180. data/lib/active_record/suppressor.rb +2 -2
  181. data/lib/active_record/table_metadata.rb +23 -15
  182. data/lib/active_record/tasks/database_tasks.rb +194 -25
  183. data/lib/active_record/tasks/mysql_database_tasks.rb +5 -6
  184. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -8
  185. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -9
  186. data/lib/active_record/test_databases.rb +23 -0
  187. data/lib/active_record/test_fixtures.rb +243 -0
  188. data/lib/active_record/timestamp.rb +39 -26
  189. data/lib/active_record/touch_later.rb +5 -4
  190. data/lib/active_record/transactions.rb +64 -73
  191. data/lib/active_record/translation.rb +1 -1
  192. data/lib/active_record/type/adapter_specific_registry.rb +3 -13
  193. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  194. data/lib/active_record/type/serialized.rb +0 -1
  195. data/lib/active_record/type/time.rb +10 -0
  196. data/lib/active_record/type/type_map.rb +0 -1
  197. data/lib/active_record/type/unsigned_integer.rb +0 -1
  198. data/lib/active_record/type.rb +3 -5
  199. data/lib/active_record/type_caster/connection.rb +15 -14
  200. data/lib/active_record/type_caster/map.rb +1 -4
  201. data/lib/active_record/validations/associated.rb +0 -1
  202. data/lib/active_record/validations/uniqueness.rb +15 -27
  203. data/lib/active_record/validations.rb +3 -3
  204. data/lib/active_record.rb +10 -2
  205. data/lib/arel/alias_predication.rb +9 -0
  206. data/lib/arel/attributes/attribute.rb +37 -0
  207. data/lib/arel/attributes.rb +22 -0
  208. data/lib/arel/collectors/bind.rb +24 -0
  209. data/lib/arel/collectors/composite.rb +31 -0
  210. data/lib/arel/collectors/plain_string.rb +20 -0
  211. data/lib/arel/collectors/sql_string.rb +20 -0
  212. data/lib/arel/collectors/substitute_binds.rb +28 -0
  213. data/lib/arel/crud.rb +42 -0
  214. data/lib/arel/delete_manager.rb +18 -0
  215. data/lib/arel/errors.rb +9 -0
  216. data/lib/arel/expressions.rb +29 -0
  217. data/lib/arel/factory_methods.rb +49 -0
  218. data/lib/arel/insert_manager.rb +49 -0
  219. data/lib/arel/math.rb +45 -0
  220. data/lib/arel/nodes/and.rb +32 -0
  221. data/lib/arel/nodes/ascending.rb +23 -0
  222. data/lib/arel/nodes/binary.rb +52 -0
  223. data/lib/arel/nodes/bind_param.rb +36 -0
  224. data/lib/arel/nodes/case.rb +55 -0
  225. data/lib/arel/nodes/casted.rb +50 -0
  226. data/lib/arel/nodes/comment.rb +29 -0
  227. data/lib/arel/nodes/count.rb +12 -0
  228. data/lib/arel/nodes/delete_statement.rb +45 -0
  229. data/lib/arel/nodes/descending.rb +23 -0
  230. data/lib/arel/nodes/equality.rb +18 -0
  231. data/lib/arel/nodes/extract.rb +24 -0
  232. data/lib/arel/nodes/false.rb +16 -0
  233. data/lib/arel/nodes/full_outer_join.rb +8 -0
  234. data/lib/arel/nodes/function.rb +44 -0
  235. data/lib/arel/nodes/grouping.rb +8 -0
  236. data/lib/arel/nodes/in.rb +8 -0
  237. data/lib/arel/nodes/infix_operation.rb +80 -0
  238. data/lib/arel/nodes/inner_join.rb +8 -0
  239. data/lib/arel/nodes/insert_statement.rb +37 -0
  240. data/lib/arel/nodes/join_source.rb +20 -0
  241. data/lib/arel/nodes/matches.rb +18 -0
  242. data/lib/arel/nodes/named_function.rb +23 -0
  243. data/lib/arel/nodes/node.rb +50 -0
  244. data/lib/arel/nodes/node_expression.rb +13 -0
  245. data/lib/arel/nodes/outer_join.rb +8 -0
  246. data/lib/arel/nodes/over.rb +15 -0
  247. data/lib/arel/nodes/regexp.rb +16 -0
  248. data/lib/arel/nodes/right_outer_join.rb +8 -0
  249. data/lib/arel/nodes/select_core.rb +67 -0
  250. data/lib/arel/nodes/select_statement.rb +41 -0
  251. data/lib/arel/nodes/sql_literal.rb +16 -0
  252. data/lib/arel/nodes/string_join.rb +11 -0
  253. data/lib/arel/nodes/table_alias.rb +27 -0
  254. data/lib/arel/nodes/terminal.rb +16 -0
  255. data/lib/arel/nodes/true.rb +16 -0
  256. data/lib/arel/nodes/unary.rb +45 -0
  257. data/lib/arel/nodes/unary_operation.rb +20 -0
  258. data/lib/arel/nodes/unqualified_column.rb +22 -0
  259. data/lib/arel/nodes/update_statement.rb +41 -0
  260. data/lib/arel/nodes/values_list.rb +9 -0
  261. data/lib/arel/nodes/window.rb +126 -0
  262. data/lib/arel/nodes/with.rb +11 -0
  263. data/lib/arel/nodes.rb +68 -0
  264. data/lib/arel/order_predications.rb +13 -0
  265. data/lib/arel/predications.rb +256 -0
  266. data/lib/arel/select_manager.rb +271 -0
  267. data/lib/arel/table.rb +110 -0
  268. data/lib/arel/tree_manager.rb +72 -0
  269. data/lib/arel/update_manager.rb +34 -0
  270. data/lib/arel/visitors/depth_first.rb +203 -0
  271. data/lib/arel/visitors/dot.rb +296 -0
  272. data/lib/arel/visitors/ibm_db.rb +34 -0
  273. data/lib/arel/visitors/informix.rb +62 -0
  274. data/lib/arel/visitors/mssql.rb +156 -0
  275. data/lib/arel/visitors/mysql.rb +83 -0
  276. data/lib/arel/visitors/oracle.rb +158 -0
  277. data/lib/arel/visitors/oracle12.rb +65 -0
  278. data/lib/arel/visitors/postgresql.rb +109 -0
  279. data/lib/arel/visitors/sqlite.rb +38 -0
  280. data/lib/arel/visitors/to_sql.rb +888 -0
  281. data/lib/arel/visitors/visitor.rb +45 -0
  282. data/lib/arel/visitors/where_sql.rb +22 -0
  283. data/lib/arel/visitors.rb +20 -0
  284. data/lib/arel/window_predications.rb +9 -0
  285. data/lib/arel.rb +62 -0
  286. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  287. data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
  288. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  289. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  290. data/lib/rails/generators/active_record/migration.rb +14 -2
  291. data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
  292. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  293. metadata +116 -29
  294. data/lib/active_record/collection_cache_key.rb +0 -53
@@ -7,6 +7,9 @@ require "set"
7
7
  require "active_support/dependencies"
8
8
  require "active_support/core_ext/digest/uuid"
9
9
  require "active_record/fixture_set/file"
10
+ require "active_record/fixture_set/render_context"
11
+ require "active_record/fixture_set/table_rows"
12
+ require "active_record/test_fixtures"
10
13
  require "active_record/errors"
11
14
 
12
15
  module ActiveRecord
@@ -179,8 +182,8 @@ module ActiveRecord
179
182
  # end
180
183
  # end
181
184
  #
182
- # If you preload your test database with all fixture data (probably in the rake task) and use
183
- # transactional tests, then you may omit all fixtures declarations in your test cases since
185
+ # If you preload your test database with all fixture data (probably by running `rails db:fixtures:load`)
186
+ # and use transactional tests, then you may omit all fixtures declarations in your test cases since
184
187
  # all the data's already there and every case rolls back its changes.
185
188
  #
186
189
  # In order to use instantiated fixtures with preloaded data, set +self.pre_loaded_fixtures+ to
@@ -440,60 +443,6 @@ module ActiveRecord
440
443
 
441
444
  @@all_cached_fixtures = Hash.new { |h, k| h[k] = {} }
442
445
 
443
- def self.default_fixture_model_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
444
- config.pluralize_table_names ?
445
- fixture_set_name.singularize.camelize :
446
- fixture_set_name.camelize
447
- end
448
-
449
- def self.default_fixture_table_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
450
- "#{ config.table_name_prefix }"\
451
- "#{ fixture_set_name.tr('/', '_') }"\
452
- "#{ config.table_name_suffix }".to_sym
453
- end
454
-
455
- def self.reset_cache
456
- @@all_cached_fixtures.clear
457
- end
458
-
459
- def self.cache_for_connection(connection)
460
- @@all_cached_fixtures[connection]
461
- end
462
-
463
- def self.fixture_is_cached?(connection, table_name)
464
- cache_for_connection(connection)[table_name]
465
- end
466
-
467
- def self.cached_fixtures(connection, keys_to_fetch = nil)
468
- if keys_to_fetch
469
- cache_for_connection(connection).values_at(*keys_to_fetch)
470
- else
471
- cache_for_connection(connection).values
472
- end
473
- end
474
-
475
- def self.cache_fixtures(connection, fixtures_map)
476
- cache_for_connection(connection).update(fixtures_map)
477
- end
478
-
479
- def self.instantiate_fixtures(object, fixture_set, load_instances = true)
480
- if load_instances
481
- fixture_set.each do |fixture_name, fixture|
482
- begin
483
- object.instance_variable_set "@#{fixture_name}", fixture.find
484
- rescue FixtureClassNotFound
485
- nil
486
- end
487
- end
488
- end
489
- end
490
-
491
- def self.instantiate_all_loaded_fixtures(object, load_instances = true)
492
- all_loaded_fixtures.each_value do |fixture_set|
493
- instantiate_fixtures(object, fixture_set, load_instances)
494
- end
495
- end
496
-
497
446
  cattr_accessor :all_loaded_fixtures, default: {}
498
447
 
499
448
  class ClassCache
@@ -502,18 +451,19 @@ module ActiveRecord
502
451
  @config = config
503
452
 
504
453
  # Remove string values that aren't constants or subclasses of AR
505
- @class_names.delete_if { |klass_name, klass| !insert_class(@class_names, klass_name, klass) }
454
+ @class_names.delete_if do |klass_name, klass|
455
+ !insert_class(@class_names, klass_name, klass)
456
+ end
506
457
  end
507
458
 
508
459
  def [](fs_name)
509
- @class_names.fetch(fs_name) {
460
+ @class_names.fetch(fs_name) do
510
461
  klass = default_fixture_model(fs_name, @config).safe_constantize
511
462
  insert_class(@class_names, fs_name, klass)
512
- }
463
+ end
513
464
  end
514
465
 
515
466
  private
516
-
517
467
  def insert_class(class_names, name, klass)
518
468
  # We only want to deal with AR objects.
519
469
  if klass && klass < ActiveRecord::Base
@@ -528,76 +478,150 @@ module ActiveRecord
528
478
  end
529
479
  end
530
480
 
531
- def self.create_fixtures(fixtures_directory, fixture_set_names, class_names = {}, config = ActiveRecord::Base)
532
- fixture_set_names = Array(fixture_set_names).map(&:to_s)
533
- class_names = ClassCache.new class_names, config
481
+ class << self
482
+ def default_fixture_model_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
483
+ config.pluralize_table_names ?
484
+ fixture_set_name.singularize.camelize :
485
+ fixture_set_name.camelize
486
+ end
534
487
 
535
- # FIXME: Apparently JK uses this.
536
- connection = block_given? ? yield : ActiveRecord::Base.connection
488
+ def default_fixture_table_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
489
+ "#{ config.table_name_prefix }"\
490
+ "#{ fixture_set_name.tr('/', '_') }"\
491
+ "#{ config.table_name_suffix }".to_sym
492
+ end
537
493
 
538
- files_to_read = fixture_set_names.reject { |fs_name|
539
- fixture_is_cached?(connection, fs_name)
540
- }
494
+ def reset_cache
495
+ @@all_cached_fixtures.clear
496
+ end
541
497
 
542
- unless files_to_read.empty?
543
- fixtures_map = {}
498
+ def cache_for_connection(connection)
499
+ @@all_cached_fixtures[connection]
500
+ end
544
501
 
545
- fixture_sets = files_to_read.map do |fs_name|
546
- klass = class_names[fs_name]
547
- conn = klass ? klass.connection : connection
548
- fixtures_map[fs_name] = new( # ActiveRecord::FixtureSet.new
549
- conn,
550
- fs_name,
551
- klass,
552
- ::File.join(fixtures_directory, fs_name))
502
+ def fixture_is_cached?(connection, table_name)
503
+ cache_for_connection(connection)[table_name]
504
+ end
505
+
506
+ def cached_fixtures(connection, keys_to_fetch = nil)
507
+ if keys_to_fetch
508
+ cache_for_connection(connection).values_at(*keys_to_fetch)
509
+ else
510
+ cache_for_connection(connection).values
553
511
  end
512
+ end
554
513
 
555
- update_all_loaded_fixtures fixtures_map
556
- fixture_sets_by_connection = fixture_sets.group_by { |fs| fs.model_class ? fs.model_class.connection : connection }
514
+ def cache_fixtures(connection, fixtures_map)
515
+ cache_for_connection(connection).update(fixtures_map)
516
+ end
557
517
 
558
- fixture_sets_by_connection.each do |conn, set|
559
- table_rows_for_connection = Hash.new { |h, k| h[k] = [] }
518
+ def instantiate_fixtures(object, fixture_set, load_instances = true)
519
+ return unless load_instances
520
+ fixture_set.each do |fixture_name, fixture|
521
+ object.instance_variable_set "@#{fixture_name}", fixture.find
522
+ rescue FixtureClassNotFound
523
+ nil
524
+ end
525
+ end
560
526
 
561
- set.each do |fs|
562
- fs.table_rows.each do |table, rows|
563
- table_rows_for_connection[table].unshift(*rows)
564
- end
565
- end
566
- conn.insert_fixtures_set(table_rows_for_connection, table_rows_for_connection.keys)
527
+ def instantiate_all_loaded_fixtures(object, load_instances = true)
528
+ all_loaded_fixtures.each_value do |fixture_set|
529
+ instantiate_fixtures(object, fixture_set, load_instances)
530
+ end
531
+ end
567
532
 
568
- # Cap primary key sequences to max(pk).
569
- if conn.respond_to?(:reset_pk_sequence!)
570
- set.each { |fs| conn.reset_pk_sequence!(fs.table_name) }
571
- end
533
+ def create_fixtures(fixtures_directory, fixture_set_names, class_names = {}, config = ActiveRecord::Base, &block)
534
+ fixture_set_names = Array(fixture_set_names).map(&:to_s)
535
+ class_names = ClassCache.new class_names, config
536
+
537
+ # FIXME: Apparently JK uses this.
538
+ connection = block_given? ? block : lambda { ActiveRecord::Base.connection }
539
+
540
+ fixture_files_to_read = fixture_set_names.reject do |fs_name|
541
+ fixture_is_cached?(connection.call, fs_name)
572
542
  end
573
543
 
574
- cache_fixtures(connection, fixtures_map)
544
+ if fixture_files_to_read.any?
545
+ fixtures_map = read_and_insert(
546
+ fixtures_directory,
547
+ fixture_files_to_read,
548
+ class_names,
549
+ connection,
550
+ )
551
+ cache_fixtures(connection.call, fixtures_map)
552
+ end
553
+ cached_fixtures(connection.call, fixture_set_names)
575
554
  end
576
- cached_fixtures(connection, fixture_set_names)
577
- end
578
555
 
579
- # Returns a consistent, platform-independent identifier for +label+.
580
- # Integer identifiers are values less than 2^30. UUIDs are RFC 4122 version 5 SHA-1 hashes.
581
- def self.identify(label, column_type = :integer)
582
- if column_type == :uuid
583
- Digest::UUID.uuid_v5(Digest::UUID::OID_NAMESPACE, label.to_s)
584
- else
585
- Zlib.crc32(label.to_s) % MAX_ID
556
+ # Returns a consistent, platform-independent identifier for +label+.
557
+ # Integer identifiers are values less than 2^30. UUIDs are RFC 4122 version 5 SHA-1 hashes.
558
+ def identify(label, column_type = :integer)
559
+ if column_type == :uuid
560
+ Digest::UUID.uuid_v5(Digest::UUID::OID_NAMESPACE, label.to_s)
561
+ else
562
+ Zlib.crc32(label.to_s) % MAX_ID
563
+ end
586
564
  end
587
- end
588
565
 
589
- # Superclass for the evaluation contexts used by ERB fixtures.
590
- def self.context_class
591
- @context_class ||= Class.new
592
- end
566
+ # Superclass for the evaluation contexts used by ERB fixtures.
567
+ def context_class
568
+ @context_class ||= Class.new
569
+ end
593
570
 
594
- def self.update_all_loaded_fixtures(fixtures_map) # :nodoc:
595
- all_loaded_fixtures.update(fixtures_map)
571
+ private
572
+ def read_and_insert(fixtures_directory, fixture_files, class_names, connection) # :nodoc:
573
+ fixtures_map = {}
574
+ fixture_sets = fixture_files.map do |fixture_set_name|
575
+ klass = class_names[fixture_set_name]
576
+ fixtures_map[fixture_set_name] = new( # ActiveRecord::FixtureSet.new
577
+ nil,
578
+ fixture_set_name,
579
+ klass,
580
+ ::File.join(fixtures_directory, fixture_set_name)
581
+ )
582
+ end
583
+ update_all_loaded_fixtures(fixtures_map)
584
+
585
+ insert(fixture_sets, connection)
586
+
587
+ fixtures_map
588
+ end
589
+
590
+ def insert(fixture_sets, connection) # :nodoc:
591
+ fixture_sets_by_connection = fixture_sets.group_by do |fixture_set|
592
+ if fixture_set.model_class
593
+ fixture_set.model_class.connection
594
+ else
595
+ connection.call
596
+ end
597
+ end
598
+
599
+ fixture_sets_by_connection.each do |conn, set|
600
+ table_rows_for_connection = Hash.new { |h, k| h[k] = [] }
601
+
602
+ set.each do |fixture_set|
603
+ fixture_set.table_rows.each do |table, rows|
604
+ table_rows_for_connection[table].unshift(*rows)
605
+ end
606
+ end
607
+
608
+ conn.insert_fixtures_set(table_rows_for_connection, table_rows_for_connection.keys)
609
+
610
+ # Cap primary key sequences to max(pk).
611
+ if conn.respond_to?(:reset_pk_sequence!)
612
+ set.each { |fs| conn.reset_pk_sequence!(fs.table_name) }
613
+ end
614
+ end
615
+ end
616
+
617
+ def update_all_loaded_fixtures(fixtures_map) # :nodoc:
618
+ all_loaded_fixtures.update(fixtures_map)
619
+ end
596
620
  end
597
621
 
598
622
  attr_reader :table_name, :name, :fixtures, :model_class, :config
599
623
 
600
- def initialize(connection, name, class_name, path, config = ActiveRecord::Base)
624
+ def initialize(_, name, class_name, path, config = ActiveRecord::Base)
601
625
  @name = name
602
626
  @path = path
603
627
  @config = config
@@ -606,11 +630,7 @@ module ActiveRecord
606
630
 
607
631
  @fixtures = read_fixture_files(path)
608
632
 
609
- @connection = connection
610
-
611
- @table_name = (model_class.respond_to?(:table_name) ?
612
- model_class.table_name :
613
- self.class.default_fixture_table_name(name, config))
633
+ @table_name = model_class&.table_name || self.class.default_fixture_table_name(name, config)
614
634
  end
615
635
 
616
636
  def [](x)
@@ -632,153 +652,18 @@ module ActiveRecord
632
652
  # Returns a hash of rows to be inserted. The key is the table, the value is
633
653
  # a list of rows to insert to that table.
634
654
  def table_rows
635
- now = config.default_timezone == :utc ? Time.now.utc : Time.now
636
-
637
655
  # allow a standard key to be used for doing defaults in YAML
638
656
  fixtures.delete("DEFAULTS")
639
657
 
640
- # track any join tables we need to insert later
641
- rows = Hash.new { |h, table| h[table] = [] }
642
-
643
- rows[table_name] = fixtures.map do |label, fixture|
644
- row = fixture.to_hash
645
-
646
- if model_class
647
- # fill in timestamp columns if they aren't specified and the model is set to record_timestamps
648
- if model_class.record_timestamps
649
- timestamp_column_names.each do |c_name|
650
- row[c_name] = now unless row.key?(c_name)
651
- end
652
- end
653
-
654
- # interpolate the fixture label
655
- row.each do |key, value|
656
- row[key] = value.gsub("$LABEL", label.to_s) if value.is_a?(String)
657
- end
658
-
659
- # generate a primary key if necessary
660
- if has_primary_key_column? && !row.include?(primary_key_name)
661
- row[primary_key_name] = ActiveRecord::FixtureSet.identify(label, primary_key_type)
662
- end
663
-
664
- # Resolve enums
665
- model_class.defined_enums.each do |name, values|
666
- if row.include?(name)
667
- row[name] = values.fetch(row[name], row[name])
668
- end
669
- end
670
-
671
- # If STI is used, find the correct subclass for association reflection
672
- reflection_class =
673
- if row.include?(inheritance_column_name)
674
- row[inheritance_column_name].constantize rescue model_class
675
- else
676
- model_class
677
- end
678
-
679
- reflection_class._reflections.each_value do |association|
680
- case association.macro
681
- when :belongs_to
682
- # Do not replace association name with association foreign key if they are named the same
683
- fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
684
-
685
- if association.name.to_s != fk_name && value = row.delete(association.name.to_s)
686
- if association.polymorphic? && value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
687
- # support polymorphic belongs_to as "label (Type)"
688
- row[association.foreign_type] = $1
689
- end
690
-
691
- fk_type = reflection_class.type_for_attribute(fk_name).type
692
- row[fk_name] = ActiveRecord::FixtureSet.identify(value, fk_type)
693
- end
694
- when :has_many
695
- if association.options[:through]
696
- add_join_records(rows, row, HasManyThroughProxy.new(association))
697
- end
698
- end
699
- end
700
- end
701
-
702
- row
703
- end
704
- rows
705
- end
706
-
707
- class ReflectionProxy # :nodoc:
708
- def initialize(association)
709
- @association = association
710
- end
711
-
712
- def join_table
713
- @association.join_table
714
- end
715
-
716
- def name
717
- @association.name
718
- end
719
-
720
- def primary_key_type
721
- @association.klass.type_for_attribute(@association.klass.primary_key).type
722
- end
723
- end
724
-
725
- class HasManyThroughProxy < ReflectionProxy # :nodoc:
726
- def rhs_key
727
- @association.foreign_key
728
- end
729
-
730
- def lhs_key
731
- @association.through_reflection.foreign_key
732
- end
733
-
734
- def join_table
735
- @association.through_reflection.table_name
736
- end
658
+ TableRows.new(
659
+ table_name,
660
+ model_class: model_class,
661
+ fixtures: fixtures,
662
+ config: config,
663
+ ).to_hash
737
664
  end
738
665
 
739
666
  private
740
- def primary_key_name
741
- @primary_key_name ||= model_class && model_class.primary_key
742
- end
743
-
744
- def primary_key_type
745
- @primary_key_type ||= model_class && model_class.type_for_attribute(model_class.primary_key).type
746
- end
747
-
748
- def add_join_records(rows, row, association)
749
- # This is the case when the join table has no fixtures file
750
- if (targets = row.delete(association.name.to_s))
751
- table_name = association.join_table
752
- column_type = association.primary_key_type
753
- lhs_key = association.lhs_key
754
- rhs_key = association.rhs_key
755
-
756
- targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
757
- rows[table_name].concat targets.map { |target|
758
- { lhs_key => row[primary_key_name],
759
- rhs_key => ActiveRecord::FixtureSet.identify(target, column_type) }
760
- }
761
- end
762
- end
763
-
764
- def has_primary_key_column?
765
- @has_primary_key_column ||= primary_key_name &&
766
- model_class.columns.any? { |c| c.name == primary_key_name }
767
- end
768
-
769
- def timestamp_column_names
770
- @timestamp_column_names ||=
771
- %w(created_at created_on updated_at updated_on) & column_names
772
- end
773
-
774
- def inheritance_column_name
775
- @inheritance_column_name ||= model_class && model_class.inheritance_column
776
- end
777
-
778
- def column_names
779
- @column_names ||= @connection.columns(@table_name).collect(&:name)
780
- end
781
-
782
667
  def model_class=(class_name)
783
668
  if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any?
784
669
  @model_class = class_name
@@ -841,224 +726,9 @@ module ActiveRecord
841
726
  alias :to_hash :fixture
842
727
 
843
728
  def find
844
- if model_class
845
- model_class.unscoped do
846
- model_class.find(fixture[model_class.primary_key])
847
- end
848
- else
849
- raise FixtureClassNotFound, "No class attached to find."
850
- end
851
- end
852
- end
853
- end
854
-
855
- module ActiveRecord
856
- module TestFixtures
857
- extend ActiveSupport::Concern
858
-
859
- def before_setup # :nodoc:
860
- setup_fixtures
861
- super
862
- end
863
-
864
- def after_teardown # :nodoc:
865
- super
866
- teardown_fixtures
867
- end
868
-
869
- included do
870
- class_attribute :fixture_path, instance_writer: false
871
- class_attribute :fixture_table_names, default: []
872
- class_attribute :fixture_class_names, default: {}
873
- class_attribute :use_transactional_tests, default: true
874
- class_attribute :use_instantiated_fixtures, default: false # true, false, or :no_instances
875
- class_attribute :pre_loaded_fixtures, default: false
876
- class_attribute :config, default: ActiveRecord::Base
877
- end
878
-
879
- module ClassMethods
880
- # Sets the model class for a fixture when the class name cannot be inferred from the fixture name.
881
- #
882
- # Examples:
883
- #
884
- # set_fixture_class some_fixture: SomeModel,
885
- # 'namespaced/fixture' => Another::Model
886
- #
887
- # The keys must be the fixture names, that coincide with the short paths to the fixture files.
888
- def set_fixture_class(class_names = {})
889
- self.fixture_class_names = fixture_class_names.merge(class_names.stringify_keys)
890
- end
891
-
892
- def fixtures(*fixture_set_names)
893
- if fixture_set_names.first == :all
894
- fixture_set_names = Dir["#{fixture_path}/{**,*}/*.{yml}"].uniq
895
- fixture_set_names.map! { |f| f[(fixture_path.to_s.size + 1)..-5] }
896
- else
897
- fixture_set_names = fixture_set_names.flatten.map(&:to_s)
898
- end
899
-
900
- self.fixture_table_names |= fixture_set_names
901
- setup_fixture_accessors(fixture_set_names)
902
- end
903
-
904
- def setup_fixture_accessors(fixture_set_names = nil)
905
- fixture_set_names = Array(fixture_set_names || fixture_table_names)
906
- methods = Module.new do
907
- fixture_set_names.each do |fs_name|
908
- fs_name = fs_name.to_s
909
- accessor_name = fs_name.tr("/", "_").to_sym
910
-
911
- define_method(accessor_name) do |*fixture_names|
912
- force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
913
- return_single_record = fixture_names.size == 1
914
- fixture_names = @loaded_fixtures[fs_name].fixtures.keys if fixture_names.empty?
915
-
916
- @fixture_cache[fs_name] ||= {}
917
-
918
- instances = fixture_names.map do |f_name|
919
- f_name = f_name.to_s if f_name.is_a?(Symbol)
920
- @fixture_cache[fs_name].delete(f_name) if force_reload
921
-
922
- if @loaded_fixtures[fs_name][f_name]
923
- @fixture_cache[fs_name][f_name] ||= @loaded_fixtures[fs_name][f_name].find
924
- else
925
- raise StandardError, "No fixture named '#{f_name}' found for fixture set '#{fs_name}'"
926
- end
927
- end
928
-
929
- return_single_record ? instances.first : instances
930
- end
931
- private accessor_name
932
- end
933
- end
934
- include methods
935
- end
936
-
937
- def uses_transaction(*methods)
938
- @uses_transaction = [] unless defined?(@uses_transaction)
939
- @uses_transaction.concat methods.map(&:to_s)
940
- end
941
-
942
- def uses_transaction?(method)
943
- @uses_transaction = [] unless defined?(@uses_transaction)
944
- @uses_transaction.include?(method.to_s)
945
- end
946
- end
947
-
948
- def run_in_transaction?
949
- use_transactional_tests &&
950
- !self.class.uses_transaction?(method_name)
951
- end
952
-
953
- def setup_fixtures(config = ActiveRecord::Base)
954
- if pre_loaded_fixtures && !use_transactional_tests
955
- raise RuntimeError, "pre_loaded_fixtures requires use_transactional_tests"
956
- end
957
-
958
- @fixture_cache = {}
959
- @fixture_connections = []
960
- @@already_loaded_fixtures ||= {}
961
- @connection_subscriber = nil
962
-
963
- # Load fixtures once and begin transaction.
964
- if run_in_transaction?
965
- if @@already_loaded_fixtures[self.class]
966
- @loaded_fixtures = @@already_loaded_fixtures[self.class]
967
- else
968
- @loaded_fixtures = load_fixtures(config)
969
- @@already_loaded_fixtures[self.class] = @loaded_fixtures
970
- end
971
-
972
- # Begin transactions for connections already established
973
- @fixture_connections = enlist_fixture_connections
974
- @fixture_connections.each do |connection|
975
- connection.begin_transaction joinable: false
976
- connection.pool.lock_thread = true
977
- end
978
-
979
- # When connections are established in the future, begin a transaction too
980
- @connection_subscriber = ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload|
981
- spec_name = payload[:spec_name] if payload.key?(:spec_name)
982
-
983
- if spec_name
984
- begin
985
- connection = ActiveRecord::Base.connection_handler.retrieve_connection(spec_name)
986
- rescue ConnectionNotEstablished
987
- connection = nil
988
- end
989
-
990
- if connection && !@fixture_connections.include?(connection)
991
- connection.begin_transaction joinable: false
992
- connection.pool.lock_thread = true
993
- @fixture_connections << connection
994
- end
995
- end
996
- end
997
-
998
- # Load fixtures for every test.
999
- else
1000
- ActiveRecord::FixtureSet.reset_cache
1001
- @@already_loaded_fixtures[self.class] = nil
1002
- @loaded_fixtures = load_fixtures(config)
1003
- end
1004
-
1005
- # Instantiate fixtures for every test if requested.
1006
- instantiate_fixtures if use_instantiated_fixtures
1007
- end
1008
-
1009
- def teardown_fixtures
1010
- # Rollback changes if a transaction is active.
1011
- if run_in_transaction?
1012
- ActiveSupport::Notifications.unsubscribe(@connection_subscriber) if @connection_subscriber
1013
- @fixture_connections.each do |connection|
1014
- connection.rollback_transaction if connection.transaction_open?
1015
- connection.pool.lock_thread = false
1016
- end
1017
- @fixture_connections.clear
1018
- else
1019
- ActiveRecord::FixtureSet.reset_cache
1020
- end
1021
-
1022
- ActiveRecord::Base.clear_active_connections!
1023
- end
1024
-
1025
- def enlist_fixture_connections
1026
- ActiveRecord::Base.connection_handler.connection_pool_list.map(&:connection)
1027
- end
1028
-
1029
- private
1030
- def load_fixtures(config)
1031
- fixtures = ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names, config)
1032
- Hash[fixtures.map { |f| [f.name, f] }]
1033
- end
1034
-
1035
- def instantiate_fixtures
1036
- if pre_loaded_fixtures
1037
- raise RuntimeError, "Load fixtures before instantiating them." if ActiveRecord::FixtureSet.all_loaded_fixtures.empty?
1038
- ActiveRecord::FixtureSet.instantiate_all_loaded_fixtures(self, load_instances?)
1039
- else
1040
- raise RuntimeError, "Load fixtures before instantiating them." if @loaded_fixtures.nil?
1041
- @loaded_fixtures.each_value do |fixture_set|
1042
- ActiveRecord::FixtureSet.instantiate_fixtures(self, fixture_set, load_instances?)
1043
- end
1044
- end
1045
- end
1046
-
1047
- def load_instances?
1048
- use_instantiated_fixtures != :no_instances
1049
- end
1050
- end
1051
- end
1052
-
1053
- class ActiveRecord::FixtureSet::RenderContext # :nodoc:
1054
- def self.create_subclass
1055
- Class.new ActiveRecord::FixtureSet.context_class do
1056
- def get_binding
1057
- binding()
1058
- end
1059
-
1060
- def binary(path)
1061
- %(!!binary "#{Base64.strict_encode64(File.read(path))}")
729
+ raise FixtureClassNotFound, "No class attached to find." unless model_class
730
+ model_class.unscoped do
731
+ model_class.find(fixture[model_class.primary_key])
1062
732
  end
1063
733
  end
1064
734
  end