activerecord 4.2.0 → 5.2.8.1

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 (274) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +640 -928
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +10 -11
  5. data/examples/performance.rb +32 -31
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record/aggregations.rb +264 -247
  8. data/lib/active_record/association_relation.rb +24 -6
  9. data/lib/active_record/associations/alias_tracker.rb +29 -35
  10. data/lib/active_record/associations/association.rb +87 -41
  11. data/lib/active_record/associations/association_scope.rb +106 -132
  12. data/lib/active_record/associations/belongs_to_association.rb +55 -36
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
  14. data/lib/active_record/associations/builder/association.rb +29 -38
  15. data/lib/active_record/associations/builder/belongs_to.rb +77 -30
  16. data/lib/active_record/associations/builder/collection_association.rb +14 -23
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +50 -39
  18. data/lib/active_record/associations/builder/has_many.rb +6 -4
  19. data/lib/active_record/associations/builder/has_one.rb +13 -6
  20. data/lib/active_record/associations/builder/singular_association.rb +15 -11
  21. data/lib/active_record/associations/collection_association.rb +145 -266
  22. data/lib/active_record/associations/collection_proxy.rb +242 -138
  23. data/lib/active_record/associations/foreign_association.rb +13 -0
  24. data/lib/active_record/associations/has_many_association.rb +35 -75
  25. data/lib/active_record/associations/has_many_through_association.rb +51 -69
  26. data/lib/active_record/associations/has_one_association.rb +39 -24
  27. data/lib/active_record/associations/has_one_through_association.rb +18 -9
  28. data/lib/active_record/associations/join_dependency/join_association.rb +40 -81
  29. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
  31. data/lib/active_record/associations/join_dependency.rb +134 -154
  32. data/lib/active_record/associations/preloader/association.rb +85 -116
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -74
  34. data/lib/active_record/associations/preloader.rb +83 -93
  35. data/lib/active_record/associations/singular_association.rb +27 -40
  36. data/lib/active_record/associations/through_association.rb +48 -23
  37. data/lib/active_record/associations.rb +1732 -1596
  38. data/lib/active_record/attribute_assignment.rb +58 -182
  39. data/lib/active_record/attribute_decorators.rb +39 -15
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +12 -5
  41. data/lib/active_record/attribute_methods/dirty.rb +94 -125
  42. data/lib/active_record/attribute_methods/primary_key.rb +86 -71
  43. data/lib/active_record/attribute_methods/query.rb +4 -2
  44. data/lib/active_record/attribute_methods/read.rb +45 -63
  45. data/lib/active_record/attribute_methods/serialization.rb +40 -20
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +62 -36
  47. data/lib/active_record/attribute_methods/write.rb +31 -46
  48. data/lib/active_record/attribute_methods.rb +170 -117
  49. data/lib/active_record/attributes.rb +201 -74
  50. data/lib/active_record/autosave_association.rb +118 -45
  51. data/lib/active_record/base.rb +60 -48
  52. data/lib/active_record/callbacks.rb +97 -57
  53. data/lib/active_record/coders/json.rb +3 -1
  54. data/lib/active_record/coders/yaml_column.rb +37 -13
  55. data/lib/active_record/collection_cache_key.rb +53 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +712 -284
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +10 -5
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +254 -87
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +72 -22
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -52
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +6 -4
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +67 -46
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -217
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +81 -36
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +617 -212
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +139 -75
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +332 -191
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +567 -563
  69. data/lib/active_record/connection_adapters/column.rb +50 -41
  70. data/lib/active_record/connection_adapters/connection_specification.rb +147 -135
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +42 -195
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +35 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -115
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -57
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +10 -6
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +5 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -13
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +7 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -19
  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 -11
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
  99. data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +65 -51
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +107 -47
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +144 -90
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +466 -280
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +439 -330
  117. data/lib/active_record/connection_adapters/schema_cache.rb +48 -24
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +269 -324
  126. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  127. data/lib/active_record/connection_handling.rb +40 -27
  128. data/lib/active_record/core.rb +205 -202
  129. data/lib/active_record/counter_cache.rb +80 -37
  130. data/lib/active_record/define_callbacks.rb +22 -0
  131. data/lib/active_record/dynamic_matchers.rb +87 -105
  132. data/lib/active_record/enum.rb +136 -90
  133. data/lib/active_record/errors.rb +180 -52
  134. data/lib/active_record/explain.rb +23 -11
  135. data/lib/active_record/explain_registry.rb +4 -2
  136. data/lib/active_record/explain_subscriber.rb +11 -6
  137. data/lib/active_record/fixture_set/file.rb +35 -9
  138. data/lib/active_record/fixtures.rb +193 -135
  139. data/lib/active_record/gem_version.rb +5 -3
  140. data/lib/active_record/inheritance.rb +148 -112
  141. data/lib/active_record/integration.rb +70 -28
  142. data/lib/active_record/internal_metadata.rb +45 -0
  143. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  144. data/lib/active_record/locale/en.yml +3 -2
  145. data/lib/active_record/locking/optimistic.rb +92 -98
  146. data/lib/active_record/locking/pessimistic.rb +15 -3
  147. data/lib/active_record/log_subscriber.rb +95 -33
  148. data/lib/active_record/migration/command_recorder.rb +133 -90
  149. data/lib/active_record/migration/compatibility.rb +217 -0
  150. data/lib/active_record/migration/join_table.rb +8 -6
  151. data/lib/active_record/migration.rb +594 -267
  152. data/lib/active_record/model_schema.rb +292 -111
  153. data/lib/active_record/nested_attributes.rb +266 -214
  154. data/lib/active_record/no_touching.rb +8 -2
  155. data/lib/active_record/null_relation.rb +24 -37
  156. data/lib/active_record/persistence.rb +350 -119
  157. data/lib/active_record/query_cache.rb +13 -24
  158. data/lib/active_record/querying.rb +19 -17
  159. data/lib/active_record/railtie.rb +117 -35
  160. data/lib/active_record/railties/console_sandbox.rb +2 -0
  161. data/lib/active_record/railties/controller_runtime.rb +9 -3
  162. data/lib/active_record/railties/databases.rake +160 -174
  163. data/lib/active_record/readonly_attributes.rb +5 -4
  164. data/lib/active_record/reflection.rb +447 -288
  165. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  166. data/lib/active_record/relation/batches.rb +204 -55
  167. data/lib/active_record/relation/calculations.rb +259 -244
  168. data/lib/active_record/relation/delegation.rb +67 -60
  169. data/lib/active_record/relation/finder_methods.rb +290 -253
  170. data/lib/active_record/relation/from_clause.rb +26 -0
  171. data/lib/active_record/relation/merger.rb +91 -68
  172. data/lib/active_record/relation/predicate_builder/array_handler.rb +24 -23
  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 +19 -0
  175. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
  176. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  177. data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
  178. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  179. data/lib/active_record/relation/predicate_builder.rb +118 -92
  180. data/lib/active_record/relation/query_attribute.rb +45 -0
  181. data/lib/active_record/relation/query_methods.rb +446 -389
  182. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  183. data/lib/active_record/relation/spawn_methods.rb +18 -16
  184. data/lib/active_record/relation/where_clause.rb +186 -0
  185. data/lib/active_record/relation/where_clause_factory.rb +34 -0
  186. data/lib/active_record/relation.rb +287 -339
  187. data/lib/active_record/result.rb +54 -36
  188. data/lib/active_record/runtime_registry.rb +6 -4
  189. data/lib/active_record/sanitization.rb +155 -124
  190. data/lib/active_record/schema.rb +30 -24
  191. data/lib/active_record/schema_dumper.rb +91 -87
  192. data/lib/active_record/schema_migration.rb +19 -19
  193. data/lib/active_record/scoping/default.rb +102 -84
  194. data/lib/active_record/scoping/named.rb +81 -32
  195. data/lib/active_record/scoping.rb +45 -26
  196. data/lib/active_record/secure_token.rb +40 -0
  197. data/lib/active_record/serialization.rb +5 -5
  198. data/lib/active_record/statement_cache.rb +45 -35
  199. data/lib/active_record/store.rb +42 -36
  200. data/lib/active_record/suppressor.rb +61 -0
  201. data/lib/active_record/table_metadata.rb +82 -0
  202. data/lib/active_record/tasks/database_tasks.rb +136 -95
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +59 -89
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -31
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -16
  206. data/lib/active_record/timestamp.rb +70 -38
  207. data/lib/active_record/touch_later.rb +64 -0
  208. data/lib/active_record/transactions.rb +208 -123
  209. data/lib/active_record/translation.rb +2 -0
  210. data/lib/active_record/type/adapter_specific_registry.rb +136 -0
  211. data/lib/active_record/type/date.rb +4 -41
  212. data/lib/active_record/type/date_time.rb +4 -38
  213. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  214. data/lib/active_record/type/hash_lookup_type_map.rb +13 -5
  215. data/lib/active_record/type/internal/timezone.rb +17 -0
  216. data/lib/active_record/type/json.rb +30 -0
  217. data/lib/active_record/type/serialized.rb +30 -15
  218. data/lib/active_record/type/text.rb +2 -2
  219. data/lib/active_record/type/time.rb +11 -16
  220. data/lib/active_record/type/type_map.rb +15 -17
  221. data/lib/active_record/type/unsigned_integer.rb +9 -7
  222. data/lib/active_record/type.rb +79 -23
  223. data/lib/active_record/type_caster/connection.rb +33 -0
  224. data/lib/active_record/type_caster/map.rb +23 -0
  225. data/lib/active_record/type_caster.rb +9 -0
  226. data/lib/active_record/validations/absence.rb +25 -0
  227. data/lib/active_record/validations/associated.rb +13 -4
  228. data/lib/active_record/validations/length.rb +26 -0
  229. data/lib/active_record/validations/presence.rb +14 -13
  230. data/lib/active_record/validations/uniqueness.rb +41 -32
  231. data/lib/active_record/validations.rb +38 -35
  232. data/lib/active_record/version.rb +3 -1
  233. data/lib/active_record.rb +36 -21
  234. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  235. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  236. data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -35
  237. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +8 -6
  238. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +8 -7
  239. data/lib/rails/generators/active_record/migration.rb +18 -1
  240. data/lib/rails/generators/active_record/model/model_generator.rb +18 -22
  241. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +3 -0
  242. data/lib/rails/generators/active_record.rb +7 -5
  243. metadata +77 -53
  244. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  245. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  246. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  247. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  248. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  249. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  250. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  251. data/lib/active_record/attribute.rb +0 -149
  252. data/lib/active_record/attribute_set/builder.rb +0 -86
  253. data/lib/active_record/attribute_set.rb +0 -77
  254. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  255. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  256. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  257. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  258. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  259. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  260. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  261. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  262. data/lib/active_record/type/big_integer.rb +0 -13
  263. data/lib/active_record/type/binary.rb +0 -50
  264. data/lib/active_record/type/boolean.rb +0 -30
  265. data/lib/active_record/type/decimal.rb +0 -40
  266. data/lib/active_record/type/decorator.rb +0 -14
  267. data/lib/active_record/type/float.rb +0 -19
  268. data/lib/active_record/type/integer.rb +0 -55
  269. data/lib/active_record/type/mutable.rb +0 -16
  270. data/lib/active_record/type/numeric.rb +0 -36
  271. data/lib/active_record/type/string.rb +0 -36
  272. data/lib/active_record/type/time_value.rb +0 -38
  273. data/lib/active_record/type/value.rb +0 -101
  274. /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
