activerecord 5.1.7 → 5.2.0.beta1

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 (259) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +221 -900
  3. data/README.rdoc +3 -3
  4. data/examples/performance.rb +2 -0
  5. data/examples/simple.rb +2 -0
  6. data/lib/active_record.rb +10 -3
  7. data/lib/active_record/aggregations.rb +2 -0
  8. data/lib/active_record/association_relation.rb +2 -0
  9. data/lib/active_record/associations.rb +13 -42
  10. data/lib/active_record/associations/alias_tracker.rb +17 -17
  11. data/lib/active_record/associations/association.rb +11 -22
  12. data/lib/active_record/associations/association_scope.rb +32 -44
  13. data/lib/active_record/associations/belongs_to_association.rb +6 -4
  14. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -1
  15. data/lib/active_record/associations/builder/association.rb +2 -5
  16. data/lib/active_record/associations/builder/belongs_to.rb +7 -12
  17. data/lib/active_record/associations/builder/collection_association.rb +1 -1
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
  19. data/lib/active_record/associations/builder/has_many.rb +2 -0
  20. data/lib/active_record/associations/builder/has_one.rb +2 -0
  21. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  22. data/lib/active_record/associations/collection_association.rb +41 -33
  23. data/lib/active_record/associations/collection_proxy.rb +11 -14
  24. data/lib/active_record/associations/foreign_association.rb +2 -0
  25. data/lib/active_record/associations/has_many_association.rb +4 -2
  26. data/lib/active_record/associations/has_many_through_association.rb +4 -2
  27. data/lib/active_record/associations/has_one_association.rb +3 -1
  28. data/lib/active_record/associations/has_one_through_association.rb +3 -1
  29. data/lib/active_record/associations/join_dependency.rb +22 -40
  30. data/lib/active_record/associations/join_dependency/join_association.rb +17 -56
  31. data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
  32. data/lib/active_record/associations/join_dependency/join_part.rb +2 -9
  33. data/lib/active_record/associations/preloader.rb +17 -37
  34. data/lib/active_record/associations/preloader/association.rb +42 -58
  35. data/lib/active_record/associations/preloader/through_association.rb +71 -79
  36. data/lib/active_record/associations/singular_association.rb +14 -10
  37. data/lib/active_record/associations/through_association.rb +3 -1
  38. data/lib/active_record/attribute_assignment.rb +2 -0
  39. data/lib/active_record/attribute_decorators.rb +3 -2
  40. data/lib/active_record/attribute_methods.rb +47 -7
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
  42. data/lib/active_record/attribute_methods/dirty.rb +25 -214
  43. data/lib/active_record/attribute_methods/primary_key.rb +7 -6
  44. data/lib/active_record/attribute_methods/query.rb +2 -0
  45. data/lib/active_record/attribute_methods/read.rb +8 -2
  46. data/lib/active_record/attribute_methods/serialization.rb +23 -0
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
  48. data/lib/active_record/attribute_methods/write.rb +21 -9
  49. data/lib/active_record/attributes.rb +7 -6
  50. data/lib/active_record/autosave_association.rb +5 -11
  51. data/lib/active_record/base.rb +2 -0
  52. data/lib/active_record/callbacks.rb +6 -8
  53. data/lib/active_record/coders/json.rb +2 -0
  54. data/lib/active_record/coders/yaml_column.rb +2 -0
  55. data/lib/active_record/collection_cache_key.rb +10 -5
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +110 -35
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -0
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +120 -28
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +7 -2
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +14 -33
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +13 -5
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +40 -2
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +103 -63
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +45 -9
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +62 -90
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +75 -138
  69. data/lib/active_record/connection_adapters/column.rb +3 -1
  70. data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +2 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +3 -1
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -6
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +91 -1
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -1
  86. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -11
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -1
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +3 -5
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  107. data/lib/active_record/connection_adapters/postgresql/quoting.rb +10 -0
  108. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  109. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +2 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +11 -7
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +79 -65
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -0
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +47 -82
  116. data/lib/active_record/connection_adapters/schema_cache.rb +2 -0
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
  118. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
  119. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +19 -2
  120. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
  121. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
  122. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
  123. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +71 -1
  124. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -89
  125. data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
  126. data/lib/active_record/connection_handling.rb +4 -2
  127. data/lib/active_record/core.rb +27 -57
  128. data/lib/active_record/counter_cache.rb +15 -12
  129. data/lib/active_record/define_callbacks.rb +5 -3
  130. data/lib/active_record/dynamic_matchers.rb +9 -9
  131. data/lib/active_record/enum.rb +15 -13
  132. data/lib/active_record/errors.rb +54 -21
  133. data/lib/active_record/explain.rb +3 -1
  134. data/lib/active_record/explain_registry.rb +2 -0
  135. data/lib/active_record/explain_subscriber.rb +2 -0
  136. data/lib/active_record/fixture_set/file.rb +2 -0
  137. data/lib/active_record/fixtures.rb +40 -24
  138. data/lib/active_record/gem_version.rb +5 -3
  139. data/lib/active_record/inheritance.rb +6 -5
  140. data/lib/active_record/integration.rb +58 -19
  141. data/lib/active_record/internal_metadata.rb +2 -0
  142. data/lib/active_record/legacy_yaml_adapter.rb +3 -1
  143. data/lib/active_record/locking/optimistic.rb +31 -20
  144. data/lib/active_record/locking/pessimistic.rb +10 -7
  145. data/lib/active_record/log_subscriber.rb +2 -0
  146. data/lib/active_record/migration.rb +47 -21
  147. data/lib/active_record/migration/command_recorder.rb +11 -9
  148. data/lib/active_record/migration/compatibility.rb +20 -2
  149. data/lib/active_record/migration/join_table.rb +2 -0
  150. data/lib/active_record/model_schema.rb +29 -38
  151. data/lib/active_record/nested_attributes.rb +18 -6
  152. data/lib/active_record/no_touching.rb +3 -1
  153. data/lib/active_record/null_relation.rb +2 -0
  154. data/lib/active_record/persistence.rb +184 -40
  155. data/lib/active_record/query_cache.rb +17 -12
  156. data/lib/active_record/querying.rb +3 -1
  157. data/lib/active_record/railtie.rb +54 -1
  158. data/lib/active_record/railties/console_sandbox.rb +2 -0
  159. data/lib/active_record/railties/controller_runtime.rb +2 -0
  160. data/lib/active_record/railties/databases.rake +41 -28
  161. data/lib/active_record/readonly_attributes.rb +3 -2
  162. data/lib/active_record/reflection.rb +100 -182
  163. data/lib/active_record/relation.rb +61 -193
  164. data/lib/active_record/relation/batches.rb +20 -5
  165. data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
  166. data/lib/active_record/relation/calculations.rb +40 -23
  167. data/lib/active_record/relation/delegation.rb +10 -27
  168. data/lib/active_record/relation/finder_methods.rb +53 -49
  169. data/lib/active_record/relation/from_clause.rb +2 -8
  170. data/lib/active_record/relation/merger.rb +22 -19
  171. data/lib/active_record/relation/predicate_builder.rb +42 -79
  172. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
  173. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  174. data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
  175. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
  176. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +54 -0
  177. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -6
  178. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  179. data/lib/active_record/relation/query_attribute.rb +9 -2
  180. data/lib/active_record/relation/query_methods.rb +80 -69
  181. data/lib/active_record/relation/record_fetch_warning.rb +2 -0
  182. data/lib/active_record/relation/spawn_methods.rb +2 -0
  183. data/lib/active_record/relation/where_clause.rb +50 -67
  184. data/lib/active_record/relation/where_clause_factory.rb +4 -46
  185. data/lib/active_record/result.rb +2 -0
  186. data/lib/active_record/runtime_registry.rb +2 -0
  187. data/lib/active_record/sanitization.rb +15 -9
  188. data/lib/active_record/schema.rb +3 -1
  189. data/lib/active_record/schema_dumper.rb +24 -23
  190. data/lib/active_record/schema_migration.rb +2 -0
  191. data/lib/active_record/scoping.rb +9 -8
  192. data/lib/active_record/scoping/default.rb +6 -7
  193. data/lib/active_record/scoping/named.rb +15 -7
  194. data/lib/active_record/secure_token.rb +2 -0
  195. data/lib/active_record/serialization.rb +2 -0
  196. data/lib/active_record/statement_cache.rb +22 -12
  197. data/lib/active_record/store.rb +2 -0
  198. data/lib/active_record/suppressor.rb +2 -0
  199. data/lib/active_record/table_metadata.rb +3 -1
  200. data/lib/active_record/tasks/database_tasks.rb +23 -12
  201. data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
  202. data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
  203. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
  204. data/lib/active_record/timestamp.rb +5 -12
  205. data/lib/active_record/touch_later.rb +2 -0
  206. data/lib/active_record/transactions.rb +9 -7
  207. data/lib/active_record/translation.rb +2 -0
  208. data/lib/active_record/type.rb +4 -1
  209. data/lib/active_record/type/adapter_specific_registry.rb +2 -0
  210. data/lib/active_record/type/date.rb +2 -0
  211. data/lib/active_record/type/date_time.rb +2 -0
  212. data/lib/active_record/type/decimal_without_scale.rb +2 -0
  213. data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
  214. data/lib/active_record/type/internal/timezone.rb +2 -0
  215. data/lib/active_record/type/json.rb +30 -0
  216. data/lib/active_record/type/serialized.rb +2 -4
  217. data/lib/active_record/type/text.rb +2 -0
  218. data/lib/active_record/type/time.rb +2 -0
  219. data/lib/active_record/type/type_map.rb +2 -0
  220. data/lib/active_record/type/unsigned_integer.rb +2 -0
  221. data/lib/active_record/type_caster.rb +2 -0
  222. data/lib/active_record/type_caster/connection.rb +2 -0
  223. data/lib/active_record/type_caster/map.rb +2 -0
  224. data/lib/active_record/validations.rb +2 -0
  225. data/lib/active_record/validations/absence.rb +2 -0
  226. data/lib/active_record/validations/associated.rb +2 -0
  227. data/lib/active_record/validations/length.rb +2 -0
  228. data/lib/active_record/validations/presence.rb +2 -0
  229. data/lib/active_record/validations/uniqueness.rb +36 -6
  230. data/lib/active_record/version.rb +2 -0
  231. data/lib/rails/generators/active_record.rb +3 -1
  232. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  233. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  234. data/lib/rails/generators/active_record/migration.rb +2 -0
  235. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
  236. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
  237. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
  238. data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
  239. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
  240. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  241. metadata +25 -38
  242. data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
  243. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  244. data/lib/active_record/associations/preloader/has_many.rb +0 -15
  245. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  246. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  247. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  248. data/lib/active_record/associations/preloader/singular_association.rb +0 -18
  249. data/lib/active_record/attribute.rb +0 -240
  250. data/lib/active_record/attribute/user_provided_default.rb +0 -30
  251. data/lib/active_record/attribute_mutation_tracker.rb +0 -122
  252. data/lib/active_record/attribute_set.rb +0 -113
  253. data/lib/active_record/attribute_set/builder.rb +0 -126
  254. data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
  255. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
  256. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  257. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  258. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
  259. 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,18 @@ 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
