activerecord 3.2.19 → 5.0.0

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 (264) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1715 -604
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +40 -45
  5. data/examples/performance.rb +33 -22
  6. data/examples/simple.rb +3 -4
  7. data/lib/active_record/aggregations.rb +76 -51
  8. data/lib/active_record/association_relation.rb +35 -0
  9. data/lib/active_record/associations/alias_tracker.rb +54 -40
  10. data/lib/active_record/associations/association.rb +76 -56
  11. data/lib/active_record/associations/association_scope.rb +125 -93
  12. data/lib/active_record/associations/belongs_to_association.rb +57 -28
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
  14. data/lib/active_record/associations/builder/association.rb +120 -32
  15. data/lib/active_record/associations/builder/belongs_to.rb +115 -62
  16. data/lib/active_record/associations/builder/collection_association.rb +61 -53
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +117 -43
  18. data/lib/active_record/associations/builder/has_many.rb +9 -65
  19. data/lib/active_record/associations/builder/has_one.rb +18 -52
  20. data/lib/active_record/associations/builder/singular_association.rb +18 -19
  21. data/lib/active_record/associations/collection_association.rb +268 -186
  22. data/lib/active_record/associations/collection_proxy.rb +1003 -63
  23. data/lib/active_record/associations/foreign_association.rb +11 -0
  24. data/lib/active_record/associations/has_many_association.rb +81 -41
  25. data/lib/active_record/associations/has_many_through_association.rb +76 -55
  26. data/lib/active_record/associations/has_one_association.rb +51 -21
  27. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  28. data/lib/active_record/associations/join_dependency/join_association.rb +83 -108
  29. data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
  31. data/lib/active_record/associations/join_dependency.rb +239 -155
  32. data/lib/active_record/associations/preloader/association.rb +97 -62
  33. data/lib/active_record/associations/preloader/collection_association.rb +2 -8
  34. data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
  35. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +75 -33
  38. data/lib/active_record/associations/preloader.rb +111 -79
  39. data/lib/active_record/associations/singular_association.rb +35 -13
  40. data/lib/active_record/associations/through_association.rb +41 -19
  41. data/lib/active_record/associations.rb +727 -501
  42. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  43. data/lib/active_record/attribute.rb +213 -0
  44. data/lib/active_record/attribute_assignment.rb +32 -162
  45. data/lib/active_record/attribute_decorators.rb +67 -0
  46. data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
  47. data/lib/active_record/attribute_methods/dirty.rb +101 -61
  48. data/lib/active_record/attribute_methods/primary_key.rb +50 -36
  49. data/lib/active_record/attribute_methods/query.rb +7 -6
  50. data/lib/active_record/attribute_methods/read.rb +56 -117
  51. data/lib/active_record/attribute_methods/serialization.rb +43 -96
  52. data/lib/active_record/attribute_methods/time_zone_conversion.rb +93 -42
  53. data/lib/active_record/attribute_methods/write.rb +34 -45
  54. data/lib/active_record/attribute_methods.rb +333 -144
  55. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  56. data/lib/active_record/attribute_set/builder.rb +108 -0
  57. data/lib/active_record/attribute_set.rb +108 -0
  58. data/lib/active_record/attributes.rb +265 -0
  59. data/lib/active_record/autosave_association.rb +285 -223
  60. data/lib/active_record/base.rb +95 -490
  61. data/lib/active_record/callbacks.rb +95 -61
  62. data/lib/active_record/coders/json.rb +13 -0
  63. data/lib/active_record/coders/yaml_column.rb +28 -19
  64. data/lib/active_record/collection_cache_key.rb +40 -0
  65. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +724 -277
  66. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  67. data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -192
  68. data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -26
  69. data/lib/active_record/connection_adapters/abstract/quoting.rb +140 -57
  70. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +147 -0
  72. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +419 -276
  73. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +105 -0
  74. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +963 -276
  75. data/lib/active_record/connection_adapters/abstract/transaction.rb +232 -0
  76. data/lib/active_record/connection_adapters/abstract_adapter.rb +397 -106
  77. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +643 -342
  78. data/lib/active_record/connection_adapters/column.rb +30 -259
  79. data/lib/active_record/connection_adapters/connection_specification.rb +263 -0
  80. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  81. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  82. data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
  83. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  84. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  85. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  86. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  87. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  88. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  89. data/lib/active_record/connection_adapters/mysql2_adapter.rb +47 -196
  90. data/lib/active_record/connection_adapters/postgresql/column.rb +15 -0
  91. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +170 -0
  92. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +70 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +48 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +21 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +10 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +39 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +93 -0
  109. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
  110. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  111. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  112. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  113. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  114. data/lib/active_record/connection_adapters/postgresql/oid.rb +31 -0
  115. data/lib/active_record/connection_adapters/postgresql/quoting.rb +116 -0
  116. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +49 -0
  117. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +180 -0
  118. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  119. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +682 -0
  120. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  121. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  122. data/lib/active_record/connection_adapters/postgresql_adapter.rb +558 -1039
  123. data/lib/active_record/connection_adapters/schema_cache.rb +74 -36
  124. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  125. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  126. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  127. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  128. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +538 -24
  129. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  130. data/lib/active_record/connection_handling.rb +155 -0
  131. data/lib/active_record/core.rb +561 -0
  132. data/lib/active_record/counter_cache.rb +146 -105
  133. data/lib/active_record/dynamic_matchers.rb +101 -64
  134. data/lib/active_record/enum.rb +234 -0
  135. data/lib/active_record/errors.rb +153 -56
  136. data/lib/active_record/explain.rb +15 -63
  137. data/lib/active_record/explain_registry.rb +30 -0
  138. data/lib/active_record/explain_subscriber.rb +10 -6
  139. data/lib/active_record/fixture_set/file.rb +77 -0
  140. data/lib/active_record/fixtures.rb +355 -232
  141. data/lib/active_record/gem_version.rb +15 -0
  142. data/lib/active_record/inheritance.rb +144 -79
  143. data/lib/active_record/integration.rb +66 -13
  144. data/lib/active_record/internal_metadata.rb +56 -0
  145. data/lib/active_record/legacy_yaml_adapter.rb +46 -0
  146. data/lib/active_record/locale/en.yml +9 -1
  147. data/lib/active_record/locking/optimistic.rb +77 -56
  148. data/lib/active_record/locking/pessimistic.rb +6 -6
  149. data/lib/active_record/log_subscriber.rb +53 -28
  150. data/lib/active_record/migration/command_recorder.rb +166 -33
  151. data/lib/active_record/migration/compatibility.rb +126 -0
  152. data/lib/active_record/migration/join_table.rb +15 -0
  153. data/lib/active_record/migration.rb +792 -264
  154. data/lib/active_record/model_schema.rb +192 -130
  155. data/lib/active_record/nested_attributes.rb +238 -145
  156. data/lib/active_record/no_touching.rb +52 -0
  157. data/lib/active_record/null_relation.rb +89 -0
  158. data/lib/active_record/persistence.rb +357 -157
  159. data/lib/active_record/query_cache.rb +22 -43
  160. data/lib/active_record/querying.rb +34 -23
  161. data/lib/active_record/railtie.rb +88 -48
  162. data/lib/active_record/railties/console_sandbox.rb +3 -4
  163. data/lib/active_record/railties/controller_runtime.rb +5 -4
  164. data/lib/active_record/railties/databases.rake +170 -422
  165. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  166. data/lib/active_record/readonly_attributes.rb +2 -5
  167. data/lib/active_record/reflection.rb +715 -189
  168. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  169. data/lib/active_record/relation/batches.rb +203 -50
  170. data/lib/active_record/relation/calculations.rb +203 -194
  171. data/lib/active_record/relation/delegation.rb +103 -25
  172. data/lib/active_record/relation/finder_methods.rb +457 -261
  173. data/lib/active_record/relation/from_clause.rb +32 -0
  174. data/lib/active_record/relation/merger.rb +167 -0
  175. data/lib/active_record/relation/predicate_builder/array_handler.rb +43 -0
  176. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  177. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  178. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  179. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  180. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  181. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  182. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  183. data/lib/active_record/relation/predicate_builder.rb +153 -48
  184. data/lib/active_record/relation/query_attribute.rb +19 -0
  185. data/lib/active_record/relation/query_methods.rb +1019 -194
  186. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  187. data/lib/active_record/relation/spawn_methods.rb +46 -150
  188. data/lib/active_record/relation/where_clause.rb +174 -0
  189. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  190. data/lib/active_record/relation.rb +450 -245
  191. data/lib/active_record/result.rb +104 -12
  192. data/lib/active_record/runtime_registry.rb +22 -0
  193. data/lib/active_record/sanitization.rb +120 -94
  194. data/lib/active_record/schema.rb +28 -18
  195. data/lib/active_record/schema_dumper.rb +141 -74
  196. data/lib/active_record/schema_migration.rb +50 -0
  197. data/lib/active_record/scoping/default.rb +64 -57
  198. data/lib/active_record/scoping/named.rb +93 -108
  199. data/lib/active_record/scoping.rb +73 -121
  200. data/lib/active_record/secure_token.rb +38 -0
  201. data/lib/active_record/serialization.rb +7 -5
  202. data/lib/active_record/statement_cache.rb +113 -0
  203. data/lib/active_record/store.rb +173 -15
  204. data/lib/active_record/suppressor.rb +58 -0
  205. data/lib/active_record/table_metadata.rb +68 -0
  206. data/lib/active_record/tasks/database_tasks.rb +313 -0
  207. data/lib/active_record/tasks/mysql_database_tasks.rb +151 -0
  208. data/lib/active_record/tasks/postgresql_database_tasks.rb +110 -0
  209. data/lib/active_record/tasks/sqlite_database_tasks.rb +59 -0
  210. data/lib/active_record/timestamp.rb +42 -24
  211. data/lib/active_record/touch_later.rb +58 -0
  212. data/lib/active_record/transactions.rb +233 -105
  213. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  214. data/lib/active_record/type/date.rb +7 -0
  215. data/lib/active_record/type/date_time.rb +7 -0
  216. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  217. data/lib/active_record/type/internal/abstract_json.rb +29 -0
  218. data/lib/active_record/type/internal/timezone.rb +15 -0
  219. data/lib/active_record/type/serialized.rb +63 -0
  220. data/lib/active_record/type/time.rb +20 -0
  221. data/lib/active_record/type/type_map.rb +64 -0
  222. data/lib/active_record/type.rb +72 -0
  223. data/lib/active_record/type_caster/connection.rb +29 -0
  224. data/lib/active_record/type_caster/map.rb +19 -0
  225. data/lib/active_record/type_caster.rb +7 -0
  226. data/lib/active_record/validations/absence.rb +23 -0
  227. data/lib/active_record/validations/associated.rb +33 -18
  228. data/lib/active_record/validations/length.rb +24 -0
  229. data/lib/active_record/validations/presence.rb +66 -0
  230. data/lib/active_record/validations/uniqueness.rb +128 -68
  231. data/lib/active_record/validations.rb +48 -40
  232. data/lib/active_record/version.rb +5 -7
  233. data/lib/active_record.rb +71 -47
  234. data/lib/rails/generators/active_record/migration/migration_generator.rb +56 -8
  235. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +24 -0
  236. data/lib/rails/generators/active_record/migration/templates/migration.rb +28 -16
  237. data/lib/rails/generators/active_record/migration.rb +18 -8
  238. data/lib/rails/generators/active_record/model/model_generator.rb +38 -16
  239. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  240. data/lib/rails/generators/active_record/model/templates/model.rb +7 -6
  241. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  242. data/lib/rails/generators/active_record.rb +3 -11
  243. metadata +188 -134
  244. data/examples/associations.png +0 -0
  245. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  246. data/lib/active_record/associations/join_helper.rb +0 -55
  247. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  248. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  249. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  250. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -441
  251. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  252. data/lib/active_record/dynamic_finder_match.rb +0 -68
  253. data/lib/active_record/dynamic_scope_match.rb +0 -23
  254. data/lib/active_record/fixtures/file.rb +0 -65
  255. data/lib/active_record/identity_map.rb +0 -162
  256. data/lib/active_record/observer.rb +0 -121
  257. data/lib/active_record/serializers/xml_serializer.rb +0 -203
  258. data/lib/active_record/session_store.rb +0 -360
  259. data/lib/active_record/test_case.rb +0 -73
  260. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
  261. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  262. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  263. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  264. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,7 +1,5 @@
