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
  module Associations
3
5
  class SingularAssociation < Association #:nodoc:
@@ -30,24 +32,22 @@ module ActiveRecord
30
32
  end
31
33
 
32
34
  private
33
-
34
- def create_scope
35
- scope.scope_for_create.stringify_keys.except(klass.primary_key)
35
+ def scope_for_create
36
+ super.except!(klass.primary_key)
36
37
  end
37
38
 
38
39
  def find_target
39
- return scope.take if skip_statement_cache?
40
+ scope = self.scope
41
+ return scope.take if skip_statement_cache?(scope)
40
42
 
41
43
  conn = klass.connection
42
- sc = reflection.association_scope_cache(conn, owner) do
43
- StatementCache.create(conn) { |params|
44
- as = AssociationScope.create { params.bind }
45
- target_scope.merge(as.scope(self, conn)).limit(1)
46
- }
44
+ sc = reflection.association_scope_cache(conn, owner) do |params|
45
+ as = AssociationScope.create { params.bind }
46
+ target_scope.merge!(as.scope(self)).limit(1)
47
47
  end
48
48
 
49
49
  binds = AssociationScope.get_bind_values(owner, reflection.chain)
50
- sc.execute(binds, klass, conn) do |record|
50
+ sc.execute(binds, conn) do |record|
51
51
  set_inverse_instance record
52
52
  end.first
53
53
  rescue ::RangeError
@@ -63,6 +63,10 @@ module ActiveRecord
63
63
  end
64
64
 
65
65
  def _create_record(attributes, raise_error = false)
66
+ unless owner.persisted?
67
+ raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
68
+ end
69
+
66
70
  record = build_record(attributes)
67
71
  yield(record) if block_given?
68
72
  saved = record.save
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
- # = Active Record Through Association
3
4
  module Associations
5
+ # = Active Record Through Association
4
6
  module ThroughAssociation #:nodoc:
5
7
  delegate :source_reflection, :through_reflection, to: :reflection
6
8
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_model/forbidden_attributes_protection"
2
4
 
3
5
  module ActiveRecord
@@ -1,10 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module AttributeDecorators # :nodoc:
3
5
  extend ActiveSupport::Concern
4
6
 
5
7
  included do
6
- class_attribute :attribute_type_decorations, instance_accessor: false # :internal:
7
- self.attribute_type_decorations = TypeDecorator.new
8
+ class_attribute :attribute_type_decorations, instance_accessor: false, default: TypeDecorator.new # :internal:
8
9
  end
9
10
 
10
11
  module ClassMethods # :nodoc:
@@ -1,7 +1,6 @@
1
- require "active_support/core_ext/enumerable"
2
- require "active_support/core_ext/string/filters"
1
+ # frozen_string_literal: true
2
+
3
3
  require "mutex_m"
4
- require "concurrent/map"
5
4
 
6
5
  module ActiveRecord
7
6
  # = Active Record Attribute Methods
@@ -34,7 +33,9 @@ module ActiveRecord
34
33
 
35
34
  BLACKLISTED_CLASS_METHODS = %w(private public protected allocate new name parent superclass)
36
35
 
37
- class GeneratedAttributeMethods < Module; end # :nodoc:
36
+ class GeneratedAttributeMethods < Module #:nodoc:
37
+ include Mutex_m
38
+ end
38
39
 
39
40
  module ClassMethods
40
41
  def inherited(child_class) #:nodoc:
@@ -43,7 +44,7 @@ module ActiveRecord
43
44
  end
44
45
 
45
46
  def initialize_generated_modules # :nodoc:
46
- @generated_attribute_methods = GeneratedAttributeMethods.new { extend Mutex_m }
47
+ @generated_attribute_methods = GeneratedAttributeMethods.new
47
48
  @attribute_methods_generated = false
48
49
  include @generated_attribute_methods
49
50
 
@@ -62,7 +63,6 @@ module ActiveRecord
62
63
  super(attribute_names)
63
64
  @attribute_methods_generated = true
64
65
  end
65
- true
66
66
  end
67
67
 
68
68
  def undefine_attribute_methods # :nodoc:
@@ -167,6 +167,46 @@ module ActiveRecord
167
167
  end
168
168
  end
169
169
 