+ end
15
20
 
16
21
  class V5_0 < V5_1
17
22
  module TableDefinition
23
+ def primary_key(name, type = :primary_key, **options)
24
+ type = :integer if type == :primary_key
25
+ super
26
+ end
27
+
18
28
  def references(*args, **options)
19
29
  super(*args, type: :integer, **options)
20
30
  end
@@ -34,7 +44,7 @@ module ActiveRecord
34
44
  end
35
45
  end
36
46
 
37
- # Since 5.1 Postgres adapter uses bigserial type for primary
47
+ # Since 5.1 PostgreSQL adapter uses bigserial type for primary
38
48
  # keys by default and MySQL uses bigint. This compat layer makes old migrations utilize
39
49
  # serial/int type instead -- the way it used to work before 5.1.
40
50
  unless options.key?(:id)
@@ -72,6 +82,14 @@ module ActiveRecord
72
82
  end
73
83
  end
74
84
 
85
+ def add_column(table_name, column_name, type, options = {})
86
+ if type == :primary_key
87
+ type = :integer
88
+ options[:primary_key] = true
89
+ end
90
+ super
91
+ end
92
+
75
93
  def add_reference(table_name, ref_name, **options)
76
94
  super(table_name, ref_name, type: :integer, **options)
77
95
  end