1
- require 'active_support/concern'
2
-
3
1
  module ActiveRecord
4
- # = Active Record Persistence
2
+ # = Active Record \Persistence
5
3
  module Persistence
6
4
  extend ActiveSupport::Concern
7
5
 
@@ -9,99 +7,149 @@ module ActiveRecord
9
7
  # Creates an object (or multiple objects) and saves it to the database, if validations pass.
10
8
  # The resulting object is returned whether the object was saved successfully to the database or not.
11
9
  #
12
- # The +attributes+ parameter can be either be a Hash or an Array of Hashes. These Hashes describe the
10
+ # The +attributes+ parameter can be either a Hash or an Array of Hashes. These Hashes describe the
13
11
  # attributes on the objects that are to be created.
14
12
  #
15
- # +create+ respects mass-assignment security and accepts either +:as+ or +:without_protection+ options
16
- # in the +options+ parameter.
17
- #
18
13
  # ==== Examples
19
14
  # # Create a single new object
20
- # User.create(:first_name => 'Jamie')
21
- #
22
- # # Create a single new object using the :admin mass-assignment security role
23
- # User.create({ :first_name => 'Jamie', :is_admin => true }, :as => :admin)
24
- #
25
- # # Create a single new object bypassing mass-assignment security
26
- # User.create({ :first_name => 'Jamie', :is_admin => true }, :without_protection => true)
15
+ # User.create(first_name: 'Jamie')
27
16
  #
