activerecord 4.2.11 → 5.2.4.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 +4 -4
  2. data/CHANGELOG.md +580 -1626
  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 +263 -249
  8. data/lib/active_record/association_relation.rb +11 -6
  9. data/lib/active_record/associations/alias_tracker.rb +29 -35
  10. data/lib/active_record/associations/association.rb +77 -43
  11. data/lib/active_record/associations/association_scope.rb +106 -133
  12. data/lib/active_record/associations/belongs_to_association.rb +52 -41
  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 +9 -22
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +42 -35
  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 +139 -280
  22. data/lib/active_record/associations/collection_proxy.rb +231 -133
  23. data/lib/active_record/associations/foreign_association.rb +3 -1
  24. data/lib/active_record/associations/has_many_association.rb +34 -89
  25. data/lib/active_record/associations/has_many_through_association.rb +49 -76
  26. data/lib/active_record/associations/has_one_association.rb +38 -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 -87
  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 +133 -159
  32. data/lib/active_record/associations/preloader/association.rb +85 -120
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -74
  34. data/lib/active_record/associations/preloader.rb +81 -91
  35. data/lib/active_record/associations/singular_association.rb +27 -34
  36. data/lib/active_record/associations/through_association.rb +38 -18
  37. data/lib/active_record/associations.rb +1732 -1597
  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 +10 -8
  41. data/lib/active_record/attribute_methods/dirty.rb +94 -135
  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 +58 -36
  47. data/lib/active_record/attribute_methods/write.rb +30 -45
  48. data/lib/active_record/attribute_methods.rb +166 -109
  49. data/lib/active_record/attributes.rb +201 -82
  50. data/lib/active_record/autosave_association.rb +94 -36
  51. data/lib/active_record/base.rb +57 -44
  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 +24 -12
  55. data/lib/active_record/collection_cache_key.rb +53 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +712 -290
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +10 -5
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +237 -90
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +71 -21
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +118 -52
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +67 -46
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +318 -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 +570 -228
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +138 -70
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +325 -202
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +542 -601
  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 +41 -180
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +35 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +45 -114
  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 -58
  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 +4 -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 -22
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -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 +5 -7
  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 -5
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +55 -53
  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 +462 -284
  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 +432 -323
  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 -308
  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 +178 -198
  129. data/lib/active_record/counter_cache.rb +79 -36
  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 +135 -88
  133. data/lib/active_record/errors.rb +179 -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 +10 -5
  137. data/lib/active_record/fixture_set/file.rb +35 -9
  138. data/lib/active_record/fixtures.rb +188 -132
  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 +21 -3
  144. data/lib/active_record/locale/en.yml +3 -2
  145. data/lib/active_record/locking/optimistic.rb +88 -96
  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 +581 -282
  152. data/lib/active_record/model_schema.rb +290 -111
  153. data/lib/active_record/nested_attributes.rb +264 -222
  154. data/lib/active_record/no_touching.rb +7 -1
  155. data/lib/active_record/null_relation.rb +24 -37
  156. data/lib/active_record/persistence.rb +347 -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 +94 -32
  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 +149 -156
  163. data/lib/active_record/readonly_attributes.rb +5 -4
  164. data/lib/active_record/reflection.rb +414 -267
  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 +256 -248
  168. data/lib/active_record/relation/delegation.rb +67 -60
  169. data/lib/active_record/relation/finder_methods.rb +288 -239
  170. data/lib/active_record/relation/from_clause.rb +26 -0
  171. data/lib/active_record/relation/merger.rb +86 -86
  172. data/lib/active_record/relation/predicate_builder/array_handler.rb +24 -24
  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 +116 -119
  180. data/lib/active_record/relation/query_attribute.rb +45 -0
  181. data/lib/active_record/relation/query_methods.rb +448 -393
  182. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  183. data/lib/active_record/relation/spawn_methods.rb +11 -13
  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 -340
  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 -16
  193. data/lib/active_record/scoping/default.rb +102 -85
  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 +134 -96
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +56 -100
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +83 -41
  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 +199 -124
  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 -45
  212. data/lib/active_record/type/date_time.rb +4 -49
  213. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  214. data/lib/active_record/type/hash_lookup_type_map.rb +5 -3
  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 +24 -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 +40 -41
  231. data/lib/active_record/validations.rb +38 -35
  232. data/lib/active_record/version.rb +3 -1
  233. data/lib/active_record.rb +34 -22
  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 -3
  238. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +8 -1
  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/model/templates/{module.rb → module.rb.tt} +0 -0
  243. data/lib/rails/generators/active_record.rb +7 -5
  244. metadata +72 -50
  245. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  246. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  247. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  248. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  249. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  250. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  251. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  252. data/lib/active_record/attribute.rb +0 -163
  253. data/lib/active_record/attribute_set/builder.rb +0 -106
  254. data/lib/active_record/attribute_set.rb +0 -81
  255. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  256. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  257. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  258. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  259. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  260. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  261. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  262. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  263. data/lib/active_record/type/big_integer.rb +0 -13
  264. data/lib/active_record/type/binary.rb +0 -50
  265. data/lib/active_record/type/boolean.rb +0 -31
  266. data/lib/active_record/type/decimal.rb +0 -64
  267. data/lib/active_record/type/decorator.rb +0 -14
  268. data/lib/active_record/type/float.rb +0 -19
  269. data/lib/active_record/type/integer.rb +0 -59
  270. data/lib/active_record/type/mutable.rb +0 -16
  271. data/lib/active_record/type/numeric.rb +0 -36
  272. data/lib/active_record/type/string.rb +0 -40
  273. data/lib/active_record/type/time_value.rb +0 -38
  274. data/lib/active_record/type/value.rb +0 -110