170
+ # Regexp whitelist. Matches the following:
171
+ # "#{table_name}.#{column_name}"
172
+ # "#{column_name}"
173
+ COLUMN_NAME_WHITELIST = /\A(?:\w+\.)?\w+\z/i
174
+
175
+ # Regexp whitelist. Matches the following:
176
+ # "#{table_name}.#{column_name}"
177
+ # "#{table_name}.#{column_name} #{direction}"
178
+ # "#{column_name}"
179
+ # "#{column_name} #{direction}"
180
+ COLUMN_NAME_ORDER_WHITELIST = /\A(?:\w+\.)?\w+(?:\s+asc|\s+desc)?\z/i
181
+
182
+ def enforce_raw_sql_whitelist(args, whitelist: COLUMN_NAME_WHITELIST) # :nodoc:
183
+ unexpected = args.reject do |arg|
184
+ arg.kind_of?(Arel::Node) ||
185
+ arg.is_a?(Arel::Nodes::SqlLiteral) ||
186
+ arg.is_a?(Arel::Attributes::Attribute) ||
187
+ arg.to_s.split(/\s*,\s*/).all? { |part| whitelist.match?(part) }
188
+ end
189
+
190
+ return if unexpected.none?
191
+
192
+ if allow_unsafe_raw_sql == :deprecated
193
+ ActiveSupport::Deprecation.warn(
194
+ "Dangerous query method (method whose arguments are used as raw " \
195
+ "SQL) called with non-attribute argument(s): " \
196
+ "#{unexpected.map(&:inspect).join(", ")}. Non-attribute " \
197
+ "arguments will be disallowed in Rails 6.0. This method should " \
198
+ "not be called with user-provided values, such as request " \
199
+ "parameters or model attributes. Known-safe values can be passed " \
200
+ "by wrapping them in Arel.sql()."
201
+ )
202
+ else
203
+ raise(ActiveRecord::UnknownAttributeReference,
204
+ "Query method called with non-attribute argument(s): " +
205
+ unexpected.map(&:inspect).join(", ")
206
+ )
207
+ end
208
+ end
209
+
170
210
  # Returns true if the given attribute exists, otherwise false.
171
211
  #
172
212
  # class Person < ActiveRecord::Base
@@ -236,7 +276,7 @@ module ActiveRecord
236
276
  return has_attribute?(name)
237
277
  end
238
278
 
239
- return true
279
+ true
240
280
  end
241
281
 
242
282
  # Returns +true+ if the given attribute is in the attributes hash, otherwise +false+.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module AttributeMethods
3
5
  # = Active Record Attribute Methods Before Type Cast
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "active_support/core_ext/module/attribute_accessors"
3
- require "active_record/attribute_mutation_tracker"
4
4
 
5
5
  module ActiveRecord
6
6
  module AttributeMethods
@@ -14,11 +14,10 @@ module ActiveRecord
14
14
  raise "You cannot include Dirty after Timestamp"
15
15
  end
16
16
 
17
- class_attribute :partial_writes, instance_writer: false
18
- self.partial_writes = true
17
+ class_attribute :partial_writes, instance_writer: false, default: true
19
18
 
20
- after_create { changes_internally_applied }
21
- after_update { changes_internally_applied }
19
+ after_create { changes_applied }
20
+ after_update { changes_applied }
22
21
 
23
22
  # Attribute methods for "changed in last call to save?"
24
23
  attribute_method_affix(prefix: "saved_change_to_", suffix: "?")
@@ -30,107 +29,18 @@ module ActiveRecord
30
29
  attribute_method_suffix("_change_to_be_saved", "_in_database")
31
30
  end
32
31
 
33
- # Attempts to +save+ the record and clears changed attributes if successful.
34
- def save(*)
35
- if status = super
36
- changes_applied
37
- end
38
- status
39
- end
40
-
41
- # Attempts to <tt>save!</tt> the record and clears changed attributes if successful.
42
- def save!(*)
43
- super.tap do
44
- changes_applied
45
- end
46
- end
47
-
48
32
  # <tt>reload</tt> the record and clears changed attributes.
49
33
  def reload(*)
50
34
  super.tap do