- # = Active Record Persistence
4
+ # = Active Record \Persistence
3
5
  module Persistence
4
6
  extend ActiveSupport::Concern
5
7
 
@@ -61,12 +63,148 @@ module ActiveRecord
61
63
  # +instantiate+ instead of +new+, finder methods ensure they get new
62
64
  # instances of the appropriate class for each record.
63
65
  #
64
- # See +ActiveRecord::Inheritance#discriminate_class_for_record+ to see
66
+ # See <tt>ActiveRecord::Inheritance#discriminate_class_for_record</tt> to see
65
67
  # how this "single-table" inheritance mapping is implemented.
66
- def instantiate(attributes, column_types = {})
68
+ def instantiate(attributes, column_types = {}, &block)
67
69
  klass = discriminate_class_for_record(attributes)
68
70
  attributes = klass.attributes_builder.build_from_database(attributes, column_types)
69
- klass.allocate.init_with('attributes' => attributes, 'new_record' => false)
71
+ klass.allocate.init_with("attributes" => attributes, "new_record" => false, &block)
72
+ end
73
+
74
+ # Updates an object (or multiple objects) and saves it to the database, if validations pass.
75
+ # The resulting object is returned whether the object was saved successfully to the database or not.
76
+ #
77
+ # ==== Parameters
78
+ #
79
+ # * +id+ - This should be the id or an array of ids to be updated.
80
+ # * +attributes+ - This should be a hash of attributes or an array of hashes.
81
+ #
82
+ # ==== Examples
83
+ #
84
+ # # Updates one record
85
+ # Person.update(15, user_name: "Samuel", group: "expert")
86
+ #
87
+ # # Updates multiple records
88
+ # people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy" } }
89
+ # Person.update(people.keys, people.values)
90
+ #
91
+ # # Updates multiple records from the result of a relation
92
+ # people = Person.where(group: "expert")
93
+ # people.update(group: "masters")
94
+ #
95
+ # Note: Updating a large number of records will run an UPDATE
96
+ # query for each record, which may cause a performance issue.
97
+ # When running callbacks is not needed for each record update,
98
+ # it is preferred to use {update_all}[rdoc-ref:Relation#update_all]
99
+ # for updating all records in a single query.
100
+ def update(id = :all, attributes)
101
+ if id.is_a?(Array)
102
+ id.map { |one_id| find(one_id) }.each_with_index { |object, idx|
103
+ object.update(attributes[idx])
104
+ }
105
+ elsif id == :all
106
+ all.each { |record| record.update(attributes) }
107
+ else
108
+ if ActiveRecord::Base === id
109
+ raise ArgumentError,
110
+ "You are passing an instance of ActiveRecord::Base to `update`. " \
111
+ "Please pass the id of the object by calling `.id`."
112
+ end
113
+ object = find(id)
114
+ object.update(attributes)
115
+ object
116
+ end
117
+ end
118
+
119
+ # Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
120
+ # therefore all callbacks and filters are fired off before the object is deleted. This method is
121
+ # less efficient than #delete but allows cleanup methods and other actions to be run.
122
+ #
123
+ # This essentially finds the object (or multiple objects) with the given id, creates a new object
124
+ # from the attributes, and then calls destroy on it.
125
+ #
126
+ # ==== Parameters
127
+ #
128
+ # * +id+ - This should be the id or an array of ids to be destroyed.
129
+ #
130
+ # ==== Examples
131
+ #
132
+ # # Destroy a single object
133
+ # Todo.destroy(1)
134
+ #
135
+ # # Destroy multiple objects
136
+ # todos = [1,2,3]
137
+ # Todo.destroy(todos)
138
+ def destroy(id)
139
+ if id.is_a?(Array)
140
+ find(id).each(&:destroy)
141
+ else
142
+ find(id).destroy
143
+ end
144
+ end
145
+
146
+ # Deletes the row with a primary key matching the +id+ argument, using a
147
+ # SQL +DELETE+ statement, and returns the number of rows deleted. Active
148
+ # Record objects are not instantiated, so the object's callbacks are not
149
+ # executed, including any <tt>:dependent</tt> association options.
150
+ #
151
+ # You can delete multiple rows at once by passing an Array of <tt>id</tt>s.
152
+ #
153
+ # Note: Although it is often much faster than the alternative, #destroy,
154
+ # skipping callbacks might bypass business logic in your application
155
+ # that ensures referential integrity or performs other essential jobs.
156
+ #
157
+ # ==== Examples
158
+ #
159
+ # # Delete a single row
160
+ # Todo.delete(1)
161
+ #
162
+ # # Delete multiple rows
163
+ # Todo.delete([2,3,4])
164
+ def delete(id_or_array)
165
+ where(primary_key => id_or_array).delete_all
166
+ end
167
+
168
+ def _insert_record(values) # :nodoc:
169
+ primary_key_value = nil
170
+
171
+ if primary_key && Hash === values
172
+ primary_key_value = values[primary_key]
173
+
174
+ if !primary_key_value && prefetch_primary_key?
175
+ primary_key_value = next_sequence_value
176
+ values[primary_key] = primary_key_value
177
+ end
178
+ end
179
+
180
+ if values.empty?
181
+ im = arel_table.compile_insert(connection.empty_insert_statement_value)
182
+ im.into arel_table
183
+ else
184
+ im = arel_table.compile_insert(_substitute_values(values))
185
+ end
186
+
187
+ connection.insert(im, "#{self} Create", primary_key || false, primary_key_value)
188
+ end
189
+
190
+ def _update_record(values, constraints) # :nodoc:
191
+ constraints = _substitute_values(constraints).map { |attr, bind| attr.eq(bind) }
192
+
193
+ um = arel_table.where(
194
+ constraints.reduce(&:and)
195
+ ).compile_update(_substitute_values(values), primary_key)
196
+
197
+ connection.update(um, "#{self} Update")
198
+ end
199
+
200
+ def _delete_record(constraints) # :nodoc:
201
+ constraints = _substitute_values(constraints).map { |attr, bind| attr.eq(bind) }
202
+
203
+ dm = Arel::DeleteManager.new
204
+ dm.from(arel_table)
205
+ dm.wheres = constraints
206
+
207
+ connection.delete(dm, "#{self} Destroy")
70
208
  end
