activerecord 5.1.0 → 5.2.3

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 (261) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +596 -450
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -5
  5. data/examples/performance.rb +2 -0
  6. data/examples/simple.rb +2 -0
  7. data/lib/active_record.rb +11 -4
  8. data/lib/active_record/aggregations.rb +6 -5
  9. data/lib/active_record/association_relation.rb +7 -5
  10. data/lib/active_record/associations.rb +77 -85
  11. data/lib/active_record/associations/alias_tracker.rb +23 -32
  12. data/lib/active_record/associations/association.rb +49 -35
  13. data/lib/active_record/associations/association_scope.rb +55 -55
  14. data/lib/active_record/associations/belongs_to_association.rb +30 -11
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
  16. data/lib/active_record/associations/builder/association.rb +4 -7
  17. data/lib/active_record/associations/builder/belongs_to.rb +21 -8
  18. data/lib/active_record/associations/builder/collection_association.rb +1 -1
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
  20. data/lib/active_record/associations/builder/has_many.rb +2 -0
  21. data/lib/active_record/associations/builder/has_one.rb +2 -0
  22. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  23. data/lib/active_record/associations/collection_association.rb +66 -53
  24. data/lib/active_record/associations/collection_proxy.rb +30 -73
  25. data/lib/active_record/associations/foreign_association.rb +2 -0
  26. data/lib/active_record/associations/has_many_association.rb +13 -2
  27. data/lib/active_record/associations/has_many_through_association.rb +37 -19
  28. data/lib/active_record/associations/has_one_association.rb +14 -1
  29. data/lib/active_record/associations/has_one_through_association.rb +13 -8
  30. data/lib/active_record/associations/join_dependency.rb +52 -96
  31. data/lib/active_record/associations/join_dependency/join_association.rb +22 -75
  32. data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
  33. data/lib/active_record/associations/join_dependency/join_part.rb +9 -9
  34. data/lib/active_record/associations/preloader.rb +17 -37
  35. data/lib/active_record/associations/preloader/association.rb +53 -92
  36. data/lib/active_record/associations/preloader/through_association.rb +72 -73
  37. data/lib/active_record/associations/singular_association.rb +14 -16
  38. data/lib/active_record/associations/through_association.rb +27 -12
  39. data/lib/active_record/attribute_assignment.rb +2 -5
  40. data/lib/active_record/attribute_decorators.rb +3 -2
  41. data/lib/active_record/attribute_methods.rb +65 -24
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
  43. data/lib/active_record/attribute_methods/dirty.rb +33 -216
  44. data/lib/active_record/attribute_methods/primary_key.rb +10 -13
  45. data/lib/active_record/attribute_methods/query.rb +2 -0
  46. data/lib/active_record/attribute_methods/read.rb +9 -3
  47. data/lib/active_record/attribute_methods/serialization.rb +23 -0
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
  49. data/lib/active_record/attribute_methods/write.rb +22 -19
  50. data/lib/active_record/attributes.rb +7 -6
  51. data/lib/active_record/autosave_association.rb +15 -13
  52. data/lib/active_record/base.rb +2 -0
  53. data/lib/active_record/callbacks.rb +12 -6
  54. data/lib/active_record/coders/json.rb +2 -0
  55. data/lib/active_record/coders/yaml_column.rb +2 -0
  56. data/lib/active_record/collection_cache_key.rb +15 -11
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +120 -39
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +192 -37
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +13 -2
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -25
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +15 -6
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +65 -7
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +158 -87
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +86 -98
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +126 -189
  70. data/lib/active_record/connection_adapters/column.rb +4 -2
  71. data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
  72. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +13 -2
  73. data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
  74. data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -15
  75. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
  76. data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
  77. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
  78. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
  79. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -23
  80. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
  81. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
  82. data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
  83. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
  84. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -32
  85. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +13 -1
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  99. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -1
  101. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +8 -2
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
  106. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  109. data/lib/active_record/connection_adapters/postgresql/quoting.rb +22 -1
  110. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  111. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +50 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
  113. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
  114. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +258 -129
  115. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
  116. data/lib/active_record/connection_adapters/postgresql/utils.rb +3 -1
  117. data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -87
  118. data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
  119. data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
  120. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
  121. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +24 -1
  122. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
  124. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
  125. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +75 -1
  126. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +90 -96
  127. data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
  128. data/lib/active_record/connection_handling.rb +4 -2
  129. data/lib/active_record/core.rb +41 -61
  130. data/lib/active_record/counter_cache.rb +20 -15
  131. data/lib/active_record/define_callbacks.rb +5 -3
  132. data/lib/active_record/dynamic_matchers.rb +9 -9
  133. data/lib/active_record/enum.rb +18 -13
  134. data/lib/active_record/errors.rb +60 -15
  135. data/lib/active_record/explain.rb +3 -1
  136. data/lib/active_record/explain_registry.rb +2 -0
  137. data/lib/active_record/explain_subscriber.rb +2 -0
  138. data/lib/active_record/fixture_set/file.rb +2 -0
  139. data/lib/active_record/fixtures.rb +67 -60
  140. data/lib/active_record/gem_version.rb +4 -2
  141. data/lib/active_record/inheritance.rb +49 -19
  142. data/lib/active_record/integration.rb +58 -19
  143. data/lib/active_record/internal_metadata.rb +2 -0
  144. data/lib/active_record/legacy_yaml_adapter.rb +3 -1
  145. data/lib/active_record/locking/optimistic.rb +30 -42
  146. data/lib/active_record/locking/pessimistic.rb +10 -7
  147. data/lib/active_record/log_subscriber.rb +46 -4
  148. data/lib/active_record/migration.rb +189 -139
  149. data/lib/active_record/migration/command_recorder.rb +11 -9
  150. data/lib/active_record/migration/compatibility.rb +81 -29
  151. data/lib/active_record/migration/join_table.rb +2 -0
  152. data/lib/active_record/model_schema.rb +74 -58
  153. data/lib/active_record/nested_attributes.rb +18 -6
  154. data/lib/active_record/no_touching.rb +3 -1
  155. data/lib/active_record/null_relation.rb +2 -0
  156. data/lib/active_record/persistence.rb +199 -54
  157. data/lib/active_record/query_cache.rb +8 -10
  158. data/lib/active_record/querying.rb +5 -3
  159. data/lib/active_record/railtie.rb +62 -6
  160. data/lib/active_record/railties/console_sandbox.rb +2 -0
  161. data/lib/active_record/railties/controller_runtime.rb +2 -0
  162. data/lib/active_record/railties/databases.rake +48 -38
  163. data/lib/active_record/readonly_attributes.rb +3 -2
  164. data/lib/active_record/reflection.rb +137 -207
  165. data/lib/active_record/relation.rb +132 -207
  166. data/lib/active_record/relation/batches.rb +32 -17
  167. data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
  168. data/lib/active_record/relation/calculations.rb +66 -25
  169. data/lib/active_record/relation/delegation.rb +45 -29
  170. data/lib/active_record/relation/finder_methods.rb +76 -85
  171. data/lib/active_record/relation/from_clause.rb +2 -8
  172. data/lib/active_record/relation/merger.rb +53 -23
  173. data/lib/active_record/relation/predicate_builder.rb +60 -79
  174. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
  175. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  176. data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
  177. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
  178. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  179. data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
  180. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  181. data/lib/active_record/relation/query_attribute.rb +28 -2
  182. data/lib/active_record/relation/query_methods.rb +135 -103
  183. data/lib/active_record/relation/record_fetch_warning.rb +2 -0
  184. data/lib/active_record/relation/spawn_methods.rb +4 -2
  185. data/lib/active_record/relation/where_clause.rb +65 -67
  186. data/lib/active_record/relation/where_clause_factory.rb +5 -48
  187. data/lib/active_record/result.rb +2 -0
  188. data/lib/active_record/runtime_registry.rb +2 -0
  189. data/lib/active_record/sanitization.rb +129 -121
  190. data/lib/active_record/schema.rb +4 -2
  191. data/lib/active_record/schema_dumper.rb +36 -26
  192. data/lib/active_record/schema_migration.rb +2 -0
  193. data/lib/active_record/scoping.rb +12 -10
  194. data/lib/active_record/scoping/default.rb +10 -7
  195. data/lib/active_record/scoping/named.rb +40 -12
  196. data/lib/active_record/secure_token.rb +2 -0
  197. data/lib/active_record/serialization.rb +2 -0
  198. data/lib/active_record/statement_cache.rb +22 -12
  199. data/lib/active_record/store.rb +3 -1
  200. data/lib/active_record/suppressor.rb +2 -0
  201. data/lib/active_record/table_metadata.rb +12 -3
  202. data/lib/active_record/tasks/database_tasks.rb +38 -26
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +11 -50
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -3
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
  206. data/lib/active_record/timestamp.rb +13 -6
  207. data/lib/active_record/touch_later.rb +2 -0
  208. data/lib/active_record/transactions.rb +32 -27
  209. data/lib/active_record/translation.rb +2 -0
  210. data/lib/active_record/type.rb +4 -1
  211. data/lib/active_record/type/adapter_specific_registry.rb +2 -0
  212. data/lib/active_record/type/date.rb +2 -0
  213. data/lib/active_record/type/date_time.rb +2 -0
  214. data/lib/active_record/type/decimal_without_scale.rb +2 -0
  215. data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
  216. data/lib/active_record/type/internal/timezone.rb +2 -0
  217. data/lib/active_record/type/json.rb +30 -0
  218. data/lib/active_record/type/serialized.rb +6 -0
  219. data/lib/active_record/type/text.rb +2 -0
  220. data/lib/active_record/type/time.rb +2 -0
  221. data/lib/active_record/type/type_map.rb +2 -0
  222. data/lib/active_record/type/unsigned_integer.rb +2 -0
  223. data/lib/active_record/type_caster.rb +2 -0
  224. data/lib/active_record/type_caster/connection.rb +2 -0
  225. data/lib/active_record/type_caster/map.rb +3 -1
  226. data/lib/active_record/validations.rb +2 -0
  227. data/lib/active_record/validations/absence.rb +2 -0
  228. data/lib/active_record/validations/associated.rb +2 -0
  229. data/lib/active_record/validations/length.rb +2 -0
  230. data/lib/active_record/validations/presence.rb +2 -0
  231. data/lib/active_record/validations/uniqueness.rb +36 -6
  232. data/lib/active_record/version.rb +2 -0
  233. data/lib/rails/generators/active_record.rb +3 -1
  234. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  235. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  236. data/lib/rails/generators/active_record/migration.rb +2 -0
  237. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
  238. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
  239. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
  240. data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
  241. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
  242. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  243. metadata +24 -36
  244. data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
  245. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  246. data/lib/active_record/associations/preloader/has_many.rb +0 -15
  247. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  248. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  249. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  250. data/lib/active_record/associations/preloader/singular_association.rb +0 -18
  251. data/lib/active_record/attribute.rb +0 -240
  252. data/lib/active_record/attribute/user_provided_default.rb +0 -30
  253. data/lib/active_record/attribute_mutation_tracker.rb +0 -113
  254. data/lib/active_record/attribute_set.rb +0 -113
  255. data/lib/active_record/attribute_set/builder.rb +0 -124
  256. data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
  257. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
  258. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  259. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  260. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
  261. data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Querying