@@ -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("Failed to save the record", 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,15 +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
339
  self.class.connection.add_transaction_record(self)
172
- destroy_row if persisted?
340
+ @_trigger_destroy_callback = if persisted?
341
+ destroy_row > 0
342
+ else
343
+ true
344
+ end
173
345
  @destroyed = true
174
346
  freeze
175
347
  end
@@ -177,12 +349,12 @@ module ActiveRecord
177
349
  # Deletes the record in the database and freezes this instance to reflect
178
350
  # that no changes should be made (since they can't be persisted).
179
351
  #
180
- # There's a series of callbacks associated with <tt>destroy!</tt>. If
181
- # the <tt>before_destroy</tt> callback return +false+ the action is cancelled
182
- # and <tt>destroy!</tt> raises ActiveRecord::RecordNotDestroyed. See
183
- # 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.
184
356
  def destroy!
185
- destroy || raise(RecordNotDestroyed.new("Failed to destroy the record", self))
357
+ destroy || _raise_record_not_destroyed
186
358
  end
187
359
 
188
360
  # Returns an instance of the specified +klass+ with the attributes of the
@@ -194,19 +366,22 @@ module ActiveRecord
194
366
  # instance using the companies/company partial instead of clients/client.
195
367
  #
196
368
  # Note: The new instance will share a link to the same attributes as the original class.
197
- # 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.
198
372
  def becomes(klass)
199
- became = klass.new
373
+ became = klass.allocate
374
+ became.send(:initialize)
200
375
  became.instance_variable_set("@attributes", @attributes)
201
- changed_attributes = @changed_attributes if defined?(@changed_attributes)
202
- became.instance_variable_set("@changed_attributes", 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)
203
378
  became.instance_variable_set("@new_record", new_record?)
204
379
  became.instance_variable_set("@destroyed", destroyed?)
205
- became.instance_variable_set("@errors", errors)
380
+ became.errors.copy!(errors)
206
381
  became
207
382
  end
208
383
 
209
- # 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.
210
385
  # This is especially useful if you want to persist the changed class in your
211
386
  # database.
212
387
  #
@@ -226,18 +401,19 @@ module ActiveRecord
226
401
  # This is especially useful for boolean flags on existing records. Also note that
227
402
  #
228
403
  # * Validation is skipped.
229
- # * Callbacks are invoked.
404
+ # * \Callbacks are invoked.
230
405
  # * updated_at/updated_on column is updated if that column is available.
231
406
  # * Updates all the attributes that are dirty in this object.
232
407
  #
233
- # This method raises an +ActiveRecord::ActiveRecordError+ if the
408
+ # This method raises an ActiveRecord::ActiveRecordError if the
234
409
  # attribute is marked as readonly.
235
410
  #
236
- # See also +update_column+.
411
+ # Also see #update_column.
237
412
  def update_attribute(name, value)
238
413
  name = name.to_s
239
414
  verify_readonly_attribute(name)
240
- send("#{name}=", value)
415
+ public_send("#{name}=", value)
416
+
241
417
  save(validate: false)
242
418
  end
243
419
 
@@ -255,8 +431,8 @@ module ActiveRecord
255
431
 
256
432
  alias update_attributes update
257
433
 
258
- # Updates its receiver just like +update+ but calls <tt>save!</tt> instead
259
- # 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.
260
436
  def update!(attributes)
261
437
  # The following transaction covers any possible database side-effects of the
262
438
  # attributes assignment. For example, setting the IDs of a child collection.
@@ -282,11 +458,12 @@ module ActiveRecord
282
458
  # the database, but take into account that in consequence the regular update
283
459
  # procedures are totally bypassed. In particular:
284
460
  #
285
- # * Validations are skipped.
286
- # * Callbacks are skipped.
461
+ # * \Validations are skipped.
462
+ # * \Callbacks are skipped.
287
463
  # * +updated_at+/+updated_on+ are not updated.
464
+ # * However, attributes are serialized with the same rules as ActiveRecord::Relation#update_all
288
465
  #
289
- # This method raises an +ActiveRecord::ActiveRecordError+ when called on new
466
+ # This method raises an ActiveRecord::ActiveRecordError when called on new
290
467
  # objects, or when at least one of the attributes is marked as readonly.
291
468
  def update_columns(attributes)
292
469
  raise ActiveRecordError, "cannot update a new record" if new_record?
@@ -296,13 +473,17 @@ module ActiveRecord
296
473
  verify_readonly_attribute(key.to_s)
297
474
  end
298
475
 
299
- updated_count = self.class.unscoped.where(self.class.primary_key => id).update_all(attributes)
300
-
476
+ id_in_database = self.id_in_database
301
477
  attributes.each do |k, v|
302
- raw_write_attribute(k, v)
478
+ write_attribute_without_type_cast(k, v)
303
479
  end
304
480
 
305
- 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
306
487
  end
307
488
 
308
489
  # Initializes +attribute+ to zero if +nil+ and adds the value passed as +by+ (default is 1).
@@ -314,42 +495,56 @@ module ActiveRecord
314
495
  self
315
496
  end
316
497
 
317
- # Wrapper around +increment+ that saves the record. This method differs from
318
- # its non-bang version in that it passes through the attribute setter.
319
- # Saving is not subjected to validation checks. Returns +true+ if the
320
- # record could be saved.
321
- def increment!(attribute, by = 1)
322
- 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
323
510
  end
324
511
 
325
512
  # Initializes +attribute+ to zero if +nil+ and subtracts the value passed as +by+ (default is 1).
326
513
  # The decrement is performed directly on the underlying attribute, no setter is invoked.
327
514
  # Only makes sense for number-based attributes. Returns +self+.
328
515
  def decrement(attribute, by = 1)
329
- self[attribute] ||= 0
330
- self[attribute] -= by
331
- self
516
+ increment(attribute, -by)
332
517
  end
333
518
 
334
- # Wrapper around +decrement+ that saves the record. This method differs from
335
- # its non-bang version in that it passes through the attribute setter.
336
- # Saving is not subjected to validation checks. Returns +true+ if the
337
- # record could be saved.
338
- def decrement!(attribute, by = 1)
339
- 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)
340
527
  end