28
17
  # # Create an Array of new objects
29
- # User.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }])
18
+ # User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }])
30
19
  #
31
20
  # # Create a single object and pass it into a block to set other attributes.
32
- # User.create(:first_name => 'Jamie') do |u|
21
+ # User.create(first_name: 'Jamie') do |u|
33
22
  # u.is_admin = false
34
23
  # end
35
24
  #
36
25
  # # Creating an Array of new objects using a block, where the block is executed for each object:
37
- # User.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }]) do |u|
26
+ # User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }]) do |u|
38
27
  # u.is_admin = false
39
28
  # end
40
- def create(attributes = nil, options = {}, &block)
29
+ def create(attributes = nil, &block)
41
30
  if attributes.is_a?(Array)
42
- attributes.collect { |attr| create(attr, options, &block) }
31
+ attributes.collect { |attr| create(attr, &block) }
43
32
  else
44
- object = new(attributes, options, &block)
33
+ object = new(attributes, &block)
45
34
  object.save
46
35
  object
47
36
  end
48
37
  end
38
+
39
+ # Creates an object (or multiple objects) and saves it to the database,
40
+ # if validations pass. Raises a RecordInvalid error if validations fail,
41
+ # unlike Base#create.
42
+ #
43
+ # The +attributes+ parameter can be either a Hash or an Array of Hashes.
44
+ # These describe which attributes to be created on the object, or
45
+ # multiple objects when given an Array of Hashes.
46
+ def create!(attributes = nil, &block)
47
+ if attributes.is_a?(Array)
48
+ attributes.collect { |attr| create!(attr, &block) }
49
+ else
50
+ object = new(attributes, &block)
51
+ object.save!
52
+ object
53
+ end
54
+ end
55
+
56
+ # Given an attributes hash, +instantiate+ returns a new instance of
57
+ # the appropriate class. Accepts only keys as strings.
58
+ #
59
+ # For example, +Post.all+ may return Comments, Messages, and Emails
60
+ # by storing the record's subclass in a +type+ attribute. By calling
61
+ # +instantiate+ instead of +new+, finder methods ensure they get new
62
+ # instances of the appropriate class for each record.
63
+ #
64
+ # See <tt>ActiveRecord::Inheritance#discriminate_class_for_record</tt> to see
65
+ # how this "single-table" inheritance mapping is implemented.
66
+ def instantiate(attributes, column_types = {})
67
+ klass = discriminate_class_for_record(attributes)
68
+ attributes = klass.attributes_builder.build_from_database(attributes, column_types)
69
+ klass.allocate.init_with('attributes' => attributes, 'new_record' => false)
70
+ end
71
+
72
+ private
73
+ # Called by +instantiate+ to decide which class to use for a new
74
+ # record instance.
75
+ #
76
+ # See +ActiveRecord::Inheritance#discriminate_class_for_record+ for
77
+ # the single-table inheritance discriminator.
78
+ def discriminate_class_for_record(record)
79
+ self
80
+ end
49
81
  end