3
5
  delegate :find, :take, :take!, :first, :first!, :last, :last!, :exists?, :any?, :many?, :none?, :one?, to: :all
@@ -5,10 +7,10 @@ module ActiveRecord
5
7
  delegate :first_or_create, :first_or_create!, :first_or_initialize, to: :all
6
8
  delegate :find_or_create_by, :find_or_create_by!, :find_or_initialize_by, to: :all
7
9
  delegate :find_by, :find_by!, to: :all
8
- delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, to: :all
10
+ delegate :destroy_all, :delete_all, :update_all, to: :all
9
11
  delegate :find_each, :find_in_batches, :in_batches, to: :all
10
12
  delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, :left_joins, :left_outer_joins, :or,
11
- :where, :rewhere, :preload, :eager_load, :includes, :from, :lock, :readonly,
13
+ :where, :rewhere, :preload, :eager_load, :includes, :from, :lock, :readonly, :extending,
12
14
  :having, :create_with, :distinct, :references, :none, :unscope, :merge, to: :all
13
15
  delegate :count, :average, :minimum, :maximum, :sum, :calculate, to: :all
14
16
  delegate :pluck, :ids, to: :all
@@ -38,7 +40,7 @@ module ActiveRecord
38
40
  def find_by_sql(sql, binds = [], preparable: nil, &block)
39
41
  result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable)
40
42
  column_types = result_set.column_types.dup
41
- columns_hash.each_key { |k| column_types.delete k }
43
+ attribute_types.each_key { |k| column_types.delete k }
42
44
  message_bus = ActiveSupport::Notifications.instrumenter
43
45
 
