activerecord 5.1.7 → 5.2.4.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 +4 -4
  2. data/CHANGELOG.md +556 -685
  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 +40 -63
  11. data/lib/active_record/associations/alias_tracker.rb +19 -27
  12. data/lib/active_record/associations/association.rb +41 -37
  13. data/lib/active_record/associations/association_scope.rb +38 -50
  14. data/lib/active_record/associations/belongs_to_association.rb +27 -8
  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 +12 -4
  18. data/lib/active_record/associations/builder/collection_association.rb +3 -3
  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 +59 -47
  24. data/lib/active_record/associations/collection_proxy.rb +20 -49
  25. data/lib/active_record/associations/foreign_association.rb +2 -0
  26. data/lib/active_record/associations/has_many_association.rb +12 -1
  27. data/lib/active_record/associations/has_many_through_association.rb +36 -30
  28. data/lib/active_record/associations/has_one_association.rb +12 -1
  29. data/lib/active_record/associations/has_one_through_association.rb +13 -8
  30. data/lib/active_record/associations/join_dependency.rb +48 -93
  31. data/lib/active_record/associations/join_dependency/join_association.rb +39 -63
  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 +18 -38
  35. data/lib/active_record/associations/preloader/association.rb +45 -61
  36. data/lib/active_record/associations/preloader/through_association.rb +71 -79
  37. data/lib/active_record/associations/singular_association.rb +14 -16
  38. data/lib/active_record/associations/through_association.rb +26 -11
  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 +30 -214
  44. data/lib/active_record/attribute_methods/primary_key.rb +7 -6
  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 +21 -9
  50. data/lib/active_record/attributes.rb +6 -5
  51. data/lib/active_record/autosave_association.rb +35 -19
  52. data/lib/active_record/base.rb +2 -0
  53. data/lib/active_record/callbacks.rb +8 -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 +12 -8
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +139 -41
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +174 -33
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +15 -5
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +13 -31
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +14 -5
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +64 -6
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +152 -81
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +84 -97
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +92 -165
  70. data/lib/active_record/connection_adapters/column.rb +3 -1
  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 +47 -2
  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 -30
  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 +2 -0
  84. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
  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 +2 -0
  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 +2 -0
  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 -1
  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 +4 -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 +18 -0
  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 +233 -111
  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 +57 -73
  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 +22 -0
  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 +81 -94
  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 +10 -3
  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 +42 -3
  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 +5 -3
  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 +14 -17
  146. data/lib/active_record/locking/pessimistic.rb +9 -6
  147. data/lib/active_record/log_subscriber.rb +43 -0
  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 +47 -9
  151. data/lib/active_record/migration/join_table.rb +2 -0
  152. data/lib/active_record/model_schema.rb +16 -21
  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 +167 -16
  157. data/lib/active_record/query_cache.rb +6 -8
  158. data/lib/active_record/querying.rb +4 -2
  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 +46 -36
  163. data/lib/active_record/readonly_attributes.rb +3 -2
  164. data/lib/active_record/reflection.rb +108 -194
  165. data/lib/active_record/relation.rb +120 -214
  166. data/lib/active_record/relation/batches.rb +20 -5
  167. data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
  168. data/lib/active_record/relation/calculations.rb +45 -19
  169. data/lib/active_record/relation/delegation.rb +45 -27
  170. data/lib/active_record/relation/finder_methods.rb +75 -76
  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 +128 -99
  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 -68
  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 +9 -8
  194. data/lib/active_record/scoping/default.rb +8 -9
  195. data/lib/active_record/scoping/named.rb +23 -7
  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 +23 -13
  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 +25 -14
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
  206. data/lib/active_record/timestamp.rb +6 -6
  207. data/lib/active_record/touch_later.rb +2 -0
  208. data/lib/active_record/transactions.rb +33 -28
  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 +2 -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 +35 -5
  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 +23 -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 -122
  254. data/lib/active_record/attribute_set.rb +0 -113
  255. data/lib/active_record/attribute_set/builder.rb +0 -126
  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 -37
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  class Migration
3
5
  # <tt>ActiveRecord::Migration::CommandRecorder</tt> records commands done during