@@ -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
@@ -84,6 +86,19 @@ module ActiveRecord
84
86
  #
85
87
  # Sets the name of the internal metadata table.
86
88
 
89
+ ##
90
+ # :singleton-method: protected_environments
91
+ # :call-seq: protected_environments
92
+ #
93
+ # The array of names of environments where destructive actions should be prohibited. By default,
94
+ # the value is <tt>["production"]</tt>.
95
+
96
+ ##
97
+ # :singleton-method: protected_environments=
98
+ # :call-seq: protected_environments=(environments)
99
+ #
100
+ # Sets an array of names of environments where destructive actions should be prohibited.
101
+
87
102
  ##
88
103
  # :singleton-method: pluralize_table_names
89
104
  # :call-seq: pluralize_table_names
@@ -103,22 +118,13 @@ module ActiveRecord
103
118
  included do
104
119
  mattr_accessor :primary_key_prefix_type, instance_writer: false
105
120
 
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"
121
+ class_attribute :table_name_prefix, instance_writer: false, default: ""
122
+ class_attribute :table_name_suffix, instance_writer: false, default: ""
123
+ class_attribute :schema_migrations_table_name, instance_accessor: false, default: "schema_migrations"
124
+ class_attribute :internal_metadata_table_name, instance_accessor: false, default: "ar_internal_metadata"
125
+ class_attribute :protected_environments, instance_accessor: false, default: [ "production" ]
126
+ class_attribute :pluralize_table_names, instance_writer: false, default: true
114
127
 
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
120
-
121
- self.protected_environments = ["production"]
122
128
  self.inheritance_column = "type"
