activerecord 5.2.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (244) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +937 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +217 -0
  5. data/examples/performance.rb +185 -0
  6. data/examples/simple.rb +15 -0
  7. data/lib/active_record.rb +188 -0
  8. data/lib/active_record/aggregations.rb +283 -0
  9. data/lib/active_record/association_relation.rb +40 -0
  10. data/lib/active_record/associations.rb +1860 -0
  11. data/lib/active_record/associations/alias_tracker.rb +81 -0
  12. data/lib/active_record/associations/association.rb +299 -0
  13. data/lib/active_record/associations/association_scope.rb +168 -0
  14. data/lib/active_record/associations/belongs_to_association.rb +130 -0
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +40 -0
  16. data/lib/active_record/associations/builder/association.rb +140 -0
  17. data/lib/active_record/associations/builder/belongs_to.rb +163 -0
  18. data/lib/active_record/associations/builder/collection_association.rb +82 -0
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +135 -0
  20. data/lib/active_record/associations/builder/has_many.rb +17 -0
  21. data/lib/active_record/associations/builder/has_one.rb +30 -0
  22. data/lib/active_record/associations/builder/singular_association.rb +42 -0
  23. data/lib/active_record/associations/collection_association.rb +513 -0
  24. data/lib/active_record/associations/collection_proxy.rb +1131 -0
  25. data/lib/active_record/associations/foreign_association.rb +13 -0
  26. data/lib/active_record/associations/has_many_association.rb +144 -0
  27. data/lib/active_record/associations/has_many_through_association.rb +227 -0
  28. data/lib/active_record/associations/has_one_association.rb +120 -0
  29. data/lib/active_record/associations/has_one_through_association.rb +45 -0
  30. data/lib/active_record/associations/join_dependency.rb +262 -0
  31. data/lib/active_record/associations/join_dependency/join_association.rb +60 -0
  32. data/lib/active_record/associations/join_dependency/join_base.rb +23 -0
  33. data/lib/active_record/associations/join_dependency/join_part.rb +71 -0
  34. data/lib/active_record/associations/preloader.rb +193 -0
  35. data/lib/active_record/associations/preloader/association.rb +131 -0
  36. data/lib/active_record/associations/preloader/through_association.rb +107 -0
  37. data/lib/active_record/associations/singular_association.rb +73 -0
  38. data/lib/active_record/associations/through_association.rb +121 -0
  39. data/lib/active_record/attribute_assignment.rb +88 -0
  40. data/lib/active_record/attribute_decorators.rb +90 -0
  41. data/lib/active_record/attribute_methods.rb +492 -0
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +78 -0
  43. data/lib/active_record/attribute_methods/dirty.rb +150 -0
  44. data/lib/active_record/attribute_methods/primary_key.rb +143 -0
  45. data/lib/active_record/attribute_methods/query.rb +42 -0
  46. data/lib/active_record/attribute_methods/read.rb +85 -0
  47. data/lib/active_record/attribute_methods/serialization.rb +90 -0
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +91 -0
  49. data/lib/active_record/attribute_methods/write.rb +68 -0
  50. data/lib/active_record/attributes.rb +266 -0
  51. data/lib/active_record/autosave_association.rb +498 -0
  52. data/lib/active_record/base.rb +329 -0
  53. data/lib/active_record/callbacks.rb +353 -0
  54. data/lib/active_record/coders/json.rb +15 -0
  55. data/lib/active_record/coders/yaml_column.rb +50 -0
  56. data/lib/active_record/collection_cache_key.rb +53 -0
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +1068 -0
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +72 -0
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +540 -0
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +145 -0
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +200 -0
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +146 -0
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +685 -0
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +95 -0
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1396 -0
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +283 -0
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +628 -0
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +887 -0
  70. data/lib/active_record/connection_adapters/column.rb +91 -0
  71. data/lib/active_record/connection_adapters/connection_specification.rb +287 -0
  72. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
  73. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  74. data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
  75. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  76. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
  80. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
  81. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
  82. data/lib/active_record/connection_adapters/mysql2_adapter.rb +129 -0
  83. data/lib/active_record/connection_adapters/postgresql/column.rb +44 -0
  84. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +163 -0
  85. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +92 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +56 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -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 +23 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +41 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +111 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +23 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
  109. data/lib/active_record/connection_adapters/postgresql/quoting.rb +168 -0
  110. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +206 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  114. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +774 -0
  115. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
  116. data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
  117. data/lib/active_record/connection_adapters/postgresql_adapter.rb +863 -0
  118. data/lib/active_record/connection_adapters/schema_cache.rb +118 -0
  119. data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
  120. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  121. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
  126. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +573 -0
  127. data/lib/active_record/connection_adapters/statement_pool.rb +61 -0
  128. data/lib/active_record/connection_handling.rb +145 -0
  129. data/lib/active_record/core.rb +559 -0
  130. data/lib/active_record/counter_cache.rb +218 -0
  131. data/lib/active_record/define_callbacks.rb +22 -0
  132. data/lib/active_record/dynamic_matchers.rb +122 -0
  133. data/lib/active_record/enum.rb +244 -0
  134. data/lib/active_record/errors.rb +380 -0
  135. data/lib/active_record/explain.rb +50 -0
  136. data/lib/active_record/explain_registry.rb +32 -0
  137. data/lib/active_record/explain_subscriber.rb +34 -0
  138. data/lib/active_record/fixture_set/file.rb +82 -0
  139. data/lib/active_record/fixtures.rb +1065 -0
  140. data/lib/active_record/gem_version.rb +17 -0
  141. data/lib/active_record/inheritance.rb +283 -0
  142. data/lib/active_record/integration.rb +155 -0
  143. data/lib/active_record/internal_metadata.rb +45 -0
  144. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  145. data/lib/active_record/locale/en.yml +48 -0
  146. data/lib/active_record/locking/optimistic.rb +198 -0
  147. data/lib/active_record/locking/pessimistic.rb +89 -0
  148. data/lib/active_record/log_subscriber.rb +137 -0
  149. data/lib/active_record/migration.rb +1378 -0
  150. data/lib/active_record/migration/command_recorder.rb +240 -0
  151. data/lib/active_record/migration/compatibility.rb +217 -0
  152. data/lib/active_record/migration/join_table.rb +17 -0
  153. data/lib/active_record/model_schema.rb +521 -0
  154. data/lib/active_record/nested_attributes.rb +600 -0
  155. data/lib/active_record/no_touching.rb +58 -0
  156. data/lib/active_record/null_relation.rb +68 -0
  157. data/lib/active_record/persistence.rb +763 -0
  158. data/lib/active_record/query_cache.rb +45 -0
  159. data/lib/active_record/querying.rb +70 -0
  160. data/lib/active_record/railtie.rb +226 -0
  161. data/lib/active_record/railties/console_sandbox.rb +7 -0
  162. data/lib/active_record/railties/controller_runtime.rb +56 -0
  163. data/lib/active_record/railties/databases.rake +377 -0
  164. data/lib/active_record/readonly_attributes.rb +24 -0
  165. data/lib/active_record/reflection.rb +1044 -0
  166. data/lib/active_record/relation.rb +629 -0
  167. data/lib/active_record/relation/batches.rb +287 -0
  168. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  169. data/lib/active_record/relation/calculations.rb +417 -0
  170. data/lib/active_record/relation/delegation.rb +147 -0
  171. data/lib/active_record/relation/finder_methods.rb +565 -0
  172. data/lib/active_record/relation/from_clause.rb +26 -0
  173. data/lib/active_record/relation/merger.rb +193 -0
  174. data/lib/active_record/relation/predicate_builder.rb +152 -0
  175. data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
  176. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  177. data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
  178. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
  179. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  180. data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
  181. data/lib/active_record/relation/predicate_builder/relation_handler.rb +19 -0
  182. data/lib/active_record/relation/query_attribute.rb +45 -0
  183. data/lib/active_record/relation/query_methods.rb +1231 -0
  184. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  185. data/lib/active_record/relation/spawn_methods.rb +77 -0
  186. data/lib/active_record/relation/where_clause.rb +186 -0
  187. data/lib/active_record/relation/where_clause_factory.rb +34 -0
  188. data/lib/active_record/result.rb +149 -0
  189. data/lib/active_record/runtime_registry.rb +24 -0
  190. data/lib/active_record/sanitization.rb +222 -0
  191. data/lib/active_record/schema.rb +70 -0
  192. data/lib/active_record/schema_dumper.rb +255 -0
  193. data/lib/active_record/schema_migration.rb +56 -0
  194. data/lib/active_record/scoping.rb +106 -0
  195. data/lib/active_record/scoping/default.rb +152 -0
  196. data/lib/active_record/scoping/named.rb +213 -0
  197. data/lib/active_record/secure_token.rb +40 -0
  198. data/lib/active_record/serialization.rb +22 -0
  199. data/lib/active_record/statement_cache.rb +121 -0
  200. data/lib/active_record/store.rb +211 -0
  201. data/lib/active_record/suppressor.rb +61 -0
  202. data/lib/active_record/table_metadata.rb +82 -0
  203. data/lib/active_record/tasks/database_tasks.rb +337 -0
  204. data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
  205. data/lib/active_record/tasks/postgresql_database_tasks.rb +143 -0
  206. data/lib/active_record/tasks/sqlite_database_tasks.rb +83 -0
  207. data/lib/active_record/timestamp.rb +153 -0
  208. data/lib/active_record/touch_later.rb +64 -0
  209. data/lib/active_record/transactions.rb +502 -0
  210. data/lib/active_record/translation.rb +24 -0
  211. data/lib/active_record/type.rb +79 -0
  212. data/lib/active_record/type/adapter_specific_registry.rb +136 -0
  213. data/lib/active_record/type/date.rb +9 -0
  214. data/lib/active_record/type/date_time.rb +9 -0
  215. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  216. data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
  217. data/lib/active_record/type/internal/timezone.rb +17 -0
  218. data/lib/active_record/type/json.rb +30 -0
  219. data/lib/active_record/type/serialized.rb +71 -0
  220. data/lib/active_record/type/text.rb +11 -0
  221. data/lib/active_record/type/time.rb +21 -0
  222. data/lib/active_record/type/type_map.rb +62 -0
  223. data/lib/active_record/type/unsigned_integer.rb +17 -0
  224. data/lib/active_record/type_caster.rb +9 -0
  225. data/lib/active_record/type_caster/connection.rb +33 -0
  226. data/lib/active_record/type_caster/map.rb +23 -0
  227. data/lib/active_record/validations.rb +93 -0
  228. data/lib/active_record/validations/absence.rb +25 -0
  229. data/lib/active_record/validations/associated.rb +60 -0
  230. data/lib/active_record/validations/length.rb +26 -0
  231. data/lib/active_record/validations/presence.rb +68 -0
  232. data/lib/active_record/validations/uniqueness.rb +238 -0
  233. data/lib/active_record/version.rb +10 -0
  234. data/lib/rails/generators/active_record.rb +19 -0
  235. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  236. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  237. data/lib/rails/generators/active_record/migration.rb +35 -0
  238. data/lib/rails/generators/active_record/migration/migration_generator.rb +78 -0
  239. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  240. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +46 -0
  241. data/lib/rails/generators/active_record/model/model_generator.rb +48 -0
  242. data/lib/rails/generators/active_record/model/templates/model.rb.tt +13 -0
  243. data/lib/rails/generators/active_record/model/templates/module.rb.tt +7 -0
  244. metadata +333 -0
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module AttributeMethods
5
+ # = Active Record Attribute Methods Before Type Cast
6
+ #
7
+ # ActiveRecord::AttributeMethods::BeforeTypeCast provides a way to
8
+ # read the value of the attributes before typecasting and deserialization.
9
+ #
10
+ # class Task < ActiveRecord::Base
11
+ # end
12
+ #
13
+ # task = Task.new(id: '1', completed_on: '2012-10-21')
14
+ # task.id # => 1
15
+ # task.completed_on # => Sun, 21 Oct 2012
16
+ #
17
+ # task.attributes_before_type_cast
18
+ # # => {"id"=>"1", "completed_on"=>"2012-10-21", ... }
19
+ # task.read_attribute_before_type_cast('id') # => "1"
20
+ # task.read_attribute_before_type_cast('completed_on') # => "2012-10-21"
21
+ #
22
+ # In addition to #read_attribute_before_type_cast and #attributes_before_type_cast,
23
+ # it declares a method for all attributes with the <tt>*_before_type_cast</tt>
24
+ # suffix.
25
+ #
26
+ # task.id_before_type_cast # => "1"
27
+ # task.completed_on_before_type_cast # => "2012-10-21"
28
+ module BeforeTypeCast
29
+ extend ActiveSupport::Concern
30
+
31
+ included do
32
+ attribute_method_suffix "_before_type_cast"
33
+ attribute_method_suffix "_came_from_user?"
34
+ end
35
+
36
+ # Returns the value of the attribute identified by +attr_name+ before
37
+ # typecasting and deserialization.
38
+ #
39
+ # class Task < ActiveRecord::Base
40
+ # end
41
+ #
42
+ # task = Task.new(id: '1', completed_on: '2012-10-21')
43
+ # task.read_attribute('id') # => 1
44
+ # task.read_attribute_before_type_cast('id') # => '1'
45
+ # task.read_attribute('completed_on') # => Sun, 21 Oct 2012
46
+ # task.read_attribute_before_type_cast('completed_on') # => "2012-10-21"
47
+ # task.read_attribute_before_type_cast(:completed_on) # => "2012-10-21"
48
+ def read_attribute_before_type_cast(attr_name)
49
+ @attributes[attr_name.to_s].value_before_type_cast
50
+ end
51
+
52
+ # Returns a hash of attributes before typecasting and deserialization.
53
+ #
54
+ # class Task < ActiveRecord::Base
55
+ # end
56
+ #
57
+ # task = Task.new(title: nil, is_done: true, completed_on: '2012-10-21')
58
+ # task.attributes
59
+ # # => {"id"=>nil, "title"=>nil, "is_done"=>true, "completed_on"=>Sun, 21 Oct 2012, "created_at"=>nil, "updated_at"=>nil}
60
+ # task.attributes_before_type_cast
61
+ # # => {"id"=>nil, "title"=>nil, "is_done"=>true, "completed_on"=>"2012-10-21", "created_at"=>nil, "updated_at"=>nil}
62
+ def attributes_before_type_cast
63
+ @attributes.values_before_type_cast
64
+ end
65
+
66
+ private
67
+
68
+ # Handle *_before_type_cast for method_missing.
69
+ def attribute_before_type_cast(attribute_name)
70
+ read_attribute_before_type_cast(attribute_name)
71
+ end
72
+
73
+ def attribute_came_from_user?(attribute_name)
74
+ @attributes[attribute_name].came_from_user?
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/attribute_accessors"
4
+
5
+ module ActiveRecord
6
+ module AttributeMethods
7
+ module Dirty
8
+ extend ActiveSupport::Concern
9
+
10
+ include ActiveModel::Dirty
11
+
12
+ included do
13
+ if self < ::ActiveRecord::Timestamp
14
+ raise "You cannot include Dirty after Timestamp"
15
+ end
16
+
17
+ class_attribute :partial_writes, instance_writer: false, default: true
18
+
19
+ # Attribute methods for "changed in last call to save?"
20
+ attribute_method_affix(prefix: "saved_change_to_", suffix: "?")
21
+ attribute_method_prefix("saved_change_to_")
22
+ attribute_method_suffix("_before_last_save")
23
+
24
+ # Attribute methods for "will change if I call save?"
25
+ attribute_method_affix(prefix: "will_save_change_to_", suffix: "?")
26
+ attribute_method_suffix("_change_to_be_saved", "_in_database")
27
+ end
28
+
29
+ # <tt>reload</tt> the record and clears changed attributes.
30
+ def reload(*)
31
+ super.tap do
32
+ @previously_changed = ActiveSupport::HashWithIndifferentAccess.new
33
+ @mutations_before_last_save = nil
34
+ @attributes_changed_by_setter = ActiveSupport::HashWithIndifferentAccess.new
35
+ @mutations_from_database = nil
36
+ end
37
+ end
38
+
39
+ # Did this attribute change when we last saved? This method can be invoked
40
+ # as +saved_change_to_name?+ instead of <tt>saved_change_to_attribute?("name")</tt>.
41
+ # Behaves similarly to +attribute_changed?+. This method is useful in
42
+ # after callbacks to determine if the call to save changed a certain
43
+ # attribute.
44
+ #
45
+ # ==== Options
46
+ #
47
+ # +from+ When passed, this method will return false unless the original
48
+ # value is equal to the given option
49
+ #
50
+ # +to+ When passed, this method will return false unless the value was
51
+ # changed to the given value
52
+ def saved_change_to_attribute?(attr_name, **options)
53
+ mutations_before_last_save.changed?(attr_name, **options)
54
+ end
55
+
56
+ # Returns the change to an attribute during the last save. If the
57
+ # attribute was changed, the result will be an array containing the
58
+ # original value and the saved value.
59
+ #
60
+ # Behaves similarly to +attribute_change+. This method is useful in after
61
+ # callbacks, to see the change in an attribute that just occurred
62
+ #
63
+ # This method can be invoked as +saved_change_to_name+ in instead of
64
+ # <tt>saved_change_to_attribute("name")</tt>
65
+ def saved_change_to_attribute(attr_name)
66
+ mutations_before_last_save.change_to_attribute(attr_name)
67
+ end
68
+
69
+ # Returns the original value of an attribute before the last save.
70
+ # Behaves similarly to +attribute_was+. This method is useful in after
71
+ # callbacks to get the original value of an attribute before the save that
72
+ # just occurred
73
+ def attribute_before_last_save(attr_name)
74
+ mutations_before_last_save.original_value(attr_name)
75
+ end
76
+
77
+ # Did the last call to +save+ have any changes to change?
78
+ def saved_changes?
79
+ mutations_before_last_save.any_changes?
80
+ end
81
+
82
+ # Returns a hash containing all the changes that were just saved.
83
+ def saved_changes
84
+ mutations_before_last_save.changes
85
+ end
86
+
87
+ # Alias for +attribute_changed?+
88
+ def will_save_change_to_attribute?(attr_name, **options)
89
+ mutations_from_database.changed?(attr_name, **options)
90
+ end
91
+
92
+ # Alias for +attribute_change+
93
+ def attribute_change_to_be_saved(attr_name)
94
+ mutations_from_database.change_to_attribute(attr_name)
95
+ end
96
+
97
+ # Alias for +attribute_was+
98
+ def attribute_in_database(attr_name)
99
+ mutations_from_database.original_value(attr_name)
100
+ end
101
+
102
+ # Alias for +changed?+
103
+ def has_changes_to_save?
104
+ mutations_from_database.any_changes?
105
+ end
106
+
107
+ # Alias for +changes+
108
+ def changes_to_save
109
+ mutations_from_database.changes
110
+ end
111
+
112
+ # Alias for +changed+
113
+ def changed_attribute_names_to_save
114
+ mutations_from_database.changed_attribute_names
115
+ end
116
+
117
+ # Alias for +changed_attributes+
118
+ def attributes_in_database
119
+ mutations_from_database.changed_values
120
+ end
121
+
122
+ private
123
+ def write_attribute_without_type_cast(attr_name, value)
124
+ name = attr_name.to_s
125
+ if self.class.attribute_alias?(name)
126
+ name = self.class.attribute_alias(name)
127
+ end
128
+ result = super(name, value)
129
+ clear_attribute_change(name)
130
+ result
131
+ end
132
+
133
+ def _update_record(*)
134
+ affected_rows = partial_writes? ? super(keys_for_partial_write) : super
135
+ changes_applied
136
+ affected_rows
137
+ end
138
+
139
+ def _create_record(*)
140
+ id = partial_writes? ? super(keys_for_partial_write) : super
141
+ changes_applied
142
+ id
143
+ end
144
+
145
+ def keys_for_partial_write
146
+ changed_attribute_names_to_save & self.class.column_names
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+
5
+ module ActiveRecord
6
+ module AttributeMethods
7
+ module PrimaryKey
8
+ extend ActiveSupport::Concern
9
+
10
+ # Returns this record's primary key value wrapped in an array if one is
11
+ # available.
12
+ def to_key
13
+ key = id
14
+ [key] if key
15
+ end
16
+
17
+ # Returns the primary key value.
18
+ def id
19
+ sync_with_transaction_state
20
+ primary_key = self.class.primary_key
21
+ _read_attribute(primary_key) if primary_key
22
+ end
23
+
24
+ # Sets the primary key value.
25
+ def id=(value)
26
+ sync_with_transaction_state
27
+ primary_key = self.class.primary_key
28
+ _write_attribute(primary_key, value) if primary_key
29
+ end
30
+
31
+ # Queries the primary key value.
32
+ def id?
33
+ sync_with_transaction_state
34
+ query_attribute(self.class.primary_key)
35
+ end
36
+
37
+ # Returns the primary key value before type cast.
38
+ def id_before_type_cast
39
+ sync_with_transaction_state
40
+ read_attribute_before_type_cast(self.class.primary_key)
41
+ end
42
+
43
+ # Returns the primary key previous value.
44
+ def id_was
45
+ sync_with_transaction_state
46
+ attribute_was(self.class.primary_key)
47
+ end
48
+
49
+ def id_in_database
50
+ sync_with_transaction_state
51
+ attribute_in_database(self.class.primary_key)
52
+ end
53
+
54
+ private
55
+
56
+ def attribute_method?(attr_name)
57
+ attr_name == "id" || super
58
+ end
59
+
60
+ module ClassMethods
61
+ ID_ATTRIBUTE_METHODS = %w(id id= id? id_before_type_cast id_was id_in_database).to_set
62
+
63
+ def instance_method_already_implemented?(method_name)
64
+ super || primary_key && ID_ATTRIBUTE_METHODS.include?(method_name)
65
+ end
66
+
67
+ def dangerous_attribute_method?(method_name)
68
+ super && !ID_ATTRIBUTE_METHODS.include?(method_name)
69
+ end
70
+
71
+ # Defines the primary key field -- can be overridden in subclasses.
72
+ # Overwriting will negate any effect of the +primary_key_prefix_type+
73
+ # setting, though.
74
+ def primary_key
75
+ @primary_key = reset_primary_key unless defined? @primary_key
76
+ @primary_key
77
+ end
78
+
79
+ # Returns a quoted version of the primary key name, used to construct
80
+ # SQL statements.
81
+ def quoted_primary_key
82
+ @quoted_primary_key ||= connection.quote_column_name(primary_key)
83
+ end
84
+
85
+ def reset_primary_key #:nodoc:
86
+ if self == base_class
87
+ self.primary_key = get_primary_key(base_class.name)
88
+ else
89
+ self.primary_key = base_class.primary_key
90
+ end
91
+ end
92
+
93
+ def get_primary_key(base_name) #:nodoc:
94
+ if base_name && primary_key_prefix_type == :table_name
95
+ base_name.foreign_key(false)
96
+ elsif base_name && primary_key_prefix_type == :table_name_with_underscore
97
+ base_name.foreign_key
98
+ else
99
+ if ActiveRecord::Base != self && table_exists?
100
+ pk = connection.schema_cache.primary_keys(table_name)
101
+ suppress_composite_primary_key(pk)
102
+ else
103
+ "id"
104
+ end
105
+ end
106
+ end
107
+
108
+ # Sets the name of the primary key column.
109
+ #
110
+ # class Project < ActiveRecord::Base
111
+ # self.primary_key = 'sysid'
112
+ # end
113
+ #
114
+ # You can also define the #primary_key method yourself:
115
+ #
116
+ # class Project < ActiveRecord::Base
117
+ # def self.primary_key
118
+ # 'foo_' + super
119
+ # end
120
+ # end
121
+ #
122
+ # Project.primary_key # => "foo_id"
123
+ def primary_key=(value)
124
+ @primary_key = value && value.to_s
125
+ @quoted_primary_key = nil
126
+ @attributes_builder = nil
127
+ end
128
+
129
+ private
130
+
131
+ def suppress_composite_primary_key(pk)
132
+ return pk unless pk.is_a?(Array)
133
+
134
+ warn <<-WARNING.strip_heredoc
135
+ WARNING: Active Record does not support composite primary key.
136
+
137
+ #{table_name} has composite primary key. Composite primary key is ignored.
138
+ WARNING
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module AttributeMethods
5
+ module Query
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ attribute_method_suffix "?"
10
+ end
11
+
12
+ def query_attribute(attr_name)
13
+ value = self[attr_name]
14
+
15
+ case value
16
+ when true then true
17
+ when false, nil then false
18
+ else
19
+ column = self.class.columns_hash[attr_name]
20
+ if column.nil?
21
+ if Numeric === value || value !~ /[^0-9]/
22
+ !value.to_i.zero?
23
+ else
24
+ return false if ActiveModel::Type::Boolean::FALSE_VALUES.include?(value)
25
+ !value.blank?
26
+ end
27
+ elsif value.respond_to?(:zero?)
28
+ !value.zero?
29
+ else
30
+ !value.blank?
31
+ end
32
+ end
33
+ end
34
+
35
+ private
36
+ # Handle *? for method_missing.
37
+ def attribute?(attribute_name)
38
+ query_attribute(attribute_name)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module AttributeMethods
5
+ module Read
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods # :nodoc:
9
+ private
10
+
11
+ # We want to generate the methods via module_eval rather than
12
+ # define_method, because define_method is slower on dispatch.
13
+ # Evaluating many similar methods may use more memory as the instruction
14
+ # sequences are duplicated and cached (in MRI). define_method may
15
+ # be slower on dispatch, but if you're careful about the closure
16
+ # created, then define_method will consume much less memory.
17
+ #
18
+ # But sometimes the database might return columns with
19
+ # characters that are not allowed in normal method names (like
20
+ # 'my_column(omg)'. So to work around this we first define with
21
+ # the __temp__ identifier, and then use alias method to rename
22
+ # it to what we want.
23
+ #
24
+ # We are also defining a constant to hold the frozen string of
25
+ # the attribute name. Using a constant means that we do not have
26
+ # to allocate an object on each call to the attribute method.
27
+ # Making it frozen means that it doesn't get duped when used to
28
+ # key the @attributes in read_attribute.
29
+ def define_method_attribute(name)
30
+ safe_name = name.unpack("h*".freeze).first
31
+ temp_method = "__temp__#{safe_name}"
32
+
33
+ ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
34
+ sync_with_transaction_state = "sync_with_transaction_state" if name == primary_key
35
+
36
+ generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
37
+ def #{temp_method}
38
+ #{sync_with_transaction_state}
39
+ name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
40
+ _read_attribute(name) { |n| missing_attribute(n, caller) }
41
+ end
42
+ STR
43
+
44
+ generated_attribute_methods.module_eval do
45
+ alias_method name, temp_method
46
+ undef_method temp_method
47
+ end
48
+ end
49
+ end
50
+
51
+ # Returns the value of the attribute identified by <tt>attr_name</tt> after
52
+ # it has been typecast (for example, "2004-12-12" in a date column is cast
53
+ # to a date object, like Date.new(2004, 12, 12)).
54
+ def read_attribute(attr_name, &block)
55
+ name = if self.class.attribute_alias?(attr_name)
56
+ self.class.attribute_alias(attr_name).to_s
57
+ else
58
+ attr_name.to_s
59
+ end
60
+
61
+ primary_key = self.class.primary_key
62
+ name = primary_key if name == "id".freeze && primary_key
63
+ sync_with_transaction_state if name == primary_key
64
+ _read_attribute(name, &block)
65
+ end
66
+
67
+ # This method exists to avoid the expensive primary_key check internally, without
68
+ # breaking compatibility with the read_attribute API
69
+ if defined?(JRUBY_VERSION)
70
+ # This form is significantly faster on JRuby, and this is one of our biggest hotspots.
71
+ # https://github.com/jruby/jruby/pull/2562
72
+ def _read_attribute(attr_name, &block) # :nodoc:
73
+ @attributes.fetch_value(attr_name.to_s, &block)
74
+ end
75
+ else
76
+ def _read_attribute(attr_name) # :nodoc:
77
+ @attributes.fetch_value(attr_name.to_s) { |n| yield n if block_given? }
78
+ end
79
+ end
80
+
81
+ alias :attribute :_read_attribute
82
+ private :attribute
83
+ end
84
+ end
85
+ end