44
46
  payload = {
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_record"
2
4
  require "rails"
3
5
  require "active_model/railtie"
@@ -26,6 +28,9 @@ module ActiveRecord
26
28
  config.active_record.use_schema_cache_dump = true
27
29
  config.active_record.maintain_test_schema = true
28
30
 
31
+ config.active_record.sqlite3 = ActiveSupport::OrderedOptions.new
32
+ config.active_record.sqlite3.represent_boolean_as_integer = nil
33
+
29
34
  config.eager_load_namespaces << ActiveRecord
30
35
 
31
36
  rake_tasks do
@@ -54,6 +59,7 @@ module ActiveRecord
54
59
  console = ActiveSupport::Logger.new(STDERR)
55
60
  Rails.logger.extend ActiveSupport::Logger.broadcast console
56
61
  end
62
+ ActiveRecord::Base.verbose_query_logs = false
57
63
  end
58
64
 
59
65
  runner do
@@ -85,12 +91,16 @@ module ActiveRecord
85
91
  filename = File.join(app.config.paths["db"].first, "schema_cache.yml")
86
92
 
87
93
  if File.file?(filename)
94
+ current_version = ActiveRecord::Migrator.current_version
95
+
96
+ next if current_version.nil?
97
+
88
98
  cache = YAML.load(File.read(filename))
89
- if cache.version == ActiveRecord::Migrator.current_version
99
+ if cache.version == current_version
90
100
  connection.schema_cache = cache
91
101
  connection_pool.schema_cache = cache.dup
92
102
  else
93
- warn "Ignoring db/schema_cache.yml because it has expired. The current schema version is #{ActiveRecord::Migrator.current_version}, but the one in the cache is #{cache.version}."
103
+ warn "Ignoring db/schema_cache.yml because it has expired. The current schema version is #{current_version}, but the one in the cache is #{cache.version}."
94
104
  end
95
105
  end
96
106
  end
@@ -108,7 +118,9 @@ module ActiveRecord
108
118
 
109
119
  initializer "active_record.set_configs" do |app|
110
120
  ActiveSupport.on_load(:active_record) do
111
- app.config.active_record.each do |k, v|
121
+ configs = app.config.active_record.dup
122
+ configs.delete(:sqlite3)
123
+ configs.each do |k, v|
112
124
  send "#{k}=", v
113
125
  end
114
126
  end
@@ -157,14 +169,58 @@ end_warning
157
169
  end
158
170
 
159
171
  initializer "active_record.set_executor_hooks" do
160
- ActiveSupport.on_load(:active_record) do
161
- ActiveRecord::QueryCache.install_executor_hooks
162
- end
172
+ ActiveRecord::QueryCache.install_executor_hooks
163
173
  end
164
174
 
165
175
  initializer "active_record.add_watchable_files" do |app|
166
176
  path = app.paths["db"].first
167
177
  config.watchable_files.concat ["#{path}/schema.rb", "#{path}/structure.sql"]
168
178
  end
179
+
180
+ initializer "active_record.clear_active_connections" do
181
+ config.after_initialize do
182
+ ActiveSupport.on_load(:active_record) do
183
+ # Ideally the application doesn't connect to the database during boot,
184
+ # but sometimes it does. In case it did, we want to empty out the
185
+ # connection pools so that a non-database-using process (e.g. a master
186
+ # process in a forking server model) doesn't retain a needless
187
+ # connection. If it was needed, the incremental cost of reestablishing
188
+ # this connection is trivial: the rest of the pool would need to be
189
+ # populated anyway.
190
+
191
+ clear_active_connections!
192
+ flush_idle_connections!
193
+ end
194
+ end
195
+ end
196
+
197
+ initializer "active_record.check_represent_sqlite3_boolean_as_integer" do
198
+ config.after_initialize do
199
+ ActiveSupport.on_load(:active_record_sqlite3adapter) do
200
+ represent_boolean_as_integer = Rails.application.config.active_record.sqlite3.delete(:represent_boolean_as_integer)
201
+ unless represent_boolean_as_integer.nil?
202
+ ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer = represent_boolean_as_integer
203
+ end
204
+
205
+ unless ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer
206
+ ActiveSupport::Deprecation.warn <<-MSG
207
+ Leaving `ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer`
208
+ set to false is deprecated. SQLite databases have used 't' and 'f' to serialize
209
+ boolean values and must have old data converted to 1 and 0 (its native boolean
210
+ serialization) before setting this flag to true. Conversion can be accomplished
211
+ by setting up a rake task which runs
212
+
213
+ ExampleModel.where("boolean_column = 't'").update_all(boolean_column: 1)
214
+ ExampleModel.where("boolean_column = 'f'").update_all(boolean_column: 0)
215
+
216
+ for all models and all boolean columns, after which the flag must be set to
217
+ true by adding the following to your application.rb file:
218
+
219
+ Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true
220
+ MSG
221
+ end
222
+ end
223
+ end
224
+ end
169
225
  end
170
226
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ActiveRecord::Base.connection.begin_transaction(joinable: false)
2
4
 
3
5
  at_exit do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/module/attr_internal"
2
4
  require "active_record/log_subscriber"
3
5
 
@@ -1,17 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_record"
2
4
 
3
5
  db_namespace = namespace :db do
4
6
  desc "Set the environment value for the database"
5
- task "environment:set" => [:environment, :load_config] do
7
+ task "environment:set" => :load_config do
6
8
  ActiveRecord::InternalMetadata.create_table
7
- ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment
9
+ ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Base.connection.migration_context.current_environment
8
10
  end
9
11
 
10
- task check_protected_environments: [:environment, :load_config] do
12
+ task check_protected_environments: :load_config do
11
13
  ActiveRecord::Tasks::DatabaseTasks.check_protected_environments!
12
14
  end
13
15
 
14
- task :load_config do
16
+ task load_config: :environment do
15
17
  ActiveRecord::Base.configurations = ActiveRecord::Tasks::DatabaseTasks.database_configuration || {}
16
18
  ActiveRecord::Migrator.migrations_paths = ActiveRecord::Tasks::DatabaseTasks.migrations_paths
17
19
  end
@@ -54,7 +56,7 @@ db_namespace = namespace :db do
54
56
  end
55
57
 
56
58
  desc "Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)."
57
- task migrate: [:environment, :load_config] do
59
+ task migrate: :load_config do
58
60
  ActiveRecord::Tasks::DatabaseTasks.migrate
59
61
  db_namespace["_dump"].invoke
60
62
  end
@@ -76,7 +78,7 @@ db_namespace = namespace :db do
76
78
 
77
79
  namespace :migrate do
78
80
  # desc 'Rollbacks the database one migration and re migrate up (options: STEP=x, VERSION=x).'
79
- task redo: [:environment, :load_config] do
81
+ task redo: :load_config do
80
82
  raise "Empty VERSION provided" if ENV["VERSION"] && ENV["VERSION"].empty?
81
83
 
82
84
  if ENV["VERSION"]
@@ -92,24 +94,33 @@ db_namespace = namespace :db do
92
94
  task reset: ["db:drop", "db:create", "db:migrate"]
93
95
 
94
96
  # desc 'Runs the "up" for a given migration VERSION.'
95
- task up: [:environment, :load_config] do
97
+ task up: :load_config do
96
98
  raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty?
97
99
 
98
- version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
99
- ActiveRecord::Migrator.run(:up, ActiveRecord::Tasks::DatabaseTasks.migrations_paths, version)
100
+ ActiveRecord::Tasks::DatabaseTasks.check_target_version
101
+
102
+ ActiveRecord::Base.connection.migration_context.run(
103
+ :up,
104
+ ActiveRecord::Tasks::DatabaseTasks.target_version
105
+ )
100
106
  db_namespace["_dump"].invoke
101
107
  end
102
108
 
103
109
  # desc 'Runs the "down" for a given migration VERSION.'
104
- task down: [:environment, :load_config] do
110
+ task down: :load_config do
105
111
  raise "VERSION is required - To go down one migration, use db:rollback" if !ENV["VERSION"] || ENV["VERSION"].empty?
106
- version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
107
- ActiveRecord::Migrator.run(:down, ActiveRecord::Tasks::DatabaseTasks.migrations_paths, version)
112
+
113
+ ActiveRecord::Tasks::DatabaseTasks.check_target_version
114
+
115
+ ActiveRecord::Base.connection.migration_context.run(
116
+ :down,
117
+ ActiveRecord::Tasks::DatabaseTasks.target_version
118
+ )
108
119
  db_namespace["_dump"].invoke
109
120
  end
110
121
 
111
122
  desc "Display status of migrations"
112
- task status: [:environment, :load_config] do
123
+ task status: :load_config do
113
124
  unless ActiveRecord::SchemaMigration.table_exists?
114
125
  abort "Schema migrations table does not exist yet."
115
126
  end
@@ -118,8 +129,7 @@ db_namespace = namespace :db do
118
129
  puts "\ndatabase: #{ActiveRecord::Base.connection_config[:database]}\n\n"
119
130
  puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
120
131
  puts "-" * 50
121
- paths = ActiveRecord::Tasks::DatabaseTasks.migrations_paths
122
- ActiveRecord::Migrator.migrations_status(paths).each do |status, version, name|
132
+ ActiveRecord::Base.connection.migration_context.migrations_status.each do |status, version, name|
123
133
  puts "#{status.center(8)} #{version.ljust(14)} #{name}"
124
134
  end
125
135
  puts
@@ -127,16 +137,16 @@ db_namespace = namespace :db do
127
137
  end
128
138
 
129
139
  desc "Rolls the schema back to the previous version (specify steps w/ STEP=n)."
130
- task rollback: [:environment, :load_config] do
140
+ task rollback: :load_config do
131
141
  step = ENV["STEP"] ? ENV["STEP"].to_i : 1
132
- ActiveRecord::Migrator.rollback(ActiveRecord::Tasks::DatabaseTasks.migrations_paths, step)
142
+ ActiveRecord::Base.connection.migration_context.rollback(step)
133
143
  db_namespace["_dump"].invoke
134
144
  end
135
145
 
136
146
  # desc 'Pushes the schema to the next version (specify steps w/ STEP=n).'
137
- task forward: [:environment, :load_config] do
147
+ task forward: :load_config do
138
148
  step = ENV["STEP"] ? ENV["STEP"].to_i : 1
139
- ActiveRecord::Migrator.forward(ActiveRecord::Tasks::DatabaseTasks.migrations_paths, step)
149
+ ActiveRecord::Base.connection.migration_context.forward(step)
140
150
  db_namespace["_dump"].invoke
141
151
  end
142
152
 
@@ -144,12 +154,12 @@ db_namespace = namespace :db do
144
154
  task reset: [ "db:drop", "db:setup" ]
145
155
 
146
156
  # desc "Retrieves the charset for the current environment's database"
147
- task charset: [:environment, :load_config] do
157
+ task charset: :load_config do
148
158
  puts ActiveRecord::Tasks::DatabaseTasks.charset_current
149
159
  end
150
160
 
151
161
  # desc "Retrieves the collation for the current environment's database"
152
- task collation: [:environment, :load_config] do
162
+ task collation: :load_config do
153
163
  begin
154
164
  puts ActiveRecord::Tasks::DatabaseTasks.collation_current
155
165
  rescue NoMethodError
@@ -158,13 +168,13 @@ db_namespace = namespace :db do
158
168
  end
159
169
 
160
170
  desc "Retrieves the current schema version number"
161
- task version: [:environment, :load_config] do
162
- puts "Current version: #{ActiveRecord::Migrator.current_version}"
171
+ task version: :load_config do
172
+ puts "Current version: #{ActiveRecord::Base.connection.migration_context.current_version}"
163
173
  end
164
174
 
165
175
  # desc "Raises an error if there are pending migrations"
166
- task abort_if_pending_migrations: [:environment, :load_config] do
167
- pending_migrations = ActiveRecord::Migrator.open(ActiveRecord::Tasks::DatabaseTasks.migrations_paths).pending_migrations
176
+ task abort_if_pending_migrations: :load_config do
177
+ pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations
168
178
 
169
179
  if pending_migrations.any?
170
180
  puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}"