71
209
 
72
210
  private
@@ -78,6 +216,14 @@ module ActiveRecord
78
216
  def discriminate_class_for_record(record)
79
217
  self
80
218
  end
219
+
220
+ def _substitute_values(values)
221
+ values.map do |name, value|
222
+ attr = arel_attribute(name)
223
+ bind = predicate_builder.build_bind_attribute(name, value)
224
+ [attr, bind]
225
+ end
226
+ end
81
227
  end
82
228
 
83
229
  # Returns true if this object hasn't been saved yet -- that is, a record
@@ -96,50 +242,70 @@ module ActiveRecord
96
242
  # Returns true if the record is persisted, i.e. it's not a new record and it was
97
243
  # not destroyed, otherwise returns false.
98
244
  def persisted?
99
- !(new_record? || destroyed?)
245
+ sync_with_transaction_state
246
+ !(@new_record || @destroyed)
100
247
  end
101
248
 
249
+ ##
250
+ # :call-seq:
251
+ # save(*args)
252
+ #
102
253
  # Saves the model.
103
254
  #
104
- # If the model is new a record gets created in the database, otherwise
255
+ # If the model is new, a record gets created in the database, otherwise
105
256
  # the existing record gets updated.
106
257
  #
107
- # By default, save always run validations. If any of them fail the action
108
- # is cancelled and +save+ returns +false+. However, if you supply
109
- # validate: false, validations are bypassed altogether. See
258
+ # By default, save always runs validations. If any of them fail the action
259
+ # is cancelled and #save returns +false+, and the record won't be saved. However, if you supply
260
+ # <tt>validate: false</tt>, validations are bypassed altogether. See
110
261
  # ActiveRecord::Validations for more information.