51
- @previous_mutation_tracker = nil
52
- clear_mutation_trackers
53
- @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
54
- end
55
- end
56
-
57
- def initialize_dup(other) # :nodoc:
58
- super
59
- @attributes = self.class._default_attributes.map do |attr|
60
- attr.with_value_from_user(@attributes.fetch_value(attr.name))
61
- end
62
- clear_mutation_trackers
63
- end
64
-
65
- def changes_internally_applied # :nodoc:
66
- @mutations_before_last_save = mutations_from_database
67
- forget_attribute_assignments
68
- @mutations_from_database = AttributeMutationTracker.new(@attributes)
69
- end
70
-
71
- def changes_applied # :nodoc:
72
- @previous_mutation_tracker = mutation_tracker
73
- @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
74
- @mutation_tracker = nil
75
- @mutations_from_database = nil
76
- end
77
-
78
- def clear_changes_information # :nodoc:
79
- @previous_mutation_tracker = nil
80
- @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
81
- forget_attribute_assignments
82
- clear_mutation_trackers
83
- end
84
-
85
- def raw_write_attribute(attr_name, *) # :nodoc:
86
- result = super
87
- clear_attribute_change(attr_name)
88
- result
89
- end
90
-
91
- def clear_attribute_changes(attr_names) # :nodoc:
92
- super
93
- attr_names.each do |attr_name|
94
- clear_attribute_change(attr_name)
95
- end
96
- end
97
-
98
- def changed_attributes # :nodoc:
99
- # This should only be set by methods which will call changed_attributes
100
- # multiple times when it is known that the computed value cannot change.
101
- if defined?(@cached_changed_attributes)
102
- @cached_changed_attributes
103
- else
104
- emit_warning_if_needed("changed_attributes", "saved_changes.transform_values(&:first)")
105
- super.reverse_merge(mutation_tracker.changed_values).freeze
106
- end
107
- end
108
-
109
- def changes # :nodoc:
110
- cache_changed_attributes do
111
- emit_warning_if_needed("changes", "saved_changes")
112
- super
113
- end
114
- end
115
-
116
- def previous_changes # :nodoc:
117
- unless previous_mutation_tracker.equal?(mutations_before_last_save)
118
- ActiveSupport::Deprecation.warn(<<-EOW.strip_heredoc)
119
- The behavior of `previous_changes` inside of after callbacks is
120
- deprecated without replacement. In the next release of Rails,
121
- this method inside of `after_save` will return the changes that
122
- were just saved.
123
- EOW
35
+ @previously_changed = ActiveSupport::HashWithIndifferentAccess.new
36
+ @mutations_before_last_save = nil
37
+ @attributes_changed_by_setter = ActiveSupport::HashWithIndifferentAccess.new
38
+ @mutations_from_database = nil
124
39
  end
125
- previous_mutation_tracker.changes
126
- end
127
-
128
- def attribute_changed_in_place?(attr_name) # :nodoc:
129
- mutation_tracker.changed_in_place?(attr_name)
130
40
  end
131
41
 
132
42
  # Did this attribute change when we last saved? This method can be invoked
133
- # as `saved_change_to_name?` instead of `saved_change_to_attribute?("name")`.
43
+ # as +saved_change_to_name?+ instead of <tt>saved_change_to_attribute?("name")</tt>.
134
44
  # Behaves similarly to +attribute_changed?+. This method is useful in
135
45
  # after callbacks to determine if the call to save changed a certain
136
46
  # attribute.
@@ -153,8 +63,8 @@ module ActiveRecord
153
63
  # Behaves similarly to +attribute_change+. This method is useful in after
154
64
  # callbacks, to see the change in an attribute that just occurred
155
65
  #
156
- # This method can be invoked as `saved_change_to_name` in instead of
157
- # `saved_change_to_attribute("name")`
66
+ # This method can be invoked as +saved_change_to_name+ in instead of
67
+ # <tt>saved_change_to_attribute("name")</tt>
158
68
  def saved_change_to_attribute(attr_name)
159
69
  mutations_before_last_save.change_to_attribute(attr_name)
160
70
  end
@@ -167,7 +77,7 @@ module ActiveRecord
167
77
  mutations_before_last_save.original_value(attr_name)
168
78
  end
169
79
 
170
- # Did the last call to `save` have any changes to change?
80
+ # Did the last call to +save+ have any changes to change?
171
81
  def saved_changes?
172
82
  mutations_before_last_save.any_changes?
173
83
  end
@@ -177,116 +87,46 @@ module ActiveRecord
177
87
  mutations_before_last_save.changes
178
88
  end
179
89
 
180
- # Alias for `attribute_changed?`
90
+ # Alias for +attribute_changed?+
181
91
  def will_save_change_to_attribute?(attr_name, **options)
182
92
  mutations_from_database.changed?(attr_name, **options)
183
93
  end
184
94
 
185
- # Alias for `attribute_change`
95
+ # Alias for +attribute_change+
186
96
  def attribute_change_to_be_saved(attr_name)
187
97
  mutations_from_database.change_to_attribute(attr_name)
188
98
  end
189
99
 
190
- # Alias for `attribute_was`
100
+ # Alias for +attribute_was+
191
101
  def attribute_in_database(attr_name)
192
102
  mutations_from_database.original_value(attr_name)
193
103
  end
194
104
 
195
- # Alias for `changed?`
105
+ # Alias for +changed?+
196
106
  def has_changes_to_save?
197
107
  mutations_from_database.any_changes?
198
108
  end
199
109
 