50
82
 
51
83
  # Returns true if this object hasn't been saved yet -- that is, a record
52
- # for the object doesn't exist in the data store yet; otherwise, returns false.
84
+ # for the object doesn't exist in the database yet; otherwise, returns false.
53
85
  def new_record?
86
+ sync_with_transaction_state
54
87
  @new_record
55
88
  end
56
89
 
57
90
  # Returns true if this object has been destroyed, otherwise returns false.
58
91
  def destroyed?
92
+ sync_with_transaction_state
59
93
  @destroyed
60
94
  end
61
95
 
62
- # Returns if the record is persisted, i.e. it's not a new record and it was
63
- # not destroyed.
96
+ # Returns true if the record is persisted, i.e. it's not a new record and it was
97
+ # not destroyed, otherwise returns false.
64
98
  def persisted?
65
- !(new_record? || destroyed?)
99
+ sync_with_transaction_state
100
+ !(@new_record || @destroyed)
66
101
  end
67
102
 
68
103
  # Saves the model.
69
104
  #
70
- # If the model is new a record gets created in the database, otherwise
105
+ # If the model is new, a record gets created in the database, otherwise
71
106
  # the existing record gets updated.
72
107
  #
73
- # By default, save always run validations. If any of them fail the action
74
- # is cancelled and +save+ returns +false+. However, if you supply
75
- # :validate => false, validations are bypassed altogether. See
108
+ # By default, save always runs validations. If any of them fail the action
109
+ # is cancelled and #save returns +false+, and the record won't be saved. However, if you supply
110
+ # validate: false, validations are bypassed altogether. See
76
111
  # ActiveRecord::Validations for more information.
77
112
  #
78
- # There's a series of callbacks associated with +save+. If any of the
79
- # <tt>before_*</tt> callbacks return +false+ the action is cancelled and
80
- # +save+ returns +false+. See ActiveRecord::Callbacks for further
113
+ # By default, #save also sets the +updated_at+/+updated_on+ attributes to
114
+ # the current time. However, if you supply <tt>touch: false</tt>, these
115
+ # timestamps will not be updated.
116
+ #
117
+ # There's a series of callbacks associated with #save. If any of the
118
+ # <tt>before_*</tt> callbacks throws +:abort+ the action is cancelled and
119
+ # #save returns +false+. See ActiveRecord::Callbacks for further
81
120
  # details.
82
- def save(*)
83
- begin
84
- create_or_update
85
- rescue ActiveRecord::RecordInvalid
86
- false
87
- end
121
+ #
122
+ # Attributes marked as readonly are silently ignored if the record is
123
+ # being updated.
124
+ def save(*args)
125
+ create_or_update(*args)
126
+ rescue ActiveRecord::RecordInvalid
127
+ false
88
128
  end
89
129
 
90
130
  # Saves the model.
91
131
  #
92
- # If the model is new a record gets created in the database, otherwise
132
+ # If the model is new, a record gets created in the database, otherwise
93
133
  # the existing record gets updated.
94
134
  #
95
- # With <tt>save!</tt> validations always run. If any of them fail
96
- # ActiveRecord::RecordInvalid gets raised. See ActiveRecord::Validations
97
- # for more information.
135
+ # By default, #save! always runs validations. If any of them fail
136
+ # ActiveRecord::RecordInvalid gets raised, and the record won't be saved. However, if you supply
137
+ # validate: false, validations are bypassed altogether. See
138
+ # ActiveRecord::Validations for more information.
139
+ #
140
+ # By default, #save! also sets the +updated_at+/+updated_on+ attributes to
141
+ # the current time. However, if you supply <tt>touch: false</tt>, these
142
+ # timestamps will not be updated.
98
143
  #
99
- # There's a series of callbacks associated with <tt>save!</tt>. If any of
100
- # the <tt>before_*</tt> callbacks return +false+ the action is cancelled
101
- # and <tt>save!</tt> raises ActiveRecord::RecordNotSaved. See
144
+ # There's a series of callbacks associated with #save!. If any of
145
+ # the <tt>before_*</tt> callbacks throws +:abort+ the action is cancelled
146
+ # and #save! raises ActiveRecord::RecordNotSaved. See
102
147
  # ActiveRecord::Callbacks for further details.
103
- def save!(*)
104
- create_or_update || raise(RecordNotSaved)
148
+ #
149
+ # Attributes marked as readonly are silently ignored if the record is
150
+ # being updated.
151
+ def save!(*args)
152
+ create_or_update(*args) || raise(RecordNotSaved.new("Failed to save the record", self))
105
153
  end
106
154
 
107
155
  # Deletes the record in the database and freezes this instance to
@@ -111,58 +159,80 @@ module ActiveRecord
111
159
  # The row is simply removed with an SQL +DELETE+ statement on the
112
160
  # record's primary key, and no callbacks are executed.
113
161
  #
162
+ # Note that this will also delete records marked as {#readonly?}[rdoc-ref:Core#readonly?].
163
+ #
114
164
  # To enforce the object's +before_destroy+ and +after_destroy+