@@ -186,7 +196,7 @@ db_namespace = namespace :db do
186
196
 
187
197
  namespace :fixtures do
188
198
  desc "Loads fixtures into the current environment's database. Load specific fixtures using FIXTURES=x,y. Load from subdirectory in test/fixtures using FIXTURES_DIR=z. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures."
189
- task load: [:environment, :load_config] do
199
+ task load: :load_config do
190
200
  require "active_record/fixtures"
191
201
 
192
202
  base_dir = ActiveRecord::Tasks::DatabaseTasks.fixtures_path
@@ -208,7 +218,7 @@ db_namespace = namespace :db do
208
218
  end
209
219
 
210
220
  # desc "Search for a fixture given a LABEL or ID. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures."
211
- task identify: [:environment, :load_config] do
221
+ task identify: :load_config do
212
222
  require "active_record/fixtures"
213
223
 
214
224
  label, id = ENV["LABEL"], ENV["ID"]
@@ -219,7 +229,7 @@ db_namespace = namespace :db do
219
229
  base_dir = ActiveRecord::Tasks::DatabaseTasks.fixtures_path
220
230
 
221
231
  Dir["#{base_dir}/**/*.yml"].each do |file|
222
- if data = YAML::load(ERB.new(IO.read(file)).result)
232
+ if data = YAML.load(ERB.new(IO.read(file)).result)
223
233
  data.each_key do |key|
224
234
  key_id = ActiveRecord::FixtureSet.identify(key)
225
235
 
@@ -234,7 +244,7 @@ db_namespace = namespace :db do
234
244
 
235
245
  namespace :schema do
236
246
  desc "Creates a db/schema.rb file that is portable against any DB supported by Active Record"
237
- task dump: [:environment, :load_config] do
247
+ task dump: :load_config do
238
248
  require "active_record/schema_dumper"
