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