115
- # callbacks, Observer methods, or any <tt>:dependent</tt> association
165
+ # callbacks or any <tt>:dependent</tt> association
116
166
  # options, use <tt>#destroy</tt>.
117
167
  def delete
118
- if persisted?
119
- self.class.delete(id)
120
- IdentityMap.remove(self) if IdentityMap.enabled?
121
- end
168
+ self.class.delete(id) if persisted?
122
169
  @destroyed = true
123
170
  freeze
124
171
  end
125
172
 
126
173
  # Deletes the record in the database and freezes this instance to reflect
127
174
  # that no changes should be made (since they can't be persisted).
175
+ #
176
+ # There's a series of callbacks associated with #destroy. If the
177
+ # <tt>before_destroy</tt> callback throws +:abort+ the action is cancelled
178
+ # and #destroy returns +false+.
179
+ # See ActiveRecord::Callbacks for further details.
128
180
  def destroy
181
+ raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
129
182
  destroy_associations
130
-
131
- if persisted?
132
- IdentityMap.remove(self) if IdentityMap.enabled?
133
- pk = self.class.primary_key
134
- column = self.class.columns_hash[pk]
135
- substitute = connection.substitute_at(column, 0)
136
-
137
- relation = self.class.unscoped.where(
138
- self.class.arel_table[pk].eq(substitute))
139
-
140
- relation.bind_values = [[column, id]]
141
- relation.delete_all
142
- end
143
-
183
+ self.class.connection.add_transaction_record(self)
184
+ destroy_row if persisted?
144
185
  @destroyed = true
145
186
  freeze
146
187
  end
147
188
 
189
+ # Deletes the record in the database and freezes this instance to reflect
190
+ # that no changes should be made (since they can't be persisted).
191
+ #
192
+ # There's a series of callbacks associated with #destroy!. If the
193
+ # <tt>before_destroy</tt> callback throws +:abort+ the action is cancelled
194
+ # and #destroy! raises ActiveRecord::RecordNotDestroyed.
195
+ # See ActiveRecord::Callbacks for further details.
196
+ def destroy!
197
+ destroy || _raise_record_not_destroyed
198
+ end
199
+
148
200
  # Returns an instance of the specified +klass+ with the attributes of the
149
201
  # current record. This is mostly useful in relation to single-table
150
202
  # inheritance structures where you want a subclass to appear as the
151
203
  # superclass. This can be used along with record identification in
152
204
  # Action Pack to allow, say, <tt>Client < Company</tt> to do something
153
- # like render <tt>:partial => @client.becomes(Company)</tt> to render that
205
+ # like render <tt>partial: @client.becomes(Company)</tt> to render that
154
206
  # instance using the companies/company partial instead of clients/client.
155
207
  #
156
208
  # Note: The new instance will share a link to the same attributes as the original class.
157
- # So any change to the attributes in either instance will affect the other.
209
+ # Therefore the sti column value will still be the same.
210
+ # Any change to the attributes on either instance will affect both instances.
211
+ # If you want to change the sti column as well, use #becomes! instead.
158
212
  def becomes(klass)
159
213
  became = klass.new
160
214
  became.instance_variable_set("@attributes", @attributes)
161
- became.instance_variable_set("@attributes_cache", @attributes_cache)
215
+ became.instance_variable_set("@mutation_tracker", @mutation_tracker) if defined?(@mutation_tracker)
216
+ became.instance_variable_set("@changed_attributes", attributes_changed_by_setter)
162
217
  became.instance_variable_set("@new_record", new_record?)
163
218
  became.instance_variable_set("@destroyed", destroyed?)
164
- became.instance_variable_set("@errors", errors)
165
- became.send("#{klass.inheritance_column}=", klass.name) unless self.class.descends_from_active_record?
219
+ became.errors.copy!(errors)
220
+ became
221
+ end
222
+
223
+ # Wrapper around #becomes that also changes the instance's sti column value.
224
+ # This is especially useful if you want to persist the changed class in your
225
+ # database.
226
+ #
227
+ # Note: The old instance's sti column value will be changed too, as both objects
228
+ # share the same set of attributes.
229
+ def becomes!(klass)
230
+ became = becomes(klass)
231
+ sti_type = nil
232
+ if !klass.descends_from_active_record?
233
+ sti_type = klass.sti_name
234
+ end
235
+ became.public_send("#{klass.inheritance_column}=", sti_type)
166
236
  became
167
237
  end
168
238
 
@@ -170,65 +240,86 @@ module ActiveRecord
170
240
  # This is especially useful for boolean flags on existing records. Also note that
171
241
  #
172
242
  # * Validation is skipped.
173
- # * Callbacks are invoked.
243
+ # * \Callbacks are invoked.
174
244
  # * updated_at/updated_on column is updated if that column is available.
175
245
  # * Updates all the attributes that are dirty in this object.
176
246
  #
177
- def update_attribute(name, value)
178
- name = name.to_s
179
- raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attributes.include?(name)
180
- send("#{name}=", value)
181
- save(:validate => false)
182
- end
183
-
184
- # Updates a single attribute of an object, without calling save.
185
- #
186
- # * Validation is skipped.
187
- # * Callbacks are skipped.
188
- # * updated_at/updated_on column is not updated if that column is available.
189
- #
190
- # Raises an +ActiveRecordError+ when called on new objects, or when the +name+
247
+ # This method raises an ActiveRecord::ActiveRecordError if the
191
248
  # attribute is marked as readonly.