239
249
  filename = ENV["SCHEMA"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema.rb")
240
250
  File.open(filename, "w:utf-8") do |file|
@@ -244,7 +254,7 @@ db_namespace = namespace :db do
244
254
  end
245
255
 
246
256
  desc "Loads a schema.rb file into the database"
247
- task load: [:environment, :load_config, :check_protected_environments] do
257
+ task load: [:load_config, :check_protected_environments] do
248
258
  ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:ruby, ENV["SCHEMA"])
249
259
  end
250
260
 
@@ -254,14 +264,14 @@ db_namespace = namespace :db do
254
264
 
255
265
  namespace :cache do
256
266
  desc "Creates a db/schema_cache.yml file."
257
- task dump: [:environment, :load_config] do
267
+ task dump: :load_config do
258
268
  conn = ActiveRecord::Base.connection
259
269
  filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.yml")
260
270
  ActiveRecord::Tasks::DatabaseTasks.dump_schema_cache(conn, filename)
261
271
  end
262
272
 
263
273
  desc "Clears a db/schema_cache.yml file."
264
- task clear: [:environment, :load_config] do
274
+ task clear: :load_config do
265
275
  filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.yml")
266
276
  rm_f filename, verbose: false
267
277
  end
@@ -271,7 +281,7 @@ db_namespace = namespace :db do
271
281
 
272
282
  namespace :structure do
273
283
  desc "Dumps the database structure to db/structure.sql. Specify another file with SCHEMA=db/my_structure.sql"
274
- task dump: [:environment, :load_config] do
284
+ task dump: :load_config do
275
285
  filename = ENV["SCHEMA"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "structure.sql")
276
286
  current_config = ActiveRecord::Tasks::DatabaseTasks.current_config
277
287
  ActiveRecord::Tasks::DatabaseTasks.structure_dump(current_config, filename)
@@ -286,7 +296,7 @@ db_namespace = namespace :db do
286
296
  end
287
297
 
288
298
  desc "Recreates the databases from the structure.sql file"
289
- task load: [:environment, :load_config, :check_protected_environments] do
299
+ task load: [:load_config, :check_protected_environments] do
290
300
  ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:sql, ENV["SCHEMA"])
291
301
  end
292
302
 
@@ -311,7 +321,7 @@ db_namespace = namespace :db do
311
321
  begin
312
322
  should_reconnect = ActiveRecord::Base.connection_pool.active_connection?
313
323
  ActiveRecord::Schema.verbose = false
314
- ActiveRecord::Tasks::DatabaseTasks.load_schema ActiveRecord::Base.configurations["test"], :ruby, ENV["SCHEMA"]
324
+ ActiveRecord::Tasks::DatabaseTasks.load_schema ActiveRecord::Base.configurations["test"], :ruby, ENV["SCHEMA"], "test"
315
325
  ensure
316
326
  if should_reconnect
317
327
  ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[ActiveRecord::Tasks::DatabaseTasks.env])
@@ -321,16 +331,16 @@ db_namespace = namespace :db do
321
331
 
322
332
  # desc "Recreate the test database from an existent structure.sql file"
323
333
  task load_structure: %w(db:test:purge) do
324
- ActiveRecord::Tasks::DatabaseTasks.load_schema ActiveRecord::Base.configurations["test"], :sql, ENV["SCHEMA"]
334
+ ActiveRecord::Tasks::DatabaseTasks.load_schema ActiveRecord::Base.configurations["test"], :sql, ENV["SCHEMA"], "test"
325
335
  end
326
336
 
327
337
  # desc "Empty the test database"
328
- task purge: %w(environment load_config check_protected_environments) do
338
+ task purge: %w(load_config check_protected_environments) do
329
339
  ActiveRecord::Tasks::DatabaseTasks.purge ActiveRecord::Base.configurations["test"]
330
340
  end
331
341
 
332
342
  # desc 'Load the test schema'
333
- task prepare: %w(environment load_config) do
343
+ task prepare: :load_config do
334
344
  unless ActiveRecord::Base.configurations.blank?
335
345
  db_namespace["test:load"].invoke
336
346
  end
@@ -1,10 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ReadonlyAttributes
3
5
  extend ActiveSupport::Concern
4
6
 
5
7
  included do
6
- class_attribute :_attr_readonly, instance_accessor: false
7
- self._attr_readonly = []
8
+ class_attribute :_attr_readonly, instance_accessor: false, default: []
8
9
  end
9
10
 
10
11
  module ClassMethods
@@ -1,6 +1,7 @@
1
- require "thread"
1
+ # frozen_string_literal: true
2
+
2
3
  require "active_support/core_ext/string/filters"
3
- require "active_support/deprecation"
4
+ require "concurrent/map"
4
5
 
5
6
  module ActiveRecord
6
7
  # = Active Record Reflection
@@ -8,10 +9,8 @@ module ActiveRecord
8
9
  extend ActiveSupport::Concern
9
10
 
10
11
  included do
11
- class_attribute :_reflections, instance_writer: false
12
- class_attribute :aggregate_reflections, instance_writer: false
13
- self._reflections = {}
14
- self.aggregate_reflections = {}
12
+ class_attribute :_reflections, instance_writer: false, default: {}
13
+ class_attribute :aggregate_reflections, instance_writer: false, default: {}
15
14
  end
16
15
 
17
16
  def self.create(macro, name, scope, options, ar)
@@ -35,7 +34,8 @@ module ActiveRecord
35
34
 
36
35
  def self.add_reflection(ar, name, reflection)
37
36
  ar.clear_reflections_cache
38
- ar._reflections = ar._reflections.merge(name.to_s => reflection)
37
+ name = name.to_s
38
+ ar._reflections = ar._reflections.except(name).merge!(name => reflection)
39
39
  end
40
40
 
41
41
  def self.add_aggregate_reflection(ar, name, reflection)
@@ -138,7 +138,7 @@ module ActiveRecord
138
138
  # HasAndBelongsToManyReflection
139
139
  # ThroughReflection
140
140
  # PolymorphicReflection
141
- # RuntimeReflection
141
+ # RuntimeReflection
142
142
  class AbstractReflection # :nodoc:
143
143
  def through_reflection?
144
144
  false
@@ -154,14 +154,6 @@ module ActiveRecord
154
154
  klass.new(attributes, &block)
155
155
  end
156
156
 
157
- def quoted_table_name
158
- klass.quoted_table_name
159
- end
160
-
161
- def primary_key_type
162
- klass.type_for_attribute(klass.primary_key)
163
- end
164
-
165
157
  # Returns the class name for the macro.
166
158
  #
167
159
  # <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
@@ -173,7 +165,7 @@ module ActiveRecord
173
165
  JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
174
166
 
175
167
  def join_keys
176
- get_join_keys klass
168
+ @join_keys ||= get_join_keys(klass)
177
169
  end
178
170
 