111
262
  #
112
- # There's a series of callbacks associated with +save+. If any of the
113
- # <tt>before_*</tt> callbacks return +false+ the action is cancelled and
114
- # +save+ returns +false+. See ActiveRecord::Callbacks for further
263
+ # By default, #save also sets the +updated_at+/+updated_on+ attributes to
264
+ # the current time. However, if you supply <tt>touch: false</tt>, these
265
+ # timestamps will not be updated.
266
+ #
267
+ # There's a series of callbacks associated with #save. If any of the
268
+ # <tt>before_*</tt> callbacks throws +:abort+ the action is cancelled and
269
+ # #save returns +false+. See ActiveRecord::Callbacks for further
115
270
  # details.
116
271
  #
117
272
  # Attributes marked as readonly are silently ignored if the record is
118
273
  # being updated.
119
- def save(*)
120
- create_or_update
274
+ def save(*args, &block)
275
+ create_or_update(*args, &block)
121
276
  rescue ActiveRecord::RecordInvalid
122
277
  false
123
278
  end
124
279
 
280
+ ##
281
+ # :call-seq:
282
+ # save!(*args)
283
+ #
125
284
  # Saves the model.
126
285
  #
127
- # If the model is new a record gets created in the database, otherwise
286
+ # If the model is new, a record gets created in the database, otherwise
128
287
  # the existing record gets updated.
129
288
  #
130
- # With <tt>save!</tt> validations always run. If any of them fail
131
- # ActiveRecord::RecordInvalid gets raised. See ActiveRecord::Validations
132
- # for more information.
289
+ # By default, #save! always runs validations. If any of them fail
290
+ # ActiveRecord::RecordInvalid gets raised, and the record won't be saved. However, if you supply
291
+ # <tt>validate: false</tt>, validations are bypassed altogether. See
292
+ # ActiveRecord::Validations for more information.
133
293
  #