341
528
 
342
529
  # Assigns to +attribute+ the boolean opposite of <tt>attribute?</tt>. So
343
530
  # if the predicate returns +true+ the attribute will become +false+. This
344
531
  # method toggles directly the underlying value without calling any setter.
345
532
  # Returns +self+.
533
+ #
534
+ # Example:
535
+ #
536
+ # user = User.first
537
+ # user.banned? # => false
538
+ # user.toggle(:banned)
539
+ # user.banned? # => true
540
+ #
346
541
  def toggle(attribute)
347
- self[attribute] = !send("#{attribute}?")
542
+ self[attribute] = !public_send("#{attribute}?")
348
543
  self
349
544
  end
350
545
 
351
- # Wrapper around +toggle+ that saves the record. This method differs from
352
- # 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.
353
548
  # Saving is not subjected to validation checks. Returns +true+ if the
354
549
  # record could be saved.
355
550
  def toggle!(attribute)
@@ -358,8 +553,8 @@ module ActiveRecord
358
553
 
359
554
  # Reloads the record from the database.
360
555
  #
361
- # This method finds record by its primary key (which could be assigned manually) and
362
- # 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:
363
558
  #
364
559
  # account = Account.new
365
560
  # # => #<Account id: nil, email: nil>
@@ -371,7 +566,7 @@ module ActiveRecord
371
566
  # Attributes are reloaded from the database, and caches busted, in
372
567
  # particular the associations cache and the QueryCache.
373
568
  #
374
- # 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
375
570
  # is raised. Otherwise, in addition to the in-place modification the method
376
571
  # returns +self+ for convenience.
377
572
  #
