activerecord 7.0.0 → 7.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1701 -1039
- data/MIT-LICENSE +1 -1
- data/README.rdoc +18 -18
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/association.rb +18 -3
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +14 -6
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +21 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +17 -12
- data/lib/active_record/associations/collection_proxy.rb +22 -12
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +27 -17
- data/lib/active_record/associations/has_many_through_association.rb +10 -6
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency.rb +20 -14
- data/lib/active_record/associations/preloader/association.rb +27 -6
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/preloader.rb +13 -10
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +362 -236
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/dirty.rb +52 -34
- data/lib/active_record/attribute_methods/primary_key.rb +76 -24
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +18 -5
- data/lib/active_record/attribute_methods/serialization.rb +172 -69
- data/lib/active_record/attribute_methods/write.rb +3 -3
- data/lib/active_record/attribute_methods.rb +110 -28
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +56 -10
- data/lib/active_record/base.rb +10 -5
- data/lib/active_record/callbacks.rb +16 -32
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -34
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +164 -89
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +3 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +63 -43
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +129 -31
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +60 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +52 -8
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +163 -29
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +302 -131
- data/lib/active_record/connection_adapters/abstract/transaction.rb +287 -58
- data/lib/active_record/connection_adapters/abstract_adapter.rb +513 -106
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +217 -104
- data/lib/active_record/connection_adapters/column.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +23 -144
- data/lib/active_record/connection_adapters/mysql/quoting.rb +29 -12
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +38 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +98 -53
- data/lib/active_record/connection_adapters/pool_config.rb +14 -5
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +16 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +75 -45
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +41 -8
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +6 -10
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +131 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +372 -63
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +359 -197
- data/lib/active_record/connection_adapters/schema_cache.rb +287 -59
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +52 -39
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +22 -5
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +41 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +242 -81
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +254 -0
- data/lib/active_record/connection_adapters.rb +3 -1
- data/lib/active_record/connection_handling.rb +73 -96
- data/lib/active_record/core.rb +142 -153
- data/lib/active_record/counter_cache.rb +46 -25
- data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -0
- data/lib/active_record/database_configurations/database_config.rb +9 -3
- data/lib/active_record/database_configurations/hash_config.rb +22 -12
- data/lib/active_record/database_configurations/url_config.rb +17 -11
- data/lib/active_record/database_configurations.rb +87 -34
- data/lib/active_record/delegated_type.rb +9 -4
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +2 -0
- data/lib/active_record/disable_joins_association_relation.rb +1 -1
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
- data/lib/active_record/encryption/config.rb +25 -1
- data/lib/active_record/encryption/configurable.rb +13 -14
- data/lib/active_record/encryption/context.rb +10 -3
- data/lib/active_record/encryption/contexts.rb +8 -4
- data/lib/active_record/encryption/derived_secret_key_provider.rb +9 -3
- data/lib/active_record/encryption/deterministic_key_provider.rb +1 -1
- data/lib/active_record/encryption/encryptable_record.rb +38 -22
- data/lib/active_record/encryption/encrypted_attribute_type.rb +19 -8
- data/lib/active_record/encryption/encryptor.rb +7 -7
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +3 -3
- data/lib/active_record/encryption/extended_deterministic_queries.rb +83 -86
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +3 -3
- data/lib/active_record/encryption/key_generator.rb +12 -1
- data/lib/active_record/encryption/message.rb +1 -1
- data/lib/active_record/encryption/message_serializer.rb +2 -0
- data/lib/active_record/encryption/properties.rb +4 -4
- data/lib/active_record/encryption/scheme.rb +20 -23
- data/lib/active_record/encryption.rb +1 -0
- data/lib/active_record/enum.rb +113 -29
- data/lib/active_record/errors.rb +108 -15
- data/lib/active_record/explain.rb +23 -3
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +29 -8
- data/lib/active_record/fixtures.rb +121 -73
- data/lib/active_record/future_result.rb +30 -5
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +30 -16
- data/lib/active_record/insert_all.rb +57 -10
- data/lib/active_record/integration.rb +10 -10
- data/lib/active_record/internal_metadata.rb +120 -30
- data/lib/active_record/locking/optimistic.rb +32 -18
- data/lib/active_record/locking/pessimistic.rb +8 -5
- data/lib/active_record/log_subscriber.rb +39 -17
- data/lib/active_record/marshalling.rb +56 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
- data/lib/active_record/middleware/database_selector.rb +18 -13
- data/lib/active_record/middleware/shard_selector.rb +7 -5
- data/lib/active_record/migration/command_recorder.rb +108 -10
- data/lib/active_record/migration/compatibility.rb +158 -64
- data/lib/active_record/migration/default_strategy.rb +23 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +274 -117
- data/lib/active_record/model_schema.rb +86 -54
- data/lib/active_record/nested_attributes.rb +24 -6
- data/lib/active_record/normalization.rb +167 -0
- data/lib/active_record/persistence.rb +200 -47
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +3 -21
- data/lib/active_record/query_logs.rb +87 -51
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +16 -3
- data/lib/active_record/railtie.rb +128 -62
- data/lib/active_record/railties/controller_runtime.rb +12 -8
- data/lib/active_record/railties/databases.rake +145 -146
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +32 -5
- data/lib/active_record/reflection.rb +189 -45
- data/lib/active_record/relation/batches/batch_enumerator.rb +5 -3
- data/lib/active_record/relation/batches.rb +190 -61
- data/lib/active_record/relation/calculations.rb +208 -83
- data/lib/active_record/relation/delegation.rb +23 -9
- data/lib/active_record/relation/finder_methods.rb +77 -16
- data/lib/active_record/relation/merger.rb +2 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +26 -14
- data/lib/active_record/relation/query_attribute.rb +25 -1
- data/lib/active_record/relation/query_methods.rb +430 -77
- data/lib/active_record/relation/spawn_methods.rb +18 -1
- data/lib/active_record/relation.rb +98 -41
- data/lib/active_record/result.rb +25 -9
- data/lib/active_record/runtime_registry.rb +10 -1
- data/lib/active_record/sanitization.rb +57 -16
- data/lib/active_record/schema.rb +36 -22
- data/lib/active_record/schema_dumper.rb +65 -23
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +20 -12
- data/lib/active_record/scoping/named.rb +2 -2
- data/lib/active_record/scoping.rb +2 -1
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/serialization.rb +5 -0
- data/lib/active_record/signed_id.rb +9 -7
- data/lib/active_record/store.rb +16 -11
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +16 -3
- data/lib/active_record/tasks/database_tasks.rb +138 -107
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +17 -15
- data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
- data/lib/active_record/test_fixtures.rb +123 -99
- data/lib/active_record/timestamp.rb +27 -15
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +39 -13
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +8 -4
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +3 -3
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +50 -5
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +143 -16
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +1 -1
- data/lib/arel/nodes/and.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -1
- data/lib/arel/nodes/bound_sql_literal.rb +61 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/filter.rb +1 -1
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/node.rb +111 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes.rb +4 -0
- data/lib/arel/predications.rb +2 -0
- data/lib/arel/table.rb +9 -5
- data/lib/arel/visitors/mysql.rb +8 -1
- data/lib/arel/visitors/to_sql.rb +81 -17
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +16 -2
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- metadata +51 -15
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
@@ -52,6 +52,23 @@ module ActiveRecord
|
|
52
52
|
attribute_before_type_cast(name)
|
53
53
|
end
|
54
54
|
|
55
|
+
# Returns the value of the attribute identified by +attr_name+ after
|
56
|
+
# serialization.
|
57
|
+
#
|
58
|
+
# class Book < ActiveRecord::Base
|
59
|
+
# enum status: { draft: 1, published: 2 }
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# book = Book.new(status: "published")
|
63
|
+
# book.read_attribute(:status) # => "published"
|
64
|
+
# book.read_attribute_for_database(:status) # => 2
|
65
|
+
def read_attribute_for_database(attr_name)
|
66
|
+
name = attr_name.to_s
|
67
|
+
name = self.class.attribute_aliases[name] || name
|
68
|
+
|
69
|
+
attribute_for_database(name)
|
70
|
+
end
|
71
|
+
|
55
72
|
# Returns a hash of attributes before typecasting and deserialization.
|
56
73
|
#
|
57
74
|
# class Task < ActiveRecord::Base
|
@@ -4,6 +4,38 @@ require "active_support/core_ext/module/attribute_accessors"
|
|
4
4
|
|
5
5
|
module ActiveRecord
|
6
6
|
module AttributeMethods
|
7
|
+
# = Active Record Attribute Methods \Dirty
|
8
|
+
#
|
9
|
+
# Provides a way to track changes in your Active Record models. It adds all
|
10
|
+
# methods from ActiveModel::Dirty and adds database-specific methods.
|
11
|
+
#
|
12
|
+
# A newly created +Person+ object is unchanged:
|
13
|
+
#
|
14
|
+
# class Person < ActiveRecord::Base
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# person = Person.create(name: "Alisson")
|
18
|
+
# person.changed? # => false
|
19
|
+
#
|
20
|
+
# Change the name:
|
21
|
+
#
|
22
|
+
# person.name = 'Alice'
|
23
|
+
# person.name_in_database # => "Allison"
|
24
|
+
# person.will_save_change_to_name? # => true
|
25
|
+
# person.name_change_to_be_saved # => ["Allison", "Alice"]
|
26
|
+
# person.changes_to_save # => {"name"=>["Allison", "Alice"]}
|
27
|
+
#
|
28
|
+
# Save the changes:
|
29
|
+
#
|
30
|
+
# person.save
|
31
|
+
# person.name_in_database # => "Alice"
|
32
|
+
# person.saved_change_to_name? # => true
|
33
|
+
# person.saved_change_to_name # => ["Allison", "Alice"]
|
34
|
+
# person.name_before_last_change # => "Allison"
|
35
|
+
#
|
36
|
+
# Similar to ActiveModel::Dirty, methods can be invoked as
|
37
|
+
# +saved_change_to_name?+ or by passing an argument to the generic method
|
38
|
+
# <tt>saved_change_to_attribute?("name")</tt>.
|
7
39
|
module Dirty
|
8
40
|
extend ActiveSupport::Concern
|
9
41
|
|
@@ -27,32 +59,6 @@ module ActiveRecord
|
|
27
59
|
attribute_method_suffix("_change_to_be_saved", "_in_database", parameters: false)
|
28
60
|
end
|
29
61
|
|
30
|
-
module ClassMethods
|
31
|
-
def partial_writes
|
32
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
33
|
-
ActiveRecord::Base.partial_writes is deprecated and will be removed in Rails 7.1.
|
34
|
-
Use `partial_updates` and `partial_inserts` instead.
|
35
|
-
MSG
|
36
|
-
partial_updates && partial_inserts
|
37
|
-
end
|
38
|
-
|
39
|
-
def partial_writes?
|
40
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
41
|
-
`ActiveRecord::Base.partial_writes?` is deprecated and will be removed in Rails 7.1.
|
42
|
-
Use `partial_updates?` and `partial_inserts?` instead.
|
43
|
-
MSG
|
44
|
-
partial_updates? && partial_inserts?
|
45
|
-
end
|
46
|
-
|
47
|
-
def partial_writes=(value)
|
48
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
49
|
-
`ActiveRecord::Base.partial_writes=` is deprecated and will be removed in Rails 7.1.
|
50
|
-
Use `partial_updates=` and `partial_inserts=` instead.
|
51
|
-
MSG
|
52
|
-
self.partial_updates = self.partial_inserts = value
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
62
|
# <tt>reload</tt> the record and clears changed attributes.
|
57
63
|
def reload(*)
|
58
64
|
super.tap do
|
@@ -70,11 +76,13 @@ module ActiveRecord
|
|
70
76
|
#
|
71
77
|
# ==== Options
|
72
78
|
#
|
73
|
-
# +from+
|
74
|
-
#
|
79
|
+
# [+from+]
|
80
|
+
# When specified, this method will return false unless the original
|
81
|
+
# value is equal to the given value.
|
75
82
|
#
|
76
|
-
# +to+
|
77
|
-
#
|
83
|
+
# [+to+]
|
84
|
+
# When specified, this method will return false unless the value will be
|
85
|
+
# changed to the given value.
|
78
86
|
def saved_change_to_attribute?(attr_name, **options)
|
79
87
|
mutations_before_last_save.changed?(attr_name.to_s, **options)
|
80
88
|
end
|
@@ -120,11 +128,13 @@ module ActiveRecord
|
|
120
128
|
#
|
121
129
|
# ==== Options
|
122
130
|
#
|
123
|
-
# +from+
|
124
|
-
#
|
131
|
+
# [+from+]
|
132
|
+
# When specified, this method will return false unless the original
|
133
|
+
# value is equal to the given value.
|
125
134
|
#
|
126
|
-
# +to+
|
127
|
-
#
|
135
|
+
# [+to+]
|
136
|
+
# When specified, this method will return false unless the value will be
|
137
|
+
# changed to the given value.
|
128
138
|
def will_save_change_to_attribute?(attr_name, **options)
|
129
139
|
mutations_from_database.changed?(attr_name.to_s, **options)
|
130
140
|
end
|
@@ -183,6 +193,14 @@ module ActiveRecord
|
|
183
193
|
end
|
184
194
|
|
185
195
|
private
|
196
|
+
def init_internals
|
197
|
+
super
|
198
|
+
@mutations_before_last_save = nil
|
199
|
+
@mutations_from_database = nil
|
200
|
+
@_touch_attr_names = nil
|
201
|
+
@_skip_dirty_tracking = nil
|
202
|
+
end
|
203
|
+
|
186
204
|
def _touch_row(attribute_names, time)
|
187
205
|
@_touch_attr_names = Set.new(attribute_names)
|
188
206
|
|
@@ -4,6 +4,7 @@ require "set"
|
|
4
4
|
|
5
5
|
module ActiveRecord
|
6
6
|
module AttributeMethods
|
7
|
+
# = Active Record Attribute Methods Primary Key
|
7
8
|
module PrimaryKey
|
8
9
|
extend ActiveSupport::Concern
|
9
10
|
|
@@ -11,41 +12,80 @@ module ActiveRecord
|
|
11
12
|
# available.
|
12
13
|
def to_key
|
13
14
|
key = id
|
14
|
-
|
15
|
+
Array(key) if key
|
15
16
|
end
|
16
17
|
|
17
|
-
# Returns the primary key column's value.
|
18
|
+
# Returns the primary key column's value. If the primary key is composite,
|
19
|
+
# returns an array of the primary key column values.
|
18
20
|
def id
|
19
|
-
_read_attribute(@primary_key)
|
21
|
+
return _read_attribute(@primary_key) unless @primary_key.is_a?(Array)
|
22
|
+
|
23
|
+
@primary_key.map { |pk| _read_attribute(pk) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def primary_key_values_present? # :nodoc:
|
27
|
+
return id.all? if self.class.composite_primary_key?
|
28
|
+
|
29
|
+
!!id
|
20
30
|
end
|
21
31
|
|
22
|
-
# Sets the primary key column's value.
|
32
|
+
# Sets the primary key column's value. If the primary key is composite,
|
33
|
+
# raises TypeError when the set value not enumerable.
|
23
34
|
def id=(value)
|
24
|
-
|
35
|
+
if self.class.composite_primary_key?
|
36
|
+
raise TypeError, "Expected value matching #{self.class.primary_key.inspect}, got #{value.inspect}." unless value.is_a?(Enumerable)
|
37
|
+
@primary_key.zip(value) { |attr, value| _write_attribute(attr, value) }
|
38
|
+
else
|
39
|
+
_write_attribute(@primary_key, value)
|
40
|
+
end
|
25
41
|
end
|
26
42
|
|
27
|
-
# Queries the primary key column's value.
|
43
|
+
# Queries the primary key column's value. If the primary key is composite,
|
44
|
+
# all primary key column values must be queryable.
|
28
45
|
def id?
|
29
|
-
|
46
|
+
if self.class.composite_primary_key?
|
47
|
+
@primary_key.all? { |col| _query_attribute(col) }
|
48
|
+
else
|
49
|
+
_query_attribute(@primary_key)
|
50
|
+
end
|
30
51
|
end
|
31
52
|
|
32
|
-
# Returns the primary key column's value before type cast.
|
53
|
+
# Returns the primary key column's value before type cast. If the primary key is composite,
|
54
|
+
# returns an array of primary key column values before type cast.
|
33
55
|
def id_before_type_cast
|
34
|
-
|
56
|
+
if self.class.composite_primary_key?
|
57
|
+
@primary_key.map { |col| attribute_before_type_cast(col) }
|
58
|
+
else
|
59
|
+
attribute_before_type_cast(@primary_key)
|
60
|
+
end
|
35
61
|
end
|
36
62
|
|
37
|
-
# Returns the primary key column's previous value.
|
63
|
+
# Returns the primary key column's previous value. If the primary key is composite,
|
64
|
+
# returns an array of primary key column previous values.
|
38
65
|
def id_was
|
39
|
-
|
66
|
+
if self.class.composite_primary_key?
|
67
|
+
@primary_key.map { |col| attribute_was(col) }
|
68
|
+
else
|
69
|
+
attribute_was(@primary_key)
|
70
|
+
end
|
40
71
|
end
|
41
72
|
|
42
|
-
# Returns the primary key column's value from the database.
|
73
|
+
# Returns the primary key column's value from the database. If the primary key is composite,
|
74
|
+
# returns an array of primary key column values from database.
|
43
75
|
def id_in_database
|
44
|
-
|
76
|
+
if self.class.composite_primary_key?
|
77
|
+
@primary_key.map { |col| attribute_in_database(col) }
|
78
|
+
else
|
79
|
+
attribute_in_database(@primary_key)
|
80
|
+
end
|
45
81
|
end
|
46
82
|
|
47
83
|
def id_for_database # :nodoc:
|
48
|
-
|
84
|
+
if self.class.composite_primary_key?
|
85
|
+
@primary_key.map { |col| @attributes[col].value_for_database }
|
86
|
+
else
|
87
|
+
@attributes[@primary_key].value_for_database
|
88
|
+
end
|
49
89
|
end
|
50
90
|
|
51
91
|
private
|
@@ -55,6 +95,7 @@ module ActiveRecord
|
|
55
95
|
|
56
96
|
module ClassMethods
|
57
97
|
ID_ATTRIBUTE_METHODS = %w(id id= id? id_before_type_cast id_was id_in_database id_for_database).to_set
|
98
|
+
PRIMARY_KEY_NOT_SET = BasicObject.new
|
58
99
|
|
59
100
|
def instance_method_already_implemented?(method_name)
|
60
101
|
super || primary_key && ID_ATTRIBUTE_METHODS.include?(method_name)
|
@@ -68,10 +109,16 @@ module ActiveRecord
|
|
68
109
|
# Overwriting will negate any effect of the +primary_key_prefix_type+
|
69
110
|
# setting, though.
|
70
111
|
def primary_key
|
71
|
-
|
112
|
+
if PRIMARY_KEY_NOT_SET.equal?(@primary_key)
|
113
|
+
@primary_key = reset_primary_key
|
114
|
+
end
|
72
115
|
@primary_key
|
73
116
|
end
|
74
117
|
|
118
|
+
def composite_primary_key? # :nodoc:
|
119
|
+
primary_key.is_a?(Array)
|
120
|
+
end
|
121
|
+
|
75
122
|
# Returns a quoted version of the primary key name, used to construct
|
76
123
|
# SQL statements.
|
77
124
|
def quoted_primary_key
|
@@ -93,8 +140,7 @@ module ActiveRecord
|
|
93
140
|
base_name.foreign_key
|
94
141
|
else
|
95
142
|
if ActiveRecord::Base != self && table_exists?
|
96
|
-
|
97
|
-
suppress_composite_primary_key(pk)
|
143
|
+
connection.schema_cache.primary_keys(table_name)
|
98
144
|
else
|
99
145
|
"id"
|
100
146
|
end
|
@@ -117,20 +163,26 @@ module ActiveRecord
|
|
117
163
|
#
|
118
164
|
# Project.primary_key # => "foo_id"
|
119
165
|
def primary_key=(value)
|
120
|
-
@primary_key = value
|
166
|
+
@primary_key = derive_primary_key(value)
|
121
167
|
@quoted_primary_key = nil
|
122
168
|
@attributes_builder = nil
|
123
169
|
end
|
124
170
|
|
125
171
|
private
|
126
|
-
def
|
127
|
-
return
|
172
|
+
def derive_primary_key(value)
|
173
|
+
return unless value
|
174
|
+
|
175
|
+
return -value.to_s unless value.is_a?(Array)
|
128
176
|
|
129
|
-
|
130
|
-
|
177
|
+
value.map { |v| -v.to_s }.freeze
|
178
|
+
end
|
131
179
|
|
132
|
-
|
133
|
-
|
180
|
+
def inherited(base)
|
181
|
+
super
|
182
|
+
base.class_eval do
|
183
|
+
@primary_key = PRIMARY_KEY_NOT_SET
|
184
|
+
@quoted_primary_key = nil
|
185
|
+
end
|
134
186
|
end
|
135
187
|
end
|
136
188
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
module AttributeMethods
|
5
|
+
# = Active Record Attribute Methods \Query
|
5
6
|
module Query
|
6
7
|
extend ActiveSupport::Concern
|
7
8
|
|
@@ -12,27 +13,38 @@ module ActiveRecord
|
|
12
13
|
def query_attribute(attr_name)
|
13
14
|
value = self.public_send(attr_name)
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
16
|
+
query_cast_attribute(attr_name, value)
|
17
|
+
end
|
18
|
+
|
19
|
+
def _query_attribute(attr_name) # :nodoc:
|
20
|
+
value = self._read_attribute(attr_name.to_s)
|
21
|
+
|
22
|
+
query_cast_attribute(attr_name, value)
|
23
|
+
end
|
24
|
+
|
25
|
+
alias :attribute? :query_attribute
|
26
|
+
private :attribute?
|
27
|
+
|
28
|
+
private
|
29
|
+
def query_cast_attribute(attr_name, value)
|
30
|
+
case value
|
31
|
+
when true then true
|
32
|
+
when false, nil then false
|
33
|
+
else
|
34
|
+
if !type_for_attribute(attr_name) { false }
|
35
|
+
if Numeric === value || !value.match?(/[^0-9]/)
|
36
|
+
!value.to_i.zero?
|
37
|
+
else
|
38
|
+
return false if ActiveModel::Type::Boolean::FALSE_VALUES.include?(value)
|
39
|
+
!value.blank?
|
40
|
+
end
|
41
|
+
elsif value.respond_to?(:zero?)
|
42
|
+
!value.zero?
|
22
43
|
else
|
23
|
-
return false if ActiveModel::Type::Boolean::FALSE_VALUES.include?(value)
|
24
44
|
!value.blank?
|
25
45
|
end
|
26
|
-
elsif value.respond_to?(:zero?)
|
27
|
-
!value.zero?
|
28
|
-
else
|
29
|
-
!value.blank?
|
30
46
|
end
|
31
47
|
end
|
32
|
-
end
|
33
|
-
|
34
|
-
alias :attribute? :query_attribute
|
35
|
-
private :attribute?
|
36
48
|
end
|
37
49
|
end
|
38
50
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
module AttributeMethods
|
5
|
+
# = Active Record Attribute Methods \Read
|
5
6
|
module Read
|
6
7
|
extend ActiveSupport::Concern
|
7
8
|
|
@@ -21,15 +22,27 @@ module ActiveRecord
|
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
24
|
-
# Returns the value of the attribute identified by
|
25
|
-
#
|
26
|
-
# to
|
25
|
+
# Returns the value of the attribute identified by +attr_name+ after it
|
26
|
+
# has been type cast. For example, a date attribute will cast "2004-12-12"
|
27
|
+
# to <tt>Date.new(2004, 12, 12)</tt>. (For information about specific type
|
28
|
+
# casting behavior, see the types under ActiveModel::Type.)
|
27
29
|
def read_attribute(attr_name, &block)
|
28
30
|
name = attr_name.to_s
|
29
31
|
name = self.class.attribute_aliases[name] || name
|
30
32
|
|
31
|
-
name
|
32
|
-
|
33
|
+
return @attributes.fetch_value(name, &block) unless name == "id" && @primary_key
|
34
|
+
|
35
|
+
if self.class.composite_primary_key?
|
36
|
+
@attributes.fetch_value("id", &block)
|
37
|
+
else
|
38
|
+
if @primary_key != "id"
|
39
|
+
ActiveRecord.deprecator.warn(<<-MSG.squish)
|
40
|
+
Using read_attribute(:id) to read the primary key value is deprecated.
|
41
|
+
Use #id instead.
|
42
|
+
MSG
|
43
|
+
end
|
44
|
+
@attributes.fetch_value(@primary_key, &block)
|
45
|
+
end
|
33
46
|
end
|
34
47
|
|
35
48
|
# This method exists to avoid the expensive primary_key check internally, without
|