134
- # There's a series of callbacks associated with <tt>save!</tt>. If any of
135
- # the <tt>before_*</tt> callbacks return +false+ the action is cancelled
136
- # and <tt>save!</tt> raises ActiveRecord::RecordNotSaved. See
294
+ # By default, #save! also sets the +updated_at+/+updated_on+ attributes to
295
+ # the current time. However, if you supply <tt>touch: false</tt>, these
296
+ # timestamps will not be updated.
297
+ #
298
+ # There's a series of callbacks associated with #save!. If any of
299
+ # the <tt>before_*</tt> callbacks throws +:abort+ the action is cancelled
300
+ # and #save! raises ActiveRecord::RecordNotSaved. See
137
301
  # ActiveRecord::Callbacks for further details.
138
302
  #
139
303
  # Attributes marked as readonly are silently ignored if the record is
140
304
  # being updated.
141
- def save!(*)
142
- create_or_update || raise(RecordNotSaved.new(nil, self))
305
+ #
306
+ # Unless an error is raised, returns true.
307
+ def save!(*args, &block)
308
+ create_or_update(*args, &block) || raise(RecordNotSaved.new("Failed to save the record", self))
143
309
  end
144
310
 
145
311
  # Deletes the record in the database and freezes this instance to
@@ -149,11 +315,13 @@ module ActiveRecord
149
315
  # The row is simply removed with an SQL +DELETE+ statement on the
150
316
  # record's primary key, and no callbacks are executed.
151
317
  #
318
+ # Note that this will also delete records marked as {#readonly?}[rdoc-ref:Core#readonly?].
319
+ #
152
320
  # To enforce the object's +before_destroy+ and +after_destroy+
153
321
  # callbacks or any <tt>:dependent</tt> association
154
322
  # options, use <tt>#destroy</tt>.
155
323
  def delete
156
- self.class.delete(id) if persisted?
324
+ _delete_row if persisted?
157
325
  @destroyed = true
158
326
  freeze
159
327
  end
@@ -161,14 +329,19 @@ module ActiveRecord
161
329
  # Deletes the record in the database and freezes this instance to reflect
162
330
  # that no changes should be made (since they can't be persisted).
163
331
  #
164
- # There's a series of callbacks associated with <tt>destroy</tt>. If
165
- # the <tt>before_destroy</tt> callback return +false+ the action is cancelled
166
- # and <tt>destroy</tt> returns +false+. See
167
- # ActiveRecord::Callbacks for further details.
332
+ # There's a series of callbacks associated with #destroy. If the
333
+ # <tt>before_destroy</tt> callback throws +:abort+ the action is cancelled
334
+ # and #destroy returns +false+.
335
+ # See ActiveRecord::Callbacks for further details.
168
336
  def destroy
169
- raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
337
+ _raise_readonly_record_error if readonly?
170
338
  destroy_associations
171
- destroy_row if persisted?
339
+ self.class.connection.add_transaction_record(self)
340
+ @_trigger_destroy_callback = if persisted?
341
+ destroy_row > 0
342
+ else
343
+ true
344
+ end
172
345
  @destroyed = true
173
346
  freeze
174
347
  end
@@ -176,12 +349,12 @@ module ActiveRecord
176
349
  # Deletes the record in the database and freezes this instance to reflect
177
350
  # that no changes should be made (since they can't be persisted).
178
351
  #
179
- # There's a series of callbacks associated with <tt>destroy!</tt>. If
180
- # the <tt>before_destroy</tt> callback return +false+ the action is cancelled
181
- # and <tt>destroy!</tt> raises ActiveRecord::RecordNotDestroyed. See
182
- # ActiveRecord::Callbacks for further details.
352
+ # There's a series of callbacks associated with #destroy!. If the
353
+ # <tt>before_destroy</tt> callback throws +:abort+ the action is cancelled
354
+ # and #destroy! raises ActiveRecord::RecordNotDestroyed.
355
+ # See ActiveRecord::Callbacks for further details.
183
356
  def destroy!
184
- destroy || raise(ActiveRecord::RecordNotDestroyed, self)
357
+ destroy || _raise_record_not_destroyed
185
358
  end
186
359
 
187
360
  # Returns an instance of the specified +klass+ with the attributes of the
@@ -193,18 +366,22 @@ module ActiveRecord
193
366
  # instance using the companies/company partial instead of clients/client.
194
367
  #
195
368
  # Note: The new instance will share a link to the same attributes as the original class.
196
- # So any change to the attributes in either instance will affect the other.
369
+ # Therefore the sti column value will still be the same.
370
+ # Any change to the attributes on either instance will affect both instances.
371
+ # If you want to change the sti column as well, use #becomes! instead.
197
372
  def becomes(klass)
198
- became = klass.new
373
+ became = klass.allocate
374
+ became.send(:initialize)
199
375
  became.instance_variable_set("@attributes", @attributes)
200
- became.instance_variable_set("@changed_attributes", @changed_attributes) if defined?(@changed_attributes)
376
+ became.instance_variable_set("@mutations_from_database", @mutations_from_database ||= nil)
377
+ became.instance_variable_set("@changed_attributes", attributes_changed_by_setter)
201
378
  became.instance_variable_set("@new_record", new_record?)