179
171
  # Returns a list of scopes that should be applied for this Reflection
@@ -182,37 +174,46 @@ module ActiveRecord
182
174
  scope ? [scope] : []
183
175
  end
184
176
 
185
- def scope_chain
186
- chain.map(&:scopes)
177
+ def build_join_constraint(table, foreign_table)
178
+ key = join_keys.key
179
+ foreign_key = join_keys.foreign_key
180
+
181
+ constraint = table[key].eq(foreign_table[foreign_key])
182
+
183
+ if klass.finder_needs_type_condition?
184
+ table.create_and([constraint, klass.send(:type_condition, table)])
185
+ else
186
+ constraint
187
+ end
188
+ end
189
+
190
+ def join_scope(table, foreign_klass)
191
+ predicate_builder = predicate_builder(table)
192
+ scope_chain_items = join_scopes(table, predicate_builder)
193
+ klass_scope = klass_join_scope(table, predicate_builder)
194
+
195
+ if type
196
+ klass_scope.where!(type => foreign_klass.polymorphic_name)
197
+ end
198
+
199
+ scope_chain_items.inject(klass_scope, &:merge!)
187
200
  end
188
- deprecate :scope_chain
189
201
 
190
202
  def join_scopes(table, predicate_builder) # :nodoc:
191
203
  if scope
192
- [ActiveRecord::Relation.create(klass, table, predicate_builder)
193
- .instance_exec(&scope)]
204
+ [scope_for(build_scope(table, predicate_builder))]
194
205
  else
195
206
  []
196
207
  end
197
208
  end
198
209
 
199
210
  def klass_join_scope(table, predicate_builder) # :nodoc:
200
- if klass.current_scope
201
- klass.current_scope.clone.tap { |scope|
202
- scope.joins_values = []
203
- }
204
- else
205
- relation = ActiveRecord::Relation.create(
206
- klass,
207
- table,
208
- predicate_builder,
209
- )
210
- klass.send(:build_default_scope, relation)
211
- end
211
+ relation = build_scope(table, predicate_builder)
212
+ klass.scope_for_association(relation)
212
213
  end
213
214
 
214
215
  def constraints
215
- chain.map(&:scopes).flatten
216
+ chain.flat_map(&:scopes)
216
217
  end
217
218
 
218
219
  def counter_cache_column
@@ -286,17 +287,37 @@ module ActiveRecord
286
287
  end
287
288
 
288
289
  def get_join_keys(association_klass)
289
- JoinKeys.new(join_pk(association_klass), join_fk)
290
+ JoinKeys.new(join_primary_key(association_klass), join_foreign_key)
290
291
  end
291
292
 
292
- private
293
+ def build_scope(table, predicate_builder = predicate_builder(table))
294
+ Relation.create(
295
+ klass,
296
+ table: table,
297
+ predicate_builder: predicate_builder
298
+ )
299
+ end
300
+
301
+ def join_primary_key(*)
302
+ foreign_key
303
+ end
304
+
305
+ def join_foreign_key
306
+ active_record_primary_key
307
+ end
293
308
 
294
- def join_pk(_)
295
- foreign_key
309
+ protected
310
+ def actual_source_reflection # FIXME: this is a horrible name
311
+ self
296
312
  end
297
313
 
298
- def join_fk
299
- active_record_primary_key
314
+ private
315
+ def predicate_builder(table)
316
+ PredicateBuilder.new(TableMetadata.new(klass, table))
317
+ end
318
+
319
+ def primary_key(klass)
320
+ klass.primary_key || raise(UnknownPrimaryKey.new(klass))
300
321
  end
301
322
  end
302
323
 
@@ -343,6 +364,17 @@ module ActiveRecord
343
364
  #
344
365
  # <tt>composed_of :balance, class_name: 'Money'</tt> returns the Money class
345
366
  # <tt>has_many :clients</tt> returns the Client class
367
+ #
368
+ # class Company < ActiveRecord::Base
369
+ # has_many :clients
370
+ # end
371
+ #
372
+ # Company.reflect_on_association(:clients).klass
373
+ # # => Client
374
+ #
375
+ # <b>Note:</b> Do not call +klass.new+ or +klass.create+ to instantiate
376
+ # a new association object. Use +build_association+ or +create_association+
377
+ # instead. This allows plugins to hook into association object creation.
346
378
  def klass
347
379
  @klass ||= compute_class(class_name)
348
380
  end
@@ -361,8 +393,8 @@ module ActiveRecord
361
393
  active_record == other_aggregation.active_record
362
394
  end
363
395
 
364
- def scope_for(klass)
365
- scope ? klass.unscoped.instance_exec(nil, &scope) : klass.unscoped
396
+ def scope_for(relation, owner = nil)
397
+ relation.instance_exec(owner, &scope) || relation
366
398
  end
367
399
 
368
400
  private
@@ -383,23 +415,10 @@ module ActiveRecord
383
415
  # Holds all the metadata about an association as it was specified in the
384
416
  # Active Record class.
385
417
  class AssociationReflection < MacroReflection #:nodoc:
386
- # Returns the target association's class.
387
- #
388
- # class Author < ActiveRecord::Base
389
- # has_many :books
390
- # end
391
- #
392
- # Author.reflect_on_association(:books).klass
393
- # # => Book
394
- #
395
- # <b>Note:</b> Do not call +klass.new+ or +klass.create+ to instantiate
396
- # a new association object. Use +build_association+ or +create_association+
397
- # instead. This allows plugins to hook into association object creation.
398
- def klass
399
- @klass ||= compute_class(class_name)
400
- end
401
-
402
418
  def compute_class(name)
419
+ if polymorphic?
420
+ raise ArgumentError, "Polymorphic association does not support to compute class."
421
+ end
403
422
  active_record.send(:compute_type, name)
404
423
  end
405
424
 
@@ -408,33 +427,22 @@ module ActiveRecord
408
427
 
409
428
  def initialize(name, scope, options, active_record)
410
429
  super
411
- @automatic_inverse_of = nil
412
430
  @type = options[:as] && (options[:foreign_type] || "#{options[:as]}_type")
413
- @foreign_type = options[:foreign_type] || "#{name}_type"
431
+ @foreign_type = options[:polymorphic] && (options[:foreign_type] || "#{name}_type")
414
432
  @constructable = calculate_constructable(macro, options)
415
- @association_scope_cache = {}
416
- @scope_lock = Mutex.new
433
+ @association_scope_cache = Concurrent::Map.new
417
434
 
418
435
  if options[:class_name] && options[:class_name].class == Class
419
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
420
- Passing a class to the `class_name` is deprecated and will raise
421
- an ArgumentError in Rails 5.2. It eagerloads more classes than
422
- necessary and potentially creates circular dependencies.
423
-
424
- Please pass the class name as a string:
425
- `#{macro} :#{name}, class_name: '#{options[:class_name]}'`
426
- MSG
436
+ raise ArgumentError, "A class was passed to `:class_name` but we are expecting a string."
427
437
  end