123
129
  self.ignored_columns = [].freeze
124
130
 
@@ -232,21 +238,6 @@ module ActiveRecord
232
238
  (parents.detect { |p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix
233
239
  end
234
240
 
235
- # The array of names of environments where destructive actions should be prohibited. By default,
236
- # the value is <tt>["production"]</tt>.
237
- def protected_environments
238
- if defined?(@protected_environments)
239
- @protected_environments
240
- else
241
- superclass.protected_environments
242
- end
243
- end
244
-
245
- # Sets an array of names of environments where destructive actions should be prohibited.
246
- def protected_environments=(environments)
247
- @protected_environments = environments.map(&:to_s)
248
- end
249
-
250
241
  # Defines the name of the table column which will store the class name on single-table
251
242
  # inheritance situations.
252
243
  #
@@ -332,11 +323,11 @@ module ActiveRecord
332
323
  end
333
324
 
334
325
  def attributes_builder # :nodoc:
335
- unless defined?(@attributes_builder) && @attributes_builder
336
- defaults = _default_attributes.except(*(column_names - [primary_key]))
337
- @attributes_builder = AttributeSet::Builder.new(attribute_types, defaults)
326
+ @attributes_builder ||= ActiveModel::AttributeSet::Builder.new(attribute_types, primary_key) do |name|
327
+ unless columns_hash.key?(name)
328
+ _default_attributes[name].dup
329
+ end
338
330
  end
339
- @attributes_builder
340
331
  end
341
332
 
342
333
  def columns_hash # :nodoc:
@@ -355,7 +346,7 @@ module ActiveRecord
355
346
  end
356
347
 
357
348
  def yaml_encoder # :nodoc:
358
- @yaml_encoder ||= AttributeSet::YAMLEncoder.new(attribute_types)
349
+ @yaml_encoder ||= ActiveModel::AttributeSet::YAMLEncoder.new(attribute_types)
359
350
  end
360
351
 
361
352
  # Returns the type of the attribute with the given name, after applying
@@ -381,11 +372,11 @@ module ActiveRecord
381
372
  # default values when instantiating the Active Record object for this table.
382
373
  def column_defaults
383
374
  load_schema
384
- _default_attributes.deep_dup.to_hash
375
+ @column_defaults ||= _default_attributes.to_hash
385
376
  end
386
377
 
387
378
  def _default_attributes # :nodoc:
388
- @default_attributes ||= AttributeSet.new({})
379
+ @default_attributes ||= ActiveModel::AttributeSet.new({})
389
380
  end
390
381
 
391
382
  # Returns an array of column names as strings.
@@ -480,12 +471,12 @@ module ActiveRecord
480
471
  end
481
472
 
482
473
  def reload_schema_from_cache
483
- @arel_engine = nil
484
474
  @arel_table = nil
485
475
  @column_names = nil
486
476
  @attribute_types = nil
487
477
  @content_columns = nil
488
478
  @default_attributes = nil
479
+ @column_defaults = nil
489
480
  @inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
490
481
  @attributes_builder = nil
491
482
  @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,132 @@ 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.with_index { |one_id, idx| update(one_id, attributes[idx]) }.compact
103
+ elsif id == :all
104
+ all.each { |record| record.update(attributes) }
105
+ else
106
+ if ActiveRecord::Base === id
107
+ raise ArgumentError,
108
+ "You are passing an instance of ActiveRecord::Base to `update`. " \
109
+ "Please pass the id of the object by calling `.id`."
110
+ end
111
+ object = find(id)
112
+ object.update(attributes)
113
+ object
114
+ end
115
+ rescue RecordNotFound
116
+ end
117
+
118
+ # Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
119
+ # therefore all callbacks and filters are fired off before the object is deleted. This method is
120
+ # less efficient than #delete but allows cleanup methods and other actions to be run.
121
+ #
122
+ # This essentially finds the object (or multiple objects) with the given id, creates a new object
123
+ # from the attributes, and then calls destroy on it.
124
+ #
125
+ # ==== Parameters
126
+ #
127
+ # * +id+ - This should be the id or an array of ids to be destroyed.
128
+ #
129
+ # ==== Examples
130
+ #
131
+ # # Destroy a single object
132
+ # Todo.destroy(1)
133
+ #
134
+ # # Destroy multiple objects
135
+ # todos = [1,2,3]
136
+ # Todo.destroy(todos)
137
+ def destroy(id)
138
+ if id.is_a?(Array)
139
+ id.map { |one_id| destroy(one_id) }.compact
140
+ else
141
+ find(id).destroy
142
+ end
143
+ rescue RecordNotFound
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
+ arel_primary_key = arel_attribute(primary_key)
173
+ primary_key_value = values[arel_primary_key]
174
+
175
+ if !primary_key_value && prefetch_primary_key?
176
+ primary_key_value = next_sequence_value
177
+ values[arel_primary_key] = primary_key_value
178
+ end
179
+ end
180
+
181
+ if values.empty?
182
+ im = arel_table.compile_insert(connection.empty_insert_statement_value)
183
+ im.into arel_table
184
+ else
185
+ im = arel_table.compile_insert(_substitute_values(values))
186
+ end
187
+
188
+ connection.insert(im, "#{self} Create", primary_key || false, primary_key_value)
189
+ end
190
+
191
+ def _update_record(values, id, id_was) # :nodoc:
192
+ bind = predicate_builder.build_bind_attribute(primary_key, id_was || id)
193
+ um = arel_table.where(
194
+ arel_attribute(primary_key).eq(bind)
195
+ ).compile_update(_substitute_values(values), primary_key)
196
+
197
+ connection.update(um, "#{self} Update")
198
+ end
199
+
72
200
  private
73
201
  # Called by +instantiate+ to decide which class to use for a new
74
202
  # record instance.
@@ -78,6 +206,13 @@ module ActiveRecord
78
206
  def discriminate_class_for_record(record)
79
207
  self
80
208
  end
209
+
210
+ def _substitute_values(values)
211
+ values.map do |attr, value|
212
+ bind = predicate_builder.build_bind_attribute(attr.name, value)
213
+ [attr, bind]
214
+ end
215
+ end
81
216
  end
82
217
 
83
218
  # Returns true if this object hasn't been saved yet -- that is, a record
@@ -175,7 +310,7 @@ module ActiveRecord
175
310
  # callbacks or any <tt>:dependent</tt> association
176
311
  # options, use <tt>#destroy</tt>.
177
312
  def delete
178
- self.class.delete(id) if persisted?
313
+ _relation_for_itself.delete_all if persisted?
179
314
  @destroyed = true
180
315
  freeze
181
316
  end
@@ -226,8 +361,7 @@ module ActiveRecord
226
361
  def becomes(klass)
227
362
  became = klass.new
228
363
  became.instance_variable_set("@attributes", @attributes)
229
- became.instance_variable_set("@mutation_tracker", @mutation_tracker ||= nil)
230
- became.instance_variable_set("@mutations_from_database", @mutations_from_database ||= nil)
364
+ became.instance_variable_set("@mutations_from_database", @mutations_from_database) if defined?(@mutations_from_database)
231
365
  became.instance_variable_set("@changed_attributes", attributes_changed_by_setter)
232
366
  became.instance_variable_set("@new_record", new_record?)
233
367
  became.instance_variable_set("@destroyed", destroyed?)
@@ -268,7 +402,11 @@ module ActiveRecord
268
402
  verify_readonly_attribute(name)
269
403
  public_send("#{name}=", value)
270
404
 
271
- save(validate: false)
405
+ if has_changes_to_save?
406
+ save(validate: false)
407
+ else
408
+ true
409
+ end
272
410
  end
273
411
 
274
412
  # Updates the attributes of the model from the passed-in hash and saves the
@@ -327,10 +465,10 @@ module ActiveRecord
327
465
  verify_readonly_attribute(key.to_s)
328
466
  end
329
467
 
330
- updated_count = self.class.unscoped.where(self.class.primary_key => id).update_all(attributes)
468
+ updated_count = _relation_for_itself.update_all(attributes)
331
469
 
332
470
  attributes.each do |k, v|
333
- raw_write_attribute(k, v)
471
+ write_attribute_without_type_cast(k, v)
334
472
  end
335
473
 
336
474
  updated_count == 1
@@ -348,7 +486,7 @@ module ActiveRecord
348
486
  # Wrapper around #increment that writes the update to the database.
349
487
  # Only +attribute+ is updated; the record itself is not saved.
350
488
  # This means that any other modified attributes will still be dirty.
351
- # Validations and callbacks are skipped. Supports the `touch` option from
489
+ # Validations and callbacks are skipped. Supports the +touch+ option from
352
490
  # +update_counters+, see that for more.
353
491
  # Returns +self+.
354
492
  def increment!(attribute, by = 1, touch: nil)
@@ -369,7 +507,7 @@ module ActiveRecord
369
507
  # Wrapper around #decrement that writes the update to the database.
370
508
  # Only +attribute+ is updated; the record itself is not saved.
371
509
  # This means that any other modified attributes will still be dirty.
372
- # Validations and callbacks are skipped. Supports the `touch` option from
510
+ # Validations and callbacks are skipped. Supports the +touch+ option from
373
511
  # +update_counters+, see that for more.
374
512
  # Returns +self+.
375
513
  def decrement!(attribute, by = 1, touch: nil)
@@ -506,12 +644,35 @@ module ActiveRecord
506
644
  MSG
507
645
  end
508
646
 
509
- attribute_names = timestamp_attributes_for_update_in_model
510
- attribute_names |= names.map(&:to_s)
647
+ time ||= current_time_from_proper_timezone
648
+ attributes = timestamp_attributes_for_update_in_model
649
+ attributes.concat(names)
650
+
651
+ unless attributes.empty?
652
+ changes = {}
511
653
 
512
- unless attribute_names.empty?
513
- affected_rows = _touch_row(attribute_names, time)
514
- @_trigger_update_callback = affected_rows == 1
654
+ attributes.each do |column|
655
+ column = column.to_s
656
+ changes[column] = write_attribute(column, time)
657
+ end
658
+
659
+ scope = _relation_for_itself
660
+
661
+ if locking_enabled?
662
+ locking_column = self.class.locking_column
663
+ scope = scope.where(locking_column => read_attribute_before_type_cast(locking_column))
664
+ changes[locking_column] = increment_lock
665
+ end
666
+
667
+ clear_attribute_changes(changes.keys)
668
+ result = scope.update_all(changes) == 1
669
+
670
+ if !result && locking_enabled?
671
+ raise ActiveRecord::StaleObjectError.new(self, "touch")
672
+ end
673
+
674
+ @_trigger_update_callback = result
675
+ result
515
676
  else
516
677
  true
517
678
  end
@@ -528,25 +689,11 @@ module ActiveRecord
528
689
  end
529
690
 
530
691
  def relation_for_destroy
531
- self.class.unscoped.where(self.class.primary_key => id)
692
+ _relation_for_itself
532
693
  end
533
694
 
534
- def _touch_row(attribute_names, time)
535
- time ||= current_time_from_proper_timezone
536
-
537
- attribute_names.each do |attr_name|
538
- write_attribute(attr_name, time)
539
- clear_attribute_change(attr_name)
540
- end
541
-
542
- _update_row(attribute_names, "touch")
543
- end
544
-
545
- def _update_row(attribute_names, attempted_action = "update")
546
- self.class.unscoped._update_record(
547
- arel_attributes_with_values(attribute_names),
548
- self.class.primary_key => id_in_database
549
- )
695
+ def _relation_for_itself
696
+ self.class.unscoped.where(self.class.primary_key => id)
550
697
  end
551
698
 
552
699
  def create_or_update(*args, &block)
@@ -558,29 +705,26 @@ module ActiveRecord
558
705
  # Updates the associated record with values matching those of the instance attributes.
559
706
  # Returns the number of affected rows.
560
707
  def _update_record(attribute_names = self.attribute_names)
561
- attribute_names &= self.class.column_names
562
- attribute_names = attributes_for_update(attribute_names)
563
-
564
- if attribute_names.empty?
565
- affected_rows = 0
708
+ attributes_values = arel_attributes_with_values_for_update(attribute_names)
709
+ if attributes_values.empty?
710
+ rows_affected = 0
566
711
  @_trigger_update_callback = true
567
712
  else
568
- affected_rows = _update_row(attribute_names)
569
- @_trigger_update_callback = affected_rows == 1
713
+ rows_affected = self.class._update_record(attributes_values, id, id_in_database)
714
+ @_trigger_update_callback = rows_affected > 0
570
715
  end
571
716
 
572
717
  yield(self) if block_given?
573
718
 
574
- affected_rows
719
+ rows_affected
575
720
  end
576
721
 
577
722
  # Creates a record with values matching those of the instance attributes
578
723
  # and returns its id.
579
724
  def _create_record(attribute_names = self.attribute_names)
580
- attribute_names &= self.class.column_names
581
725
  attributes_values = arel_attributes_with_values_for_create(attribute_names)
582
726
 
583
- new_id = self.class.unscoped.insert attributes_values
727
+ new_id = self.class._insert_record(attributes_values)
584
728
  self.id ||= new_id if self.class.primary_key
585
729
 
586
730
  @new_record = false