202
379
  became.instance_variable_set("@destroyed", destroyed?)
203
- became.instance_variable_set("@errors", errors)
380
+ became.errors.copy!(errors)
204
381
  became
205
382
  end
206
383
 
207
- # Wrapper around +becomes+ that also changes the instance's sti column value.
384
+ # Wrapper around #becomes that also changes the instance's sti column value.
208
385
  # This is especially useful if you want to persist the changed class in your
209
386
  # database.
210
387
  #
@@ -224,18 +401,19 @@ module ActiveRecord
224
401
  # This is especially useful for boolean flags on existing records. Also note that
225
402
  #
226
403
  # * Validation is skipped.
227
- # * Callbacks are invoked.
404
+ # * \Callbacks are invoked.
228
405
  # * updated_at/updated_on column is updated if that column is available.
229
406
  # * Updates all the attributes that are dirty in this object.
230
407
  #
231
- # This method raises an +ActiveRecord::ActiveRecordError+ if the
408
+ # This method raises an ActiveRecord::ActiveRecordError if the
232
409
  # attribute is marked as readonly.
233
410
  #
234
- # See also +update_column+.
411
+ # Also see #update_column.
235
412
  def update_attribute(name, value)
236
413
  name = name.to_s
237
414
  verify_readonly_attribute(name)
238
- send("#{name}=", value)
415
+ public_send("#{name}=", value)
416
+
239
417
  save(validate: false)
240
418
  end
241
419
 
@@ -253,8 +431,8 @@ module ActiveRecord
253
431
 
254
432
  alias update_attributes update
255
433
 
256
- # Updates its receiver just like +update+ but calls <tt>save!</tt> instead
257
- # of +save+, so an exception is raised if the record is invalid.
434
+ # Updates its receiver just like #update but calls #save! instead
435
+ # of +save+, so an exception is raised if the record is invalid and saving will fail.
258
436
  def update!(attributes)
259
437
  # The following transaction covers any possible database side-effects of the
260
438
  # attributes assignment. For example, setting the IDs of a child collection.
@@ -280,11 +458,12 @@ module ActiveRecord
280
458
  # the database, but take into account that in consequence the regular update
281
459
  # procedures are totally bypassed. In particular:
282
460
  #
283
- # * Validations are skipped.
284
- # * Callbacks are skipped.
461
+ # * \Validations are skipped.
462
+ # * \Callbacks are skipped.
285
463
  # * +updated_at+/+updated_on+ are not updated.
464
+ # * However, attributes are serialized with the same rules as ActiveRecord::Relation#update_all
286
465
  #
287
- # This method raises an +ActiveRecord::ActiveRecordError+ when called on new
466
+ # This method raises an ActiveRecord::ActiveRecordError when called on new
288
467
  # objects, or when at least one of the attributes is marked as readonly.
289
468
  def update_columns(attributes)
290
469
  raise ActiveRecordError, "cannot update a new record" if new_record?
@@ -294,13 +473,17 @@ module ActiveRecord
294
473
  verify_readonly_attribute(key.to_s)
295
474
  end
296
475
 
297
- updated_count = self.class.unscoped.where(self.class.primary_key => id).update_all(attributes)
298
-
476
+ id_in_database = self.id_in_database
299
477
  attributes.each do |k, v|
300
- raw_write_attribute(k, v)
478
+ write_attribute_without_type_cast(k, v)
301
479
  end
302
480
 
303
- updated_count == 1
481
+ affected_rows = self.class._update_record(
482
+ attributes,
483
+ self.class.primary_key => id_in_database
484
+ )
485
+
486
+ affected_rows == 1
304
487
  end
305
488
 
306
489
  # Initializes +attribute+ to zero if +nil+ and adds the value passed as +by+ (default is 1).
@@ -312,42 +495,56 @@ module ActiveRecord
312
495
  self
313
496
  end
314
497
 
315
- # Wrapper around +increment+ that saves the record. This method differs from
316
- # its non-bang version in that it passes through the attribute setter.
317
- # Saving is not subjected to validation checks. Returns +true+ if the
318
- # record could be saved.
319
- def increment!(attribute, by = 1)
320
- increment(attribute, by).update_attribute(attribute, self[attribute])
498
+ # Wrapper around #increment that writes the update to the database.
499
+ # Only +attribute+ is updated; the record itself is not saved.
500
+ # This means that any other modified attributes will still be dirty.
501
+ # Validations and callbacks are skipped. Supports the +touch+ option from
502
+ # +update_counters+, see that for more.
503
+ # Returns +self+.
504
+ def increment!(attribute, by = 1, touch: nil)
505
+ increment(attribute, by)
506
+ change = public_send(attribute) - (attribute_in_database(attribute.to_s) || 0)
507
+ self.class.update_counters(id, attribute => change, touch: touch)
508
+ clear_attribute_change(attribute) # eww
509
+ self
321
510
  end
322
511
 
323
512
  # Initializes +attribute+ to zero if +nil+ and subtracts the value passed as +by+ (default is 1).
324
513
  # The decrement is performed directly on the underlying attribute, no setter is invoked.
325
514
  # Only makes sense for number-based attributes. Returns +self+.
326
515
  def decrement(attribute, by = 1)