192
- def update_column(name, value)
249
+ #
250
+ # Also see #update_column.
251
+ def update_attribute(name, value)
193
252
  name = name.to_s
194
- raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attributes.include?(name)
195
- raise ActiveRecordError, "can not update on a new record object" unless persisted?
196
-
197
- updated_count = self.class.unscoped.update_all({ name => value }, self.class.primary_key => id)
198
-
199
- raw_write_attribute(name, value)
200
-
201
- updated_count == 1
253
+ verify_readonly_attribute(name)
254
+ public_send("#{name}=", value)
255
+ save(validate: false) if changed?
202
256
  end
203
257
 
204
258
  # Updates the attributes of the model from the passed-in hash and saves the
205
259
  # record, all wrapped in a transaction. If the object is invalid, the saving
206
260
  # will fail and false will be returned.
207
- #
208
- # When updating model attributes, mass-assignment security protection is respected.
209
- # If no +:as+ option is supplied then the +:default+ role will be used.
210
- # If you want to bypass the protection given by +attr_protected+ and
211
- # +attr_accessible+ then you can do so using the +:without_protection+ option.
212
- def update_attributes(attributes, options = {})
261
+ def update(attributes)
213
262
  # The following transaction covers any possible database side-effects of the
214
263
  # attributes assignment. For example, setting the IDs of a child collection.
215
264
  with_transaction_returning_status do
216
- self.assign_attributes(attributes, options)
265
+ assign_attributes(attributes)
217
266
  save
218
267
  end
219
268
  end
220
269
 
221
- # Updates its receiver just like +update_attributes+ but calls <tt>save!</tt> instead
222
- # of +save+, so an exception is raised if the record is invalid.
223
- def update_attributes!(attributes, options = {})
270
+ alias update_attributes update
271
+
272
+ # Updates its receiver just like #update but calls #save! instead
273
+ # of +save+, so an exception is raised if the record is invalid and saving will fail.
274
+ def update!(attributes)
224
275
  # The following transaction covers any possible database side-effects of the
225
276
  # attributes assignment. For example, setting the IDs of a child collection.
226
277
  with_transaction_returning_status do
227
- self.assign_attributes(attributes, options)
278
+ assign_attributes(attributes)
228
279
  save!
229
280
  end
230
281
  end
231
282
 
283
+ alias update_attributes! update!
284
+
285
+ # Equivalent to <code>update_columns(name => value)</code>.
286
+ def update_column(name, value)
287
+ update_columns(name => value)
288
+ end
289
+
290
+ # Updates the attributes directly in the database issuing an UPDATE SQL
291
+ # statement and sets them in the receiver:
292
+ #
293
+ # user.update_columns(last_request_at: Time.current)
294
+ #
295
+ # This is the fastest way to update attributes because it goes straight to
296
+ # the database, but take into account that in consequence the regular update
297
+ # procedures are totally bypassed. In particular:
298
+ #
299
+ # * \Validations are skipped.
300
+ # * \Callbacks are skipped.
301
+ # * +updated_at+/+updated_on+ are not updated.
302
+ # * However, attributes are serialized with the same rules as ActiveRecord::Relation#update_all
303
+ #
304
+ # This method raises an ActiveRecord::ActiveRecordError when called on new
305
+ # objects, or when at least one of the attributes is marked as readonly.
306
+ def update_columns(attributes)
307
+ raise ActiveRecordError, "cannot update a new record" if new_record?
308
+ raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
309
+
310
+ attributes.each_key do |key|
311
+ verify_readonly_attribute(key.to_s)
312
+ end
313
+
314
+ updated_count = self.class.unscoped.where(self.class.primary_key => id).update_all(attributes)
315
+
316
+ attributes.each do |k, v|
317
+ raw_write_attribute(k, v)
318
+ end
319
+
320
+ updated_count == 1
321
+ end
322
+
232
323
  # Initializes +attribute+ to zero if +nil+ and adds the value passed as +by+ (default is 1).
233
324
  # The increment is performed directly on the underlying attribute, no setter is invoked.
234
325
  # Only makes sense for number-based attributes. Returns +self+.
@@ -238,102 +329,189 @@ module ActiveRecord
238
329
  self
239
330
  end
240
331
 
241
- # Wrapper around +increment+ that saves the record. This method differs from
332
+ # Wrapper around #increment that saves the record. This method differs from
242
333
  # its non-bang version in that it passes through the attribute setter.
243
334
  # Saving is not subjected to validation checks. Returns +true+ if the
244
335
  # record could be saved.
245
336
  def increment!(attribute, by = 1)
246
- increment(attribute, by).update_attribute(attribute, self[attribute])
337
+ increment(attribute, by)
338
+ change = public_send(attribute) - (attribute_was(attribute.to_s) || 0)
339
+ self.class.update_counters(id, attribute => change)
340
+ clear_attribute_change(attribute) # eww
341
+ self
247
342
  end
248
343
 
249
344
  # Initializes +attribute+ to zero if +nil+ and subtracts the value passed as +by+ (default is 1).
250
345
  # The decrement is performed directly on the underlying attribute, no setter is invoked.
251
346
  # Only makes sense for number-based attributes. Returns +self+.
252
347
  def decrement(attribute, by = 1)
253
- self[attribute] ||= 0
254
- self[attribute] -= by
255
- self
348
+ increment(attribute, -by)
256
349
  end
257
350
 
258
- # Wrapper around +decrement+ that saves the record. This method differs from
259
- # its non-bang version in that it passes through the attribute setter.
351
+ # Wrapper around #decrement that saves the record. This method differs from
352
+ # its non-bang version in the sense that it passes through the attribute setter.
260
353
  # Saving is not subjected to validation checks. Returns +true+ if the