428
438
  end
429
439
 
430
- def association_scope_cache(conn, owner)
440
+ def association_scope_cache(conn, owner, &block)
431
441
  key = conn.prepared_statements
432
442
  if polymorphic?
433
443
  key = [key, owner._read_attribute(@foreign_type)]
434
444
  end
435
- @association_scope_cache[key] ||= @scope_lock.synchronize {
436
- @association_scope_cache[key] ||= yield
437
- }
445
+ @association_scope_cache.compute_if_absent(key) { StatementCache.create(conn, &block) }
438
446
  end
439
447
 
440
448
  def constructable? # :nodoc:
@@ -458,10 +466,6 @@ module ActiveRecord
458
466
  options[:primary_key] || primary_key(klass || self.klass)
459
467
  end
460
468
 
461
- def association_primary_key_type
462
- klass.type_for_attribute(association_primary_key.to_s)
463
- end
464
-
465
469
  def active_record_primary_key
466
470
  @active_record_primary_key ||= options[:primary_key] || primary_key(active_record)
467
471
  end
@@ -484,7 +488,7 @@ module ActiveRecord
484
488
  alias :check_eager_loadable! :check_preloadable!
485
489
 
486
490
  def join_id_for(owner) # :nodoc:
487
- owner[active_record_primary_key]
491
+ owner[join_foreign_key]
488
492
  end
489
493
 
490
494
  def through_reflection
@@ -567,7 +571,7 @@ module ActiveRecord
567
571
  end
568
572
 
569
573
  VALID_AUTOMATIC_INVERSE_MACROS = [:has_many, :has_one, :belongs_to]
570
- INVALID_AUTOMATIC_INVERSE_OPTIONS = [:conditions, :through, :polymorphic, :foreign_key]
574
+ INVALID_AUTOMATIC_INVERSE_OPTIONS = [:through, :foreign_key]
571
575
 
572
576
  def add_as_source(seed)
573
577
  seed
@@ -581,11 +585,9 @@ module ActiveRecord
581
585
  seed + [self]
582
586
  end
583
587
 
584
- protected
585
-
586
- def actual_source_reflection # FIXME: this is a horrible name
587
- self
588
- end
588
+ def extensions
589
+ Array(options[:extend])
590
+ end
589
591
 
590
592
  private
591
593
 
@@ -597,12 +599,14 @@ module ActiveRecord
597
599
  # If it cannot find a suitable inverse association name, it returns
598
600
  # +nil+.
599
601
  def inverse_name
600
- options.fetch(:inverse_of) do
601
- @automatic_inverse_of ||= automatic_inverse_of
602
+ unless defined?(@inverse_name)
603
+ @inverse_name = options.fetch(:inverse_of) { automatic_inverse_of }
602
604
  end
605
+
606
+ @inverse_name
603
607
  end
604
608
 
605
- # returns either false or the inverse association name that it finds.
609
+ # returns either +nil+ or the inverse association name that it finds.
606
610
  def automatic_inverse_of
607
611
  if can_find_inverse_of_automatically?(self)
608
612
  inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name.demodulize).to_sym
@@ -619,20 +623,15 @@ module ActiveRecord
619
623
  return inverse_name
620
624
  end
621
625
  end
622
-
623
- false
624
626
  end
625
627
 
626
628
  # Checks if the inverse reflection that is returned from the
627
629
  # +automatic_inverse_of+ method is a valid reflection. We must
628
630
  # make sure that the reflection's active_record name matches up
629
631
  # with the current reflection's klass name.
630
- #
631
- # Note: klass will always be valid because when there's a NameError
632
- # from calling +klass+, +reflection+ will already be set to false.
633
632
  def valid_inverse_reflection?(reflection)
634
633
  reflection &&
635
- klass.name == reflection.active_record.name &&
634
+ klass <= reflection.active_record &&
636
635
  can_find_inverse_of_automatically?(reflection)
637
636
  end
638
637
 
@@ -640,9 +639,8 @@ module ActiveRecord
640
639
  # us from being able to guess the inverse automatically. First, the
641
640
  # <tt>inverse_of</tt> option cannot be set to false. Second, we must
642
641
  # have <tt>has_many</tt>, <tt>has_one</tt>, <tt>belongs_to</tt> associations.
643
- # Third, we must not have options such as <tt>:polymorphic</tt> or
644
- # <tt>:foreign_key</tt> which prevent us from correctly guessing the
645
- # inverse association.
642
+ # Third, we must not have options such as <tt>:foreign_key</tt>
643
+ # which prevent us from correctly guessing the inverse association.
646
644
  #
647
645
  # Anything with a scope can additionally ruin our attempt at finding an
648
646
  # inverse, so we exclude reflections with scopes.
@@ -672,10 +670,6 @@ module ActiveRecord
672
670
  def derive_join_table
673
671
  ModelSchema.derive_join_table_name active_record.table_name, klass.table_name
674
672
  end
675
-
676
- def primary_key(klass)
677
- klass.primary_key || raise(UnknownPrimaryKey.new(klass))
678
- end
679
673
  end
680
674
 
681
675
  class HasManyReflection < AssociationReflection # :nodoc:
@@ -690,6 +684,10 @@ module ActiveRecord
690
684
  Associations::HasManyAssociation
691
685
  end
692
686
  end
687
+
688
+ def association_primary_key(klass = nil)
689
+ primary_key(klass || self.klass)
690
+ end
693
691
  end
694
692
 
695
693
  class HasOneReflection < AssociationReflection # :nodoc:
@@ -725,30 +723,25 @@ module ActiveRecord
725
723
  end
726
724
  end
727
725
 
728
- def join_id_for(owner) # :nodoc:
729
- owner[foreign_key]
726
+ def join_primary_key(klass = nil)
727
+ polymorphic? ? association_primary_key(klass) : association_primary_key
728
+ end
729
+
730
+ def join_foreign_key
731
+ foreign_key
730
732
  end
731
733
 
732
734
  private
735
+ def can_find_inverse_of_automatically?(_)
736
+ !polymorphic? && super
737
+ end
733
738
 
734
739
  def calculate_constructable(macro, options)
735
740
  !polymorphic?
736
741
  end
737
-
738
- def join_fk
739
- foreign_key
740
- end
741
-
742
- def join_pk(klass)
743
- polymorphic? ? association_primary_key(klass) : association_primary_key
744
- end
745
742
  end
746
743
 
747
744
  class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
748
- def initialize(name, scope, options, active_record)
749
- super
750
- end
751
-
752
745
  def macro; :has_and_belongs_to_many; end
753
746
 
754
747
  def collection?