327
- self[attribute] ||= 0
328
- self[attribute] -= by
329
- self
516
+ increment(attribute, -by)
330
517
  end
331
518
 
332
- # Wrapper around +decrement+ that saves the record. This method differs from
333
- # its non-bang version in that it passes through the attribute setter.
334
- # Saving is not subjected to validation checks. Returns +true+ if the
335
- # record could be saved.
336
- def decrement!(attribute, by = 1)
337
- decrement(attribute, by).update_attribute(attribute, self[attribute])
519
+ # Wrapper around #decrement that writes the update to the database.
520
+ # Only +attribute+ is updated; the record itself is not saved.
521
+ # This means that any other modified attributes will still be dirty.
522
+ # Validations and callbacks are skipped. Supports the +touch+ option from
523
+ # +update_counters+, see that for more.
524
+ # Returns +self+.
525
+ def decrement!(attribute, by = 1, touch: nil)
526
+ increment!(attribute, -by, touch: touch)
338
527
  end
339
528
 
340
529
  # Assigns to +attribute+ the boolean opposite of <tt>attribute?</tt>. So
341
530
  # if the predicate returns +true+ the attribute will become +false+. This
342
531
  # method toggles directly the underlying value without calling any setter.
343
532
  # Returns +self+.
533
+ #
534
+ # Example:
535
+ #
536
+ # user = User.first
537
+ # user.banned? # => false
538
+ # user.toggle(:banned)
539
+ # user.banned? # => true
540
+ #
344
541
  def toggle(attribute)
345
- self[attribute] = !send("#{attribute}?")
542
+ self[attribute] = !public_send("#{attribute}?")
346
543
  self
347
544
  end
348
545
 
349
- # Wrapper around +toggle+ that saves the record. This method differs from
350
- # its non-bang version in that it passes through the attribute setter.
546
+ # Wrapper around #toggle that saves the record. This method differs from
547
+ # its non-bang version in the sense that it passes through the attribute setter.
351
548
  # Saving is not subjected to validation checks. Returns +true+ if the
352
549
  # record could be saved.
353
550
  def toggle!(attribute)
@@ -356,8 +553,8 @@ module ActiveRecord
356
553
 
357
554
  # Reloads the record from the database.
358
555
  #
359
- # This method finds record by its primary key (which could be assigned manually) and
360
- # modifies the receiver in-place:
556
+ # This method finds the record by its primary key (which could be assigned
557
+ # manually) and modifies the receiver in-place:
361
558
  #
362
559
  # account = Account.new
363
560
  # # => #<Account id: nil, email: nil>
@@ -367,9 +564,9 @@ module ActiveRecord
367
564
  # # => #<Account id: 1, email: 'account@example.com'>
368
565
  #
369
566
  # Attributes are reloaded from the database, and caches busted, in
370
- # particular the associations cache.
567
+ # particular the associations cache and the QueryCache.
371
568
  #
372
- # If the record no longer exists in the database <tt>ActiveRecord::RecordNotFound</tt>
569
+ # If the record no longer exists in the database ActiveRecord::RecordNotFound
373
570
  # is raised. Otherwise, in addition to the in-place modification the method
374
571
  # returns +self+ for convenience.
375
572
  #
@@ -403,8 +600,7 @@ module ActiveRecord
403
600
  # end
404
601
  #
405
602
  def reload(options = nil)
406
- clear_aggregation_cache
407
- clear_association_cache
603
+ self.class.connection.clear_query_cache
408
604
 
409
605
  fresh_object =
410
606
  if options && options[:lock]
@@ -413,24 +609,27 @@ module ActiveRecord
413
609
  self.class.unscoped { self.class.find(id) }
414
610
  end
415
611
 
416
- @attributes = fresh_object.instance_variable_get('@attributes')
612
+ @attributes = fresh_object.instance_variable_get("@attributes")
417
613
  @new_record = false
418
614
  self
419
615
  end
420
616
 
421
- # Saves the record with the updated_at/on attributes set to the current time.
617
+ # Saves the record with the updated_at/on attributes set to the current time
618
+ # or the time specified.
422
619
  # Please note that no validation is performed and only the +after_touch+,
423
620
  # +after_commit+ and +after_rollback+ callbacks are executed.
424
621
  #
622
+ # This method can be passed attribute names and an optional time argument.
425
623
  # If attribute names are passed, they are updated along with updated_at/on
426
- # attributes.
624
+ # attributes. If no time argument is passed, the current time is used as default.
427
625
  #
428
- # product.touch # updates updated_at/on
626
+ # product.touch # updates updated_at/on with current time
627
+ # product.touch(time: Time.new(2015, 2, 16, 0, 0, 0)) # updates updated_at/on with specified time
429
628
  # product.touch(:designed_at) # updates the designed_at attribute and updated_at/on
430
629
  # product.touch(:started_at, :ended_at) # updates started_at, ended_at and updated_at/on attributes
431
630
  #
432
- # If used along with +belongs_to+ then +touch+ will invoke +touch+ method on
433
- # associated object.
631
+ # If used along with {belongs_to}[rdoc-ref:Associations::ClassMethods#belongs_to]
632
+ # then +touch+ will invoke +touch+ method on associated object.
434
633
  #
435
634
  # class Brake < ActiveRecord::Base
436
635
  # belongs_to :car, touch: true
@@ -449,26 +648,20 @@ module ActiveRecord
449
648
  # ball = Ball.new