@@ -92,10 +94,6 @@ module ActiveRecord
92
94
  send(method, args, &block)
93
95
  end
94
96
 
95
- def respond_to_missing?(*args) # :nodoc:
96
- super || delegate.respond_to?(*args)
97
- end
98
-
99
97
  ReversibleAndIrreversibleMethods.each do |method|
100
98
  class_eval <<-EOV, __FILE__, __LINE__ + 1
101
99
  def #{method}(*args, &block) # def create_table(*args, &block)
@@ -112,7 +110,7 @@ module ActiveRecord
112
110
 
113
111
  private
114
112
 
115
- module StraightReversions
113
+ module StraightReversions # :nodoc:
116
114
  private
117
115
  { transaction: :transaction,
118
116
  execute_block: :execute_block,
@@ -163,8 +161,8 @@ module ActiveRecord
163
161
  table, columns, options = *args
164
162
  options ||= {}
165
163
 
166
- index_name = options[:name]
167
- options_hash = index_name ? { name: index_name } : { column: columns }
164
+ options_hash = options.slice(:name, :algorithm)
165
+ options_hash[:column] = columns if !options_hash[:name]
168
166
 
169
167
  [:remove_index, [table, options_hash]]
170
168
  end
@@ -225,10 +223,14 @@ module ActiveRecord
225
223
  [:add_foreign_key, reversed_args]
226
224
  end
227
225
 
226
+ def respond_to_missing?(method, _)
227
+ super || delegate.respond_to?(method)
228
+ end
229
+
228
230
  # Forwards any missing method call to the \target.
229
231
  def method_missing(method, *args, &block)
230
- if @delegate.respond_to?(method)
231
- @delegate.send(method, *args, &block)
232
+ if delegate.respond_to?(method)
233
+ delegate.public_send(method, *args, &block)
232
234
  else
233
235
  super
234
236
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  class Migration
3
5
  module Compatibility # :nodoc: all
@@ -11,10 +13,36 @@ module ActiveRecord
11
13
  const_get(name)
12
14
  end
13
15
 
14
- V5_1 = Current
16
+ V5_2 = Current
17
+
18
+ class V5_1 < V5_2
19
+ def change_column(table_name, column_name, type, options = {})
20
+ if connection.adapter_name == "PostgreSQL"
21
+ super(table_name, column_name, type, options.except(:default, :null, :comment))
22
+ connection.change_column_default(table_name, column_name, options[:default]) if options.key?(:default)
23
+ connection.change_column_null(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
24
+ connection.change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
25
+ else
26
+ super
27
+ end
28
+ end
29
+
30
+ def create_table(table_name, options = {})
31
+ if connection.adapter_name == "Mysql2"
32
+ super(table_name, options: "ENGINE=InnoDB", **options)
33
+ else
34
+ super
35
+ end
36
+ end
37
+ end
15
38
 
16
39
  class V5_0 < V5_1
17
40
  module TableDefinition
41
+ def primary_key(name, type = :primary_key, **options)
42
+ type = :integer if type == :primary_key
43
+ super
44
+ end
45
+
18
46
  def references(*args, **options)
19
47
  super(*args, type: :integer, **options)
20
48
  end
@@ -22,19 +50,19 @@ module ActiveRecord
22
50
  end
23
51
 
24
52
  def create_table(table_name, options = {})
25
- if adapter_name == "PostgreSQL"
53
+ if connection.adapter_name == "PostgreSQL"
26
54
  if options[:id] == :uuid && !options.key?(:default)
27
55
  options[:default] = "uuid_generate_v4()"
28
56
  end
29
57
  end
30
58
 
31
- unless adapter_name == "Mysql2" && options[:id] == :bigint
59
+ unless connection.adapter_name == "Mysql2" && options[:id] == :bigint
32
60
  if [:integer, :bigint].include?(options[:id]) && !options.key?(:default)
33
61
  options[:default] = nil
34
62
  end
35
63
  end
36
64
 
37
- # Since 5.1 Postgres adapter uses bigserial type for primary
65
+ # Since 5.1 PostgreSQL adapter uses bigserial type for primary
38
66
  # keys by default and MySQL uses bigint. This compat layer makes old migrations utilize
39
67
  # serial/int type instead -- the way it used to work before 5.1.
40
68
  unless options.key?(:id)
@@ -72,6 +100,14 @@ module ActiveRecord
72
100
  end
73
101
  end
74
102
 
103
+ def add_column(table_name, column_name, type, options = {})
104
+ if type == :primary_key
105
+ type = :integer
106
+ options[:primary_key] = true
107
+ end
108
+ super
109
+ end
110
+
75
111
  def add_reference(table_name, ref_name, **options)
76
112
  super(table_name, ref_name, type: :integer, **options)
77
113
  end
@@ -137,7 +173,7 @@ module ActiveRecord
137
173
  if options[:name].present?
138
174
  options[:name].to_s
139
175
  else
140
- index_name(table_name, column: column_names)
176
+ connection.index_name(table_name, column: column_names)
141
177
  end
142
178
  super
143
179
  end
@@ -157,15 +193,17 @@ module ActiveRecord
157
193
  end
158
194
 
159
195
  def index_name_for_remove(table_name, options = {})
160
- index_name = index_name(table_name, options)
196
+ index_name = connection.index_name(table_name, options)
161
197
 
162
- unless index_name_exists?(table_name, index_name)
198
+ unless connection.index_name_exists?(table_name, index_name)
163
199
  if options.is_a?(Hash) && options.has_key?(:name)
164
200
  options_without_column = options.dup
165
201
  options_without_column.delete :column
166
- index_name_without_column = index_name(table_name, options_without_column)
202
+ index_name_without_column = connection.index_name(table_name, options_without_column)
167
203
 
168
- return index_name_without_column if index_name_exists?(table_name, index_name_without_column)
204
+ if connection.index_name_exists?(table_name, index_name_without_column)
205
+ return index_name_without_column
206
+ end
169
207
  end
170
208
 
171
209
  raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' does not exist"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  class Migration
3
5
  module JoinTable #:nodoc:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "monitor"
2
4
 
3
5
  module ActiveRecord
@@ -103,20 +105,11 @@ module ActiveRecord
103
105
  included do
104
106
  mattr_accessor :primary_key_prefix_type, instance_writer: false
105
107
 
106
- class_attribute :table_name_prefix, instance_writer: false
107
- self.table_name_prefix = ""
108
-
109
- class_attribute :table_name_suffix, instance_writer: false
110
- self.table_name_suffix = ""
111
-
112
- class_attribute :schema_migrations_table_name, instance_accessor: false
113
- self.schema_migrations_table_name = "schema_migrations"
114
-
115
- class_attribute :internal_metadata_table_name, instance_accessor: false
116
- self.internal_metadata_table_name = "ar_internal_metadata"
117
-
118
- class_attribute :pluralize_table_names, instance_writer: false
119
- self.pluralize_table_names = true
108
+ class_attribute :table_name_prefix, instance_writer: false, default: ""
109
+ class_attribute :table_name_suffix, instance_writer: false, default: ""
110
+ class_attribute :schema_migrations_table_name, instance_accessor: false, default: "schema_migrations"
111
+ class_attribute :internal_metadata_table_name, instance_accessor: false, default: "ar_internal_metadata"
112
+ class_attribute :pluralize_table_names, instance_writer: false, default: true
120
113
 
121
114
  self.protected_environments = ["production"]
122
115
  self.inheritance_column = "type"
@@ -334,7 +327,7 @@ module ActiveRecord
334
327
  def attributes_builder # :nodoc:
335
328
  unless defined?(@attributes_builder) && @attributes_builder
336
329
  defaults = _default_attributes.except(*(column_names - [primary_key]))
337
- @attributes_builder = AttributeSet::Builder.new(attribute_types, defaults)
330
+ @attributes_builder = ActiveModel::AttributeSet::Builder.new(attribute_types, defaults)
338
331
  end
339
332
  @attributes_builder
340
333
  end
@@ -355,7 +348,7 @@ module ActiveRecord
355
348
  end
356
349
 
357
350
  def yaml_encoder # :nodoc:
358
- @yaml_encoder ||= AttributeSet::YAMLEncoder.new(attribute_types)
351
+ @yaml_encoder ||= ActiveModel::AttributeSet::YAMLEncoder.new(attribute_types)
359
352
  end
360
353
 
361
354
  # Returns the type of the attribute with the given name, after applying
@@ -368,8 +361,9 @@ module ActiveRecord
368
361
  # it).
369
362
  #
370
363
  # +attr_name+ The name of the attribute to retrieve the type for. Must be
371
- # a string
364
+ # a string or a symbol.
372
365
  def type_for_attribute(attr_name, &block)
366
+ attr_name = attr_name.to_s
373
367
  if block
374
368
  attribute_types.fetch(attr_name, &block)
375
369
  else
@@ -381,11 +375,12 @@ module ActiveRecord
381
375
  # default values when instantiating the Active Record object for this table.
382
376
  def column_defaults
383
377
  load_schema
384
- _default_attributes.deep_dup.to_hash
378
+ @column_defaults ||= _default_attributes.deep_dup.to_hash
385
379
  end
386
380
 
387
381
  def _default_attributes # :nodoc:
388
- @default_attributes ||= AttributeSet.new({})
382
+ load_schema
383
+ @default_attributes ||= ActiveModel::AttributeSet.new({})
389
384
  end
390
385
 
391
386
  # Returns an array of column names as strings.
@@ -432,7 +427,7 @@ module ActiveRecord
432
427
  # end
433
428
  def reset_column_information
434
429
  connection.clear_cache!
435
- undefine_attribute_methods
430
+ ([self] + descendants).each(&:undefine_attribute_methods)
436
431
  connection.schema_cache.clear_data_source_cache!(table_name)
437
432
 
438
433
  reload_schema_from_cache
@@ -480,12 +475,12 @@ module ActiveRecord
480
475
  end
481
476
 
482
477
  def reload_schema_from_cache
483
- @arel_engine = nil
484
478
  @arel_table = nil
485
479
  @column_names = nil
486
480
  @attribute_types = nil
487
481
  @content_columns = nil
488
482
  @default_attributes = nil
483
+ @column_defaults = nil
489
484
  @inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
490
485
  @attributes_builder = nil
491
486
  @columns = nil
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/hash/except"
4
+ require "active_support/core_ext/module/redefine_method"
2
5
  require "active_support/core_ext/object/try"
3
6
  require "active_support/core_ext/hash/indifferent_access"
4
7
 
@@ -10,8 +13,7 @@ module ActiveRecord
10
13
  extend ActiveSupport::Concern
11
14
 
12
15
  included do
13
- class_attribute :nested_attributes_options, instance_writer: false
14
- self.nested_attributes_options = {}
16
+ class_attribute :nested_attributes_options, instance_writer: false, default: {}
15
17
  end
16
18
 
17
19
  # = Active Record Nested Attributes
@@ -61,6 +63,18 @@ module ActiveRecord
61
63
  # member.update params[:member]
62
64
  # member.avatar.icon # => 'sad'
63
65
  #
66
+ # If you want to update the current avatar without providing the id, you must add <tt>:update_only</tt> option.
67
+ #
68
+ # class Member < ActiveRecord::Base
69
+ # has_one :avatar
70
+ # accepts_nested_attributes_for :avatar, update_only: true
71
+ # end
72
+ #
73
+ # params = { member: { avatar_attributes: { icon: 'sad' } } }
74
+ # member.update params[:member]
75
+ # member.avatar.id # => 2
76
+ # member.avatar.icon # => 'sad'
77
+ #
64
78
  # By default you will only be able to set and update attributes on the
65
79
  # associated model. If you want to destroy the associated model through the
66
80
  # attributes hash, you have to enable it first using the
@@ -354,9 +368,7 @@ module ActiveRecord
354
368
  # associations are just regular associations.
355
369
  def generate_association_writer(association_name, type)
356
370
  generated_association_methods.module_eval <<-eoruby, __FILE__, __LINE__ + 1
357
- if method_defined?(:#{association_name}_attributes=)
358
- remove_method(:#{association_name}_attributes=)
359
- end
371
+ silence_redefinition_of_method :#{association_name}_attributes=
360
372
  def #{association_name}_attributes=(attributes)
361
373
  assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes)
362
374
  end
@@ -458,7 +470,7 @@ module ActiveRecord
458
470
  end
459
471
 
460
472
  unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array)
461
- raise ArgumentError, "Hash or Array expected, got #{attributes_collection.class.name} (#{attributes_collection.inspect})"
473
+ raise ArgumentError, "Hash or Array expected for attribute `#{association_name}`, got #{attributes_collection.class.name} (#{attributes_collection.inspect})"
462
474
  end
463
475
 
464
476
  check_record_limit!(options[:limit], attributes_collection)
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  # = Active Record No Touching
3
5
  module NoTouching
4
6
  extend ActiveSupport::Concern
5
7
 
6
8
  module ClassMethods
7
- # Lets you selectively disable calls to `touch` for the
9
+ # Lets you selectively disable calls to +touch+ for the
8
10
  # duration of a block.
9
11
  #
10
12
  # ==== Examples
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module NullRelation # :nodoc:
3
5
  def pluck(*column_names)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  # = Active Record \Persistence
3
5
  module Persistence
@@ -69,6 +71,142 @@ module ActiveRecord
69
71
  klass.allocate.init_with("attributes" => attributes, "new_record" => false, &block)
70
72
  end
71
73
 
74
+ # Updates an object (or multiple objects) and saves it to the database, if validations pass.
75
+ # The resulting object is returned whether the object was saved successfully to the database or not.
76
+ #
77
+ # ==== Parameters
78
+ #
79
+ # * +id+ - This should be the id or an array of ids to be updated.
80
+ # * +attributes+ - This should be a hash of attributes or an array of hashes.
81
+ #
82
+ # ==== Examples
83
+ #
84
+ # # Updates one record
85
+ # Person.update(15, user_name: "Samuel", group: "expert")
86
+ #
87
+ # # Updates multiple records
88
+ # people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy" } }
89
+ # Person.update(people.keys, people.values)
90
+ #
91
+ # # Updates multiple records from the result of a relation
92
+ # people = Person.where(group: "expert")
93
+ # people.update(group: "masters")
94
+ #
95
+ # Note: Updating a large number of records will run an UPDATE
96
+ # query for each record, which may cause a performance issue.
97
+ # When running callbacks is not needed for each record update,
98
+ # it is preferred to use {update_all}[rdoc-ref:Relation#update_all]
99
+ # for updating all records in a single query.
100
+ def update(id = :all, attributes)
101
+ if id.is_a?(Array)
102
+ id.map { |one_id| find(one_id) }.each_with_index { |object, idx|
103
+ object.update(attributes[idx])
104
+ }
105
+ elsif id == :all
106
+ all.each { |record| record.update(attributes) }
107
+ else
108
+ if ActiveRecord::Base === id
109
+ raise ArgumentError,
110
+ "You are passing an instance of ActiveRecord::Base to `update`. " \
111
+ "Please pass the id of the object by calling `.id`."
112
+ end
113
+ object = find(id)
114
+ object.update(attributes)
115
+ object
116
+ end
117
+ end
118
+
119
+ # Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
120
+ # therefore all callbacks and filters are fired off before the object is deleted. This method is
121
+ # less efficient than #delete but allows cleanup methods and other actions to be run.
122
+ #
123
+ # This essentially finds the object (or multiple objects) with the given id, creates a new object
124
+ # from the attributes, and then calls destroy on it.
125
+ #
126
+ # ==== Parameters
127
+ #
128
+ # * +id+ - This should be the id or an array of ids to be destroyed.
129
+ #
130
+ # ==== Examples
131
+ #
132
+ # # Destroy a single object
133
+ # Todo.destroy(1)
134
+ #
135
+ # # Destroy multiple objects
136
+ # todos = [1,2,3]
137
+ # Todo.destroy(todos)
138
+ def destroy(id)
139
+ if id.is_a?(Array)
140
+ find(id).each(&:destroy)
141
+ else
142
+ find(id).destroy
143
+ end
144
+ end
145
+
146
+ # Deletes the row with a primary key matching the +id+ argument, using a
147
+ # SQL +DELETE+ statement, and returns the number of rows deleted. Active
148
+ # Record objects are not instantiated, so the object's callbacks are not
149
+ # executed, including any <tt>:dependent</tt> association options.
150
+ #
151
+ # You can delete multiple rows at once by passing an Array of <tt>id</tt>s.
152
+ #
153
+ # Note: Although it is often much faster than the alternative, #destroy,
154
+ # skipping callbacks might bypass business logic in your application
155
+ # that ensures referential integrity or performs other essential jobs.
156
+ #
157
+ # ==== Examples
158
+ #
159
+ # # Delete a single row
160
+ # Todo.delete(1)
161
+ #
162
+ # # Delete multiple rows
163
+ # Todo.delete([2,3,4])
164
+ def delete(id_or_array)
165
+ where(primary_key => id_or_array).delete_all
166
+ end
167
+
168
+ def _insert_record(values) # :nodoc:
169
+ primary_key_value = nil
170
+
171
+ if primary_key && Hash === values
172
+ primary_key_value = values[primary_key]
173
+
174
+ if !primary_key_value && prefetch_primary_key?
175
+ primary_key_value = next_sequence_value
176
+ values[primary_key] = primary_key_value
177
+ end
178
+ end
179
+
180
+ if values.empty?
181
+ im = arel_table.compile_insert(connection.empty_insert_statement_value)
182
+ im.into arel_table
183
+ else
184
+ im = arel_table.compile_insert(_substitute_values(values))
185
+ end
186
+
187
+ connection.insert(im, "#{self} Create", primary_key || false, primary_key_value)
188
+ end
189
+
190
+ def _update_record(values, constraints) # :nodoc:
191
+ constraints = _substitute_values(constraints).map { |attr, bind| attr.eq(bind) }
192
+
193
+ um = arel_table.where(
194
+ constraints.reduce(&:and)
195
+ ).compile_update(_substitute_values(values), primary_key)
196
+
197
+ connection.update(um, "#{self} Update")
198
+ end
199
+
200
+ def _delete_record(constraints) # :nodoc:
201
+ constraints = _substitute_values(constraints).map { |attr, bind| attr.eq(bind) }
202
+
203
+ dm = Arel::DeleteManager.new
204
+ dm.from(arel_table)
205
+ dm.wheres = constraints
206
+
207
+ connection.delete(dm, "#{self} Destroy")
208
+ end
209
+
72
210
  private
73
211
  # Called by +instantiate+ to decide which class to use for a new
74
212
  # record instance.
@@ -78,6 +216,14 @@ module ActiveRecord
78
216
  def discriminate_class_for_record(record)
79
217
  self
80
218
  end
219
+
220
+ def _substitute_values(values)
221
+ values.map do |name, value|
222
+ attr = arel_attribute(name)
223
+ bind = predicate_builder.build_bind_attribute(name, value)
224
+ [attr, bind]
225
+ end
226
+ end
81
227
  end
82
228
 
83
229
  # Returns true if this object hasn't been saved yet -- that is, a record
@@ -175,7 +321,7 @@ module ActiveRecord
175
321
  # callbacks or any <tt>:dependent</tt> association
176
322
  # options, use <tt>#destroy</tt>.
177
323
  def delete
178
- self.class.delete(id) if persisted?
324
+ _delete_row if persisted?
179
325
  @destroyed = true
180
326
  freeze
181
327
  end
@@ -224,9 +370,9 @@ module ActiveRecord
224
370
  # Any change to the attributes on either instance will affect both instances.
225
371
  # If you want to change the sti column as well, use #becomes! instead.
226
372
  def becomes(klass)
227
- became = klass.new
373
+ became = klass.allocate
374
+ became.send(:initialize)
228
375
  became.instance_variable_set("@attributes", @attributes)
229
- became.instance_variable_set("@mutation_tracker", @mutation_tracker ||= nil)
230
376
  became.instance_variable_set("@mutations_from_database", @mutations_from_database ||= nil)
231
377
  became.instance_variable_set("@changed_attributes", attributes_changed_by_setter)
232
378
  became.instance_variable_set("@new_record", new_record?)
@@ -327,13 +473,17 @@ module ActiveRecord
327
473
  verify_readonly_attribute(key.to_s)
328
474
  end
329
475
 
330
- updated_count = self.class.unscoped.where(self.class.primary_key => id).update_all(attributes)
331
-
476
+ id_in_database = self.id_in_database
332
477
  attributes.each do |k, v|
333
- raw_write_attribute(k, v)
478
+ write_attribute_without_type_cast(k, v)
334
479
  end
335
480
 
336
- updated_count == 1
481
+ affected_rows = self.class._update_record(
482
+ attributes,
483
+ self.class.primary_key => id_in_database
484
+ )
485
+
486
+ affected_rows == 1
337
487
  end
338
488
 
339
489
  # Initializes +attribute+ to zero if +nil+ and adds the value passed as +by+ (default is 1).
@@ -348,7 +498,7 @@ module ActiveRecord
348
498
  # Wrapper around #increment that writes the update to the database.
349
499
  # Only +attribute+ is updated; the record itself is not saved.
350
500
  # This means that any other modified attributes will still be dirty.
351
- # Validations and callbacks are skipped. Supports the `touch` option from
501
+ # Validations and callbacks are skipped. Supports the +touch+ option from
352
502
  # +update_counters+, see that for more.
353
503
  # Returns +self+.
354
504
  def increment!(attribute, by = 1, touch: nil)
@@ -369,7 +519,7 @@ module ActiveRecord
369
519
  # Wrapper around #decrement that writes the update to the database.
370
520
  # Only +attribute+ is updated; the record itself is not saved.
371
521
  # This means that any other modified attributes will still be dirty.
372
- # Validations and callbacks are skipped. Supports the `touch` option from
522
+ # Validations and callbacks are skipped. Supports the +touch+ option from
373
523
  # +update_counters+, see that for more.
374
524
  # Returns +self+.
375
525
  def decrement!(attribute, by = 1, touch: nil)
@@ -524,11 +674,11 @@ module ActiveRecord
524
674
  end
525
675
 
526
676
  def destroy_row
527
- relation_for_destroy.delete_all
677
+ _delete_row
528
678
  end
529
679
 
530
- def relation_for_destroy
531
- self.class.unscoped.where(self.class.primary_key => id)
680
+ def _delete_row
681
+ self.class._delete_record(self.class.primary_key => id_in_database)
532
682
  end
533
683
 
534
684
  def _touch_row(attribute_names, time)
@@ -543,14 +693,15 @@ module ActiveRecord
543
693
  end
544
694
 
545
695
  def _update_row(attribute_names, attempted_action = "update")
546
- self.class.unscoped._update_record(
547
- arel_attributes_with_values(attribute_names),
696
+ self.class._update_record(
697
+ attributes_with_values(attribute_names),
548
698
  self.class.primary_key => id_in_database
549
699
  )
550
700
  end
551
701
 
552
702
  def create_or_update(*args, &block)
553
703
  _raise_readonly_record_error if readonly?
704
+ return false if destroyed?
554
705
  result = new_record? ? _create_record(&block) : _update_record(*args, &block)
555
706
  result != false
556
707
  end
@@ -578,9 +729,9 @@ module ActiveRecord
578
729
  # and returns its id.
579
730
  def _create_record(attribute_names = self.attribute_names)
580
731
  attribute_names &= self.class.column_names
581
- attributes_values = arel_attributes_with_values_for_create(attribute_names)
732
+ attributes_values = attributes_with_values_for_create(attribute_names)
582
733
 
583
- new_id = self.class.unscoped.insert attributes_values
734
+ new_id = self.class._insert_record(attributes_values)
584
735
  self.id ||= new_id if self.class.primary_key
585
736
 
586
737
  @new_record = false