@@ -405,8 +600,6 @@ module ActiveRecord
405
600
  # end
406
601
  #
407
602
  def reload(options = nil)
408
- clear_aggregation_cache
409
- clear_association_cache
410
603
  self.class.connection.clear_query_cache
411
604
 
412
605
  fresh_object =
@@ -416,24 +609,27 @@ module ActiveRecord
416
609
  self.class.unscoped { self.class.find(id) }
417
610
  end
418
611
 
419
- @attributes = fresh_object.instance_variable_get('@attributes')
612
+ @attributes = fresh_object.instance_variable_get("@attributes")
420
613
  @new_record = false
421
614
  self
422
615
  end
423
616
 
424
- # 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.
425
619
  # Please note that no validation is performed and only the +after_touch+,
426
620
  # +after_commit+ and +after_rollback+ callbacks are executed.
427
621
  #
622
+ # This method can be passed attribute names and an optional time argument.
428
623
  # If attribute names are passed, they are updated along with updated_at/on
429
- # attributes.
624
+ # attributes. If no time argument is passed, the current time is used as default.
430
625
  #
431
- # 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
432
628
  # product.touch(:designed_at) # updates the designed_at attribute and updated_at/on
433
629
  # product.touch(:started_at, :ended_at) # updates started_at, ended_at and updated_at/on attributes
434
630
  #
435
- # If used along with +belongs_to+ then +touch+ will invoke +touch+ method on
436
- # 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.
437
633
  #
438
634
  # class Brake < ActiveRecord::Base
439
635
  # belongs_to :car, touch: true
@@ -452,26 +648,20 @@ module ActiveRecord
452
648
  # ball = Ball.new
453
649
  # ball.touch(:updated_at) # => raises ActiveRecordError
454
650
  #
455
- def touch(*names)
456
- raise ActiveRecordError, "cannot touch on a new record object" unless persisted?
457
-
458
- attributes = timestamp_attributes_for_update_in_model
459
- attributes.concat(names)
460
-
461
- unless attributes.empty?
462
- current_time = current_time_from_proper_timezone
463
- changes = {}
464
-
465
- attributes.each do |column|
466
- column = column.to_s
467
- changes[column] = write_attribute(column, current_time)
468
- 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
469
658
 
470
- 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)
471
661
 
472
- clear_attribute_changes(changes.keys)
473
- primary_key = self.class.primary_key
474
- 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
475
665
  else
476
666
  true
477
667
  end
@@ -484,52 +674,90 @@ module ActiveRecord
484
674
  end
485
675
 
486
676
  def destroy_row
487
- 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)
488
682
  end
489
683
 
490
- def relation_for_destroy
491
- pk = self.class.primary_key
492
- column = self.class.columns_hash[pk]
493
- substitute = self.class.connection.substitute_at(column)
684
+ def _touch_row(attribute_names, time)
685
+ time ||= current_time_from_proper_timezone
494
686
 
495
- relation = self.class.unscoped.where(
496
- 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
497
691
 
498
- relation.bind_values = [[column, id]]
499
- relation
692
+ _update_row(attribute_names, "touch")
500
693
  end
501
694
 
502
- def create_or_update
503
- raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
504
- 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)
505
706
  result != false
506
707
  end
507
708
 
508
709
  # Updates the associated record with values matching those of the instance attributes.
509
710
  # Returns the number of affected rows.
510
711
  def _update_record(attribute_names = self.attribute_names)
511
- attributes_values = arel_attributes_with_values_for_update(attribute_names)
512
- if attributes_values.empty?
513
- 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
514
718
  else
515
- self.class.unscoped._update_record attributes_values, id, id_was
719
+ affected_rows = _update_row(attribute_names)
720
+ @_trigger_update_callback = affected_rows == 1
516
721
  end
722
+
723
+ yield(self) if block_given?
724
+
725
+ affected_rows
517
726
  end
518
727
 
519
728
  # Creates a record with values matching those of the instance attributes
520
729
  # and returns its id.
521
730
  def _create_record(attribute_names = self.attribute_names)
522
- 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)
523
733
 
524
- new_id = self.class.unscoped.insert attributes_values
734
+ new_id = self.class._insert_record(attributes_values)
525
735
  self.id ||= new_id if self.class.primary_key
526
736
 
527
737
  @new_record = false
738
+
739
+ yield(self) if block_given?
740
+
528
741
  id
529
742
  end
530
743
 
531
744
  def verify_readonly_attribute(name)
532
745
  raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attributes.include?(name)
533
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
534
762
  end
535
763
  end