261
354
  # record could be saved.
262
355
  def decrement!(attribute, by = 1)
263
- decrement(attribute, by).update_attribute(attribute, self[attribute])
356
+ increment!(attribute, -by)
264
357
  end
265
358
 
266
359
  # Assigns to +attribute+ the boolean opposite of <tt>attribute?</tt>. So
267
360
  # if the predicate returns +true+ the attribute will become +false+. This
268
361
  # method toggles directly the underlying value without calling any setter.
269
362
  # Returns +self+.
363
+ #
364
+ # Example:
365
+ #
366
+ # user = User.first
367
+ # user.banned? # => false
368
+ # user.toggle(:banned)
369
+ # user.banned? # => true
370
+ #
270
371
  def toggle(attribute)
271
- self[attribute] = !send("#{attribute}?")
372
+ self[attribute] = !public_send("#{attribute}?")
272
373
  self
273
374
  end
274
375
 
275
- # Wrapper around +toggle+ that saves the record. This method differs from
276
- # its non-bang version in that it passes through the attribute setter.
376
+ # Wrapper around #toggle that saves the record. This method differs from
377
+ # its non-bang version in the sense that it passes through the attribute setter.
277
378
  # Saving is not subjected to validation checks. Returns +true+ if the
278
379
  # record could be saved.
279
380
  def toggle!(attribute)
280
381
  toggle(attribute).update_attribute(attribute, self[attribute])
281
382
  end
282
383
 
283
- # Reloads the attributes of this object from the database.
284
- # The optional options argument is passed to find when reloading so you
285
- # may do e.g. record.reload(:lock => true) to reload the same record with
286
- # an exclusive row lock.
384
+ # Reloads the record from the database.
385
+ #
386
+ # This method finds record by its primary key (which could be assigned manually) and
387
+ # modifies the receiver in-place:
388
+ #
389
+ # account = Account.new
390
+ # # => #<Account id: nil, email: nil>
391
+ # account.id = 1
392
+ # account.reload
393
+ # # Account Load (1.2ms) SELECT "accounts".* FROM "accounts" WHERE "accounts"."id" = $1 LIMIT 1 [["id", 1]]
394
+ # # => #<Account id: 1, email: 'account@example.com'>
395
+ #
396
+ # Attributes are reloaded from the database, and caches busted, in
397
+ # particular the associations cache and the QueryCache.
398
+ #
399
+ # If the record no longer exists in the database ActiveRecord::RecordNotFound
400
+ # is raised. Otherwise, in addition to the in-place modification the method
401
+ # returns +self+ for convenience.
402
+ #
403
+ # The optional <tt>:lock</tt> flag option allows you to lock the reloaded record:
404
+ #
405
+ # reload(lock: true) # reload with pessimistic locking
406
+ #
407
+ # Reloading is commonly used in test suites to test something is actually
408
+ # written to the database, or when some action modifies the corresponding
409
+ # row in the database but not the object in memory:
410
+ #
411
+ # assert account.deposit!(25)
412
+ # assert_equal 25, account.credit # check it is updated in memory
413
+ # assert_equal 25, account.reload.credit # check it is also persisted
414
+ #
415
+ # Another common use case is optimistic locking handling:
416
+ #
417
+ # def with_optimistic_retry
418
+ # begin
419
+ # yield
420
+ # rescue ActiveRecord::StaleObjectError
421
+ # begin
422
+ # # Reload lock_version in particular.
423
+ # reload
424
+ # rescue ActiveRecord::RecordNotFound
425
+ # # If the record is gone there is nothing to do.
426
+ # else
427
+ # retry
428
+ # end
429
+ # end
430
+ # end
431
+ #
287
432
  def reload(options = nil)
288
- clear_aggregation_cache
289
- clear_association_cache
433
+ self.class.connection.clear_query_cache
290
434
 
291
- IdentityMap.without do
292
- fresh_object = self.class.unscoped { self.class.find(self.id, options) }
293
- @attributes.update(fresh_object.instance_variable_get('@attributes'))
294
- end
435
+ fresh_object =
436
+ if options && options[:lock]
437
+ self.class.unscoped { self.class.lock(options[:lock]).find(id) }
438
+ else
439
+ self.class.unscoped { self.class.find(id) }
440
+ end
295
441
 
296
- @attributes_cache = {}
442
+ @attributes = fresh_object.instance_variable_get('@attributes')
443
+ @new_record = false
297
444
  self
298
445
  end
299
446
 
300
- # Saves the record with the updated_at/on attributes set to the current time.
301
- # Please note that no validation is performed and no callbacks are executed.
302
- # If an attribute name is passed, that attribute is updated along with
303
- # updated_at/on attributes.
447
+ # Saves the record with the updated_at/on attributes set to the current time
448
+ # or the time specified.
449
+ # Please note that no validation is performed and only the +after_touch+,
450
+ # +after_commit+ and +after_rollback+ callbacks are executed.
304
451
  #
305
- # product.touch # updates updated_at/on
306
- # product.touch(:designed_at) # updates the designed_at attribute and updated_at/on
452
+ # This method can be passed attribute names and an optional time argument.
453
+ # If attribute names are passed, they are updated along with updated_at/on
454
+ # attributes. If no time argument is passed, the current time is used as default.
307
455
  #