200
- # Alias for `changes`
110
+ # Alias for +changes+
201
111
  def changes_to_save
202
112
  mutations_from_database.changes
203
113
  end
204
114
 
205
- # Alias for `changed`
115
+ # Alias for +changed+
206
116
  def changed_attribute_names_to_save
207
- mutations_from_database.changed_attribute_names
117
+ changes_to_save.keys
208
118
  end
209
119
 
210
- # Alias for `changed_attributes`
120
+ # Alias for +changed_attributes+
211
121
  def attributes_in_database
212
- mutations_from_database.changed_values
213
- end
214
-
215
- def attribute_was(*)
216
- emit_warning_if_needed("attribute_was", "attribute_before_last_save")
217
- super
218
- end
219
-
220
- def attribute_change(*)
221
- emit_warning_if_needed("attribute_change", "saved_change_to_attribute")
222
- super
223
- end
224
-
225
- def attribute_changed?(*)
226
- emit_warning_if_needed("attribute_changed?", "saved_change_to_attribute?")
227
- super
228
- end
229
-
230
- def changed?(*)
231
- emit_warning_if_needed("changed?", "saved_changes?")
232
- super
233
- end
234
-
235
- def changed(*)
236
- emit_warning_if_needed("changed", "saved_changes.keys")
237
- super
122
+ changes_to_save.transform_values(&:first)
238
123
  end
239
124
 
240
125
  private
241
-
242
- def mutation_tracker
243
- unless defined?(@mutation_tracker)
244
- @mutation_tracker = nil
245
- end
246
- @mutation_tracker ||= AttributeMutationTracker.new(@attributes)
247
- end
248
-
249
- def emit_warning_if_needed(method_name, new_method_name)
250
- unless mutation_tracker.equal?(mutations_from_database)
251
- ActiveSupport::Deprecation.warn(<<-EOW.squish)
252
- The behavior of `#{method_name}` inside of after callbacks will
253
- be changing in the next version of Rails. The new return value will reflect the
254
- behavior of calling the method after `save` returned (e.g. the opposite of what
255
- it returns now). To maintain the current behavior, use `#{new_method_name}`
256
- instead.
257
- EOW
258
- end
259
- end
260
-
261
- def mutations_from_database
262
- unless defined?(@mutations_from_database)
263
- @mutations_from_database = nil
264
- end
265
- @mutations_from_database ||= mutation_tracker
266
- end
267
-
268
- def changes_include?(attr_name)
269
- super || mutation_tracker.changed?(attr_name)
270
- end
271
-
272
- def clear_attribute_change(attr_name)
273
- mutation_tracker.forget_change(attr_name)
274
- mutations_from_database.forget_change(attr_name)
275
- end
276
-
277
- def attribute_will_change!(attr_name)
278
- super
279
- if self.class.has_attribute?(attr_name)
280
- mutations_from_database.force_change(attr_name)
281
- else
282
- ActiveSupport::Deprecation.warn(<<-EOW.squish)
283
- #{attr_name} is not an attribute known to Active Record.
284
- This behavior is deprecated and will be removed in the next
285
- version of Rails. If you'd like #{attr_name} to be managed
286
- by Active Record, add `attribute :#{attr_name} to your class.
287
- EOW
288
- mutations_from_database.deprecated_force_change(attr_name)
289
- end
126
+ def write_attribute_without_type_cast(attr_name, _)
127
+ result = super
128
+ clear_attribute_change(attr_name)
129
+ result
290
130
  end
291
131
 
292
132
  def _update_record(*)
@@ -300,35 +140,6 @@ module ActiveRecord
300
140
  def keys_for_partial_write
301
141
  changed_attribute_names_to_save & self.class.column_names
302
142
  end
303
-
304
- def forget_attribute_assignments
305
- @attributes = @attributes.map(&:forgetting_assignment)
306
- end
307
-
308
- def clear_mutation_trackers
309
- @mutation_tracker = nil
310
- @mutations_from_database = nil
311
- @mutations_before_last_save = nil
312
- end
313
-
314
- def previous_mutation_tracker
315
- @previous_mutation_tracker ||= NullMutationTracker.instance
316
- end
317
-
318
- def mutations_before_last_save
319
- @mutations_before_last_save ||= previous_mutation_tracker
320
- end
321
-
322
- def cache_changed_attributes
323
- @cached_changed_attributes = changed_attributes
324
- yield
325
- ensure
326
- clear_changed_attributes_cache
327
- end
328
-
329
- def clear_changed_attributes_cache
330
- remove_instance_variable(:@cached_changed_attributes) if defined?(@cached_changed_attributes)
331
- end
332
143
  end
333
144
  end
334
145
  end