@@ -759,8 +752,7 @@ module ActiveRecord
759
752
  # Holds all the metadata about a :through association as it was specified
760
753
  # in the Active Record class.
761
754
  class ThroughReflection < AbstractReflection #:nodoc:
762
- attr_reader :delegate_reflection
763
- delegate :foreign_key, :foreign_type, :association_foreign_key,
755
+ delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for,
764
756
  :active_record_primary_key, :type, :get_join_keys, to: :source_reflection
765
757
 
766
758
  def initialize(delegate_reflection)
@@ -851,10 +843,6 @@ module ActiveRecord
851
843
  source_reflection.join_scopes(table, predicate_builder) + super
852
844
  end
853
845
 
854
- def source_type_scope
855
- through_reflection.klass.where(foreign_type => options[:source_type])
856
- end
857
-
858
846
  def has_scope?
859
847
  scope || options[:source_type] ||
860
848
  source_reflection.has_scope? ||
@@ -875,10 +863,6 @@ module ActiveRecord
875
863
  actual_source_reflection.options[:primary_key] || primary_key(klass || self.klass)
876
864
  end
877
865
 
878
- def association_primary_key_type
879
- klass.type_for_attribute(association_primary_key.to_s)
880
- end
881
-
882
866
  # Gets an array of possible <tt>:through</tt> source reflection names in both singular and plural form.
883
867
  #
884
868
  # class Post < ActiveRecord::Base
@@ -923,10 +907,6 @@ module ActiveRecord
923
907
  through_reflection.options
924
908
  end
925
909
 
926
- def join_id_for(owner) # :nodoc:
927
- source_reflection.join_id_for(owner)
928
- end
929
-
930
910
  def check_validity!
931
911
  if through_reflection.nil?
932
912
  raise HasManyThroughAssociationNotFoundError.new(active_record.name, self)
@@ -985,23 +965,23 @@ module ActiveRecord
985
965
  collect_join_reflections(seed + [self])
986
966
  end
987
967
 
988
- def collect_join_reflections(seed)
989
- a = source_reflection.add_as_source seed
990
- if options[:source_type]
991
- through_reflection.add_as_polymorphic_through self, a
992
- else
993
- through_reflection.add_as_through a
994
- end
995
- end
996
-
997
- private
968
+ # TODO Change this to private once we've dropped Ruby 2.2 support.
969
+ # Workaround for Ruby 2.2 "private attribute?" warning.
970
+ protected
971
+ attr_reader :delegate_reflection
998
972
 
999
973
  def actual_source_reflection # FIXME: this is a horrible name
1000
- source_reflection.send(:actual_source_reflection)
974
+ source_reflection.actual_source_reflection
1001
975
  end
1002
976
 
1003
- def primary_key(klass)
1004
- klass.primary_key || raise(UnknownPrimaryKey.new(klass))
977
+ private
978
+ def collect_join_reflections(seed)
979
+ a = source_reflection.add_as_source seed
980
+ if options[:source_type]
981
+ through_reflection.add_as_polymorphic_through self, a
982
+ else
983
+ through_reflection.add_as_through a
984
+ end
1005
985
  end
1006
986
 
1007
987
  def inverse_name; delegate_reflection.send(:inverse_name); end
@@ -1018,66 +998,32 @@ module ActiveRecord
1018
998
  end
1019
999
 
1020
1000
  class PolymorphicReflection < AbstractReflection # :nodoc:
1001
+ delegate :klass, :scope, :plural_name, :type, :get_join_keys, :scope_for, to: :@reflection
1002
+
1021
1003
  def initialize(reflection, previous_reflection)
1022
1004
  @reflection = reflection
1023
1005
  @previous_reflection = previous_reflection
1024
1006
  end
1025
1007
 
1026
- def scopes
1027
- scopes = @previous_reflection.scopes
1028
- if @previous_reflection.options[:source_type]
1029
- scopes + [@previous_reflection.source_type_scope]
1030
- else
1031
- scopes
1032
- end
1033
- end
1034
-
1035
1008
  def join_scopes(table, predicate_builder) # :nodoc:
1036
1009
  scopes = @previous_reflection.join_scopes(table, predicate_builder) + super
1037
- if @previous_reflection.options[:source_type]
1038
- scopes + [@previous_reflection.source_type_scope]
1039
- else
1040
- scopes
1041
- end
1042
- end
1043
-
1044
- def klass
1045
- @reflection.klass
1046
- end
1047
-
1048
- def scope
1049
- @reflection.scope
1050
- end
1051
-
1052
- def table_name
1053
- @reflection.table_name
1054
- end
1055
-
1056
- def plural_name
1057
- @reflection.plural_name
1058
- end
1059
-
1060
- def type
1061
- @reflection.type
1010
+ scopes << build_scope(table, predicate_builder).instance_exec(nil, &source_type_scope)
1062
1011
  end
1063
1012
 
1064
1013
  def constraints
1065
- @reflection.constraints + [source_type_info]
1014
+ @reflection.constraints + [source_type_scope]
1066
1015
  end
1067
1016
 
1068
- def source_type_info
1069
- type = @previous_reflection.foreign_type
1070
- source_type = @previous_reflection.options[:source_type]
1071
- lambda { |object| where(type => source_type) }
1072
- end
1073
-
1074
- def get_join_keys(association_klass)
1075
- @reflection.get_join_keys(association_klass)
1076
- end
1017
+ private
1018
+ def source_type_scope
1019
+ type = @previous_reflection.foreign_type
1020
+ source_type = @previous_reflection.options[:source_type]
1021
+ lambda { |object| where(type => source_type) }
1022
+ end
1077
1023
  end
1078
1024
 
1079
- class RuntimeReflection < PolymorphicReflection # :nodoc:
1080
- attr_accessor :next
1025
+ class RuntimeReflection < AbstractReflection # :nodoc:
1026
+ delegate :scope, :type, :constraints, :get_join_keys, to: :@reflection
1081
1027
 
1082
1028
  def initialize(reflection, association)
1083
1029
  @reflection = reflection
@@ -1088,24 +1034,8 @@ module ActiveRecord
1088
1034
  @association.klass
1089
1035
  end
1090
1036
 
1091
- def table_name
1092
- klass.table_name
1093
- end
1094
-
1095
- def constraints
1096
- @reflection.constraints
1097
- end
1098
-
1099
- def source_type_info
1100
- @reflection.source_type_info
1101
- end
1102
-
1103
- def alias_candidate(name)
1104
- "#{plural_name}_#{name}_join"
1105
- end
1106
-
1107
- def alias_name
1108
- Arel::Table.new(table_name)
1037
+ def aliased_table
1038
+ @aliased_table ||= Arel::Table.new(table_name, type_caster: klass.type_caster)
1109
1039
  end
1110
1040
 
1111
1041
  def all_includes; yield; end