308
- # If used along with +belongs_to+ then +touch+ will invoke +touch+ method on associated object.
456
+ # product.touch # updates updated_at/on with current time
457
+ # product.touch(time: Time.new(2015, 2, 16, 0, 0, 0)) # updates updated_at/on with specified time
458
+ # product.touch(:designed_at) # updates the designed_at attribute and updated_at/on
459
+ # product.touch(:started_at, :ended_at) # updates started_at, ended_at and updated_at/on attributes
460
+ #
461
+ # If used along with {belongs_to}[rdoc-ref:Associations::ClassMethods#belongs_to]
462
+ # then +touch+ will invoke +touch+ method on associated object.
309
463
  #
310
464
  # class Brake < ActiveRecord::Base
311
- # belongs_to :car, :touch => true
465
+ # belongs_to :car, touch: true
312
466
  # end
313
467
  #
314
468
  # class Car < ActiveRecord::Base
315
- # belongs_to :corporation, :touch => true
469
+ # belongs_to :corporation, touch: true
316
470
  # end
317
471
  #
318
472
  # # triggers @brake.car.touch and @brake.car.corporation.touch
319
473
  # @brake.touch
320
- def touch(name = nil)
474
+ #
475
+ # Note that +touch+ must be used on a persisted object, or else an
476
+ # ActiveRecordError will be thrown. For example:
477
+ #
478
+ # ball = Ball.new
479
+ # ball.touch(:updated_at) # => raises ActiveRecordError
480
+ #
481
+ def touch(*names, time: nil)
482
+ raise ActiveRecordError, "cannot touch on a new record object" unless persisted?
483
+
484
+ time ||= current_time_from_proper_timezone
321
485
  attributes = timestamp_attributes_for_update_in_model
322
- attributes << name if name
486
+ attributes.concat(names)
323
487
 
324
488
  unless attributes.empty?
325
- current_time = current_time_from_proper_timezone
326
489
  changes = {}
327
490
 
328
491
  attributes.each do |column|
329
- changes[column.to_s] = write_attribute(column.to_s, current_time)
492
+ column = column.to_s
493
+ changes[column] = write_attribute(column, time)
330
494
  end
331
495
 
332
- changes[self.class.locking_column] = increment_lock if locking_enabled?
333
-
334
- @changed_attributes.except!(*changes.keys)
496
+ clear_attribute_changes(changes.keys)
335
497
  primary_key = self.class.primary_key
336
- self.class.unscoped.update_all(changes, { primary_key => self[primary_key] }) == 1
498
+ scope = self.class.unscoped.where(primary_key => _read_attribute(primary_key))
499
+
500
+ if locking_enabled?
501
+ locking_column = self.class.locking_column
502
+ scope = scope.where(locking_column => _read_attribute(locking_column))
503
+ changes[locking_column] = increment_lock
504
+ end
505
+
506
+ result = scope.update_all(changes) == 1
507
+
508
+ if !result && locking_enabled?
509
+ raise ActiveRecord::StaleObjectError.new(self, "touch")
510
+ end
511
+
512
+ result
513
+ else
514
+ true
337
515
  end
338
516
  end
339
517
 
@@ -343,34 +521,56 @@ module ActiveRecord
343
521
  def destroy_associations
344
522
  end
345
523
 
346
- def create_or_update
347
- raise ReadOnlyRecord if readonly?
348
- result = new_record? ? create : update
524
+ def destroy_row
525
+ relation_for_destroy.delete_all
526
+ end
527
+
528
+ def relation_for_destroy
529
+ self.class.unscoped.where(self.class.primary_key => id)
530
+ end
531
+
532
+ def create_or_update(*args)
533
+ raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
534
+ result = new_record? ? _create_record : _update_record(*args)
349
535
  result != false
350
536
  end
351
537
 
352
538
  # Updates the associated record with values matching those of the instance attributes.
353
539
  # Returns the number of affected rows.
354
- def update(attribute_names = @attributes.keys)
355
- attributes_with_values = arel_attributes_values(false, false, attribute_names)
356
- return 0 if attributes_with_values.empty?
357
- klass = self.class
358
- stmt = klass.unscoped.where(klass.arel_table[klass.primary_key].eq(id)).arel.compile_update(attributes_with_values)
359
- klass.connection.update stmt
540
+ def _update_record(attribute_names = self.attribute_names)
541
+ attributes_values = arel_attributes_with_values_for_update(attribute_names)
542
+ if attributes_values.empty?
543
+ 0
544
+ else
545
+ self.class.unscoped._update_record attributes_values, id, id_was
546
+ end
360
547
  end
361
548
 
362
549
  # Creates a record with values matching those of the instance attributes
363
550
  # and returns its id.
364
- def create
365
- attributes_values = arel_attributes_values(!id.nil?)
551
+ def _create_record(attribute_names = self.attribute_names)
552
+ attributes_values = arel_attributes_with_values_for_create(attribute_names)
366
553
 
367
554
  new_id = self.class.unscoped.insert attributes_values
368
-
369
555
  self.id ||= new_id if self.class.primary_key
370
556
 
371
- IdentityMap.add(self) if IdentityMap.enabled?
372
557
  @new_record = false
373
558
  id
374
559
  end
560
+
561
+ def verify_readonly_attribute(name)
562
+ raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attributes.include?(name)
563
+ end
564
+
565
+ def _raise_record_not_destroyed
566
+ @_association_destroy_exception ||= nil
567
+ raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy the record", self)
568
+ ensure
569
+ @_association_destroy_exception = nil
570
+ end
571
+
572
+ def belongs_to_touch_method
573
+ :touch
574
+ end
375
575
  end
376
576
  end