450
649
  # ball.touch(:updated_at) # => raises ActiveRecordError
451
650
  #
452
- def touch(*names)
453
- raise ActiveRecordError, "cannot touch on a new record object" unless persisted?
454
-
455
- attributes = timestamp_attributes_for_update_in_model
456
- attributes.concat(names)
457
-
458
- unless attributes.empty?
459
- current_time = current_time_from_proper_timezone
460
- changes = {}
461
-
462
- attributes.each do |column|
463
- column = column.to_s
464
- changes[column] = write_attribute(column, current_time)
465
- end
651
+ def touch(*names, time: nil)
652
+ unless persisted?
653
+ raise ActiveRecordError, <<-MSG.squish
654
+ cannot touch on a new or destroyed record object. Consider using
655
+ persisted?, new_record?, or destroyed? before touching
656
+ MSG
657
+ end
466
658
 
467
- changes[self.class.locking_column] = increment_lock if locking_enabled?
659
+ attribute_names = timestamp_attributes_for_update_in_model
660
+ attribute_names |= names.map(&:to_s)
468
661
 
469
- clear_attribute_changes(changes.keys)
470
- primary_key = self.class.primary_key
471
- self.class.unscoped.where(primary_key => self[primary_key]).update_all(changes) == 1
662
+ unless attribute_names.empty?
663
+ affected_rows = _touch_row(attribute_names, time)
664
+ @_trigger_update_callback = affected_rows == 1
472
665
  else
473
666
  true
474
667
  end
@@ -481,52 +674,90 @@ module ActiveRecord
481
674
  end
482
675
 
483
676
  def destroy_row
484
- relation_for_destroy.delete_all
677
+ _delete_row
678
+ end
679
+
680
+ def _delete_row
681
+ self.class._delete_record(self.class.primary_key => id_in_database)
485
682
  end
486
683
 
487
- def relation_for_destroy
488
- pk = self.class.primary_key
489
- column = self.class.columns_hash[pk]
490
- substitute = self.class.connection.substitute_at(column)
684
+ def _touch_row(attribute_names, time)
685
+ time ||= current_time_from_proper_timezone
491
686
 
492
- relation = self.class.unscoped.where(
493
- self.class.arel_table[pk].eq(substitute))
687
+ attribute_names.each do |attr_name|
688
+ write_attribute(attr_name, time)
689
+ clear_attribute_change(attr_name)
690
+ end
494
691
 
495
- relation.bind_values = [[column, id]]
496
- relation
692
+ _update_row(attribute_names, "touch")
497
693
  end
498
694
 
499
- def create_or_update
500
- raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
501
- result = new_record? ? _create_record : _update_record
695
+ def _update_row(attribute_names, attempted_action = "update")
696
+ self.class._update_record(
697
+ attributes_with_values(attribute_names),
698
+ self.class.primary_key => id_in_database
699
+ )
700
+ end
701
+
702
+ def create_or_update(*args, &block)
703
+ _raise_readonly_record_error if readonly?
704
+ return false if destroyed?
705
+ result = new_record? ? _create_record(&block) : _update_record(*args, &block)
502
706
  result != false
503
707
  end
504
708
 
505
709
  # Updates the associated record with values matching those of the instance attributes.
506
710
  # Returns the number of affected rows.
507
711
  def _update_record(attribute_names = self.attribute_names)
508
- attributes_values = arel_attributes_with_values_for_update(attribute_names)
509
- if attributes_values.empty?
510
- 0
712
+ attribute_names &= self.class.column_names
713
+ attribute_names = attributes_for_update(attribute_names)
714
+
715
+ if attribute_names.empty?
716
+ affected_rows = 0
717
+ @_trigger_update_callback = true
511
718
  else
512
- self.class.unscoped._update_record attributes_values, id, id_was
719
+ affected_rows = _update_row(attribute_names)
720
+ @_trigger_update_callback = affected_rows == 1
513
721
  end
722
+
723
+ yield(self) if block_given?
724
+
725
+ affected_rows
514
726
  end
515
727
 
516
728
  # Creates a record with values matching those of the instance attributes
517
729
  # and returns its id.
518
730
  def _create_record(attribute_names = self.attribute_names)
519
- attributes_values = arel_attributes_with_values_for_create(attribute_names)
731
+ attribute_names &= self.class.column_names
732
+ attributes_values = attributes_with_values_for_create(attribute_names)
520
733
 
521
- new_id = self.class.unscoped.insert attributes_values
734
+ new_id = self.class._insert_record(attributes_values)
522
735
  self.id ||= new_id if self.class.primary_key
523
736
 
524
737
  @new_record = false
738
+
739
+ yield(self) if block_given?
740
+
525
741
  id
526
742
  end
527
743
 
528
744
  def verify_readonly_attribute(name)
529
745
  raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attributes.include?(name)
530
746
  end
747
+
748
+ def _raise_record_not_destroyed
749
+ @_association_destroy_exception ||= nil
750
+ raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy the record", self)
751
+ ensure
752
+ @_association_destroy_exception = nil
753
+ end
754
+
755
+ def belongs_to_touch_method
756
+ :touch
757
+ end
758
+
759
+ def _raise_readonly_record_error
760
+ raise ReadOnlyRecord, "#{self.class} is marked as readonly"
761
+ end
531
762
  end
532
763
  end