activerecord 7.0.0 → 7.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +357 -0
- data/MIT-LICENSE +1 -1
- data/lib/active_record/associations/collection_association.rb +1 -2
- data/lib/active_record/associations/collection_proxy.rb +2 -2
- data/lib/active_record/associations/has_many_association.rb +7 -4
- data/lib/active_record/associations/join_dependency.rb +17 -13
- data/lib/active_record/associations.rb +38 -17
- data/lib/active_record/attribute_methods/serialization.rb +34 -50
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -0
- data/lib/active_record/attribute_methods.rb +2 -2
- data/lib/active_record/autosave_association.rb +2 -2
- data/lib/active_record/base.rb +3 -3
- data/lib/active_record/coders/yaml_column.rb +10 -2
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +8 -4
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +12 -7
- data/lib/active_record/connection_adapters/abstract_adapter.rb +5 -5
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +10 -2
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +3 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +10 -3
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +6 -5
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +14 -14
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +35 -2
- data/lib/active_record/connection_handling.rb +2 -2
- data/lib/active_record/core.rb +3 -3
- data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -0
- data/lib/active_record/database_configurations.rb +1 -1
- data/lib/active_record/delegated_type.rb +1 -1
- data/lib/active_record/encryption/configurable.rb +9 -3
- data/lib/active_record/encryption/contexts.rb +3 -3
- data/lib/active_record/encryption/derived_secret_key_provider.rb +1 -1
- data/lib/active_record/encryption/deterministic_key_provider.rb +1 -1
- data/lib/active_record/encryption/encryptable_record.rb +2 -4
- data/lib/active_record/encryption/encrypted_attribute_type.rb +2 -2
- 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 +28 -28
- data/lib/active_record/encryption/message.rb +1 -1
- data/lib/active_record/encryption/properties.rb +1 -1
- data/lib/active_record/encryption/scheme.rb +1 -1
- data/lib/active_record/enum.rb +1 -1
- data/lib/active_record/fixtures.rb +5 -5
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/integration.rb +2 -2
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +10 -5
- data/lib/active_record/middleware/database_selector.rb +13 -6
- data/lib/active_record/middleware/shard_selector.rb +4 -4
- data/lib/active_record/migration/command_recorder.rb +3 -3
- data/lib/active_record/migration/compatibility.rb +10 -7
- data/lib/active_record/migration.rb +6 -5
- data/lib/active_record/model_schema.rb +22 -10
- data/lib/active_record/persistence.rb +9 -8
- data/lib/active_record/querying.rb +1 -1
- data/lib/active_record/railtie.rb +22 -18
- data/lib/active_record/railties/databases.rake +16 -11
- data/lib/active_record/reflection.rb +7 -1
- data/lib/active_record/relation/batches.rb +3 -3
- data/lib/active_record/relation/calculations.rb +3 -2
- data/lib/active_record/relation/delegation.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +46 -11
- data/lib/active_record/relation.rb +22 -6
- data/lib/active_record/sanitization.rb +6 -5
- data/lib/active_record/schema.rb +38 -23
- data/lib/active_record/schema_dumper.rb +15 -16
- data/lib/active_record/scoping/default.rb +5 -7
- data/lib/active_record/serialization.rb +5 -0
- data/lib/active_record/signed_id.rb +2 -2
- data/lib/active_record/store.rb +7 -2
- data/lib/active_record/tasks/database_tasks.rb +32 -23
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -2
- data/lib/active_record/test_fixtures.rb +12 -5
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/validations/associated.rb +3 -3
- data/lib/active_record/validations/presence.rb +2 -2
- data/lib/active_record/validations/uniqueness.rb +3 -3
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +15 -1
- metadata +13 -13
|
@@ -10,10 +10,10 @@ module ActiveRecord
|
|
|
10
10
|
module QueryMethods
|
|
11
11
|
include ActiveModel::ForbiddenAttributesProtection
|
|
12
12
|
|
|
13
|
-
# WhereChain objects act as placeholder for queries in which
|
|
14
|
-
# In this case,
|
|
13
|
+
# WhereChain objects act as placeholder for queries in which +where+ does not have any parameter.
|
|
14
|
+
# In this case, +where+ can be chained to return a new relation.
|
|
15
15
|
class WhereChain
|
|
16
|
-
def initialize(scope)
|
|
16
|
+
def initialize(scope) # :nodoc:
|
|
17
17
|
@scope = scope
|
|
18
18
|
end
|
|
19
19
|
|
|
@@ -40,6 +40,13 @@ module ActiveRecord
|
|
|
40
40
|
#
|
|
41
41
|
# User.where.not(name: "Jon", role: "admin")
|
|
42
42
|
# # SELECT * FROM users WHERE NOT (name == 'Jon' AND role == 'admin')
|
|
43
|
+
#
|
|
44
|
+
# If there is a non-nil condition on a nullable column in the hash condition, the records that have
|
|
45
|
+
# nil values on the nullable column won't be returned.
|
|
46
|
+
# User.create!(nullable_country: nil)
|
|
47
|
+
# User.where.not(nullable_country: "UK")
|
|
48
|
+
# # SELECT * FROM users WHERE NOT (nullable_country = 'UK')
|
|
49
|
+
# # => []
|
|
43
50
|
def not(opts, *rest)
|
|
44
51
|
where_clause = @scope.send(:build_where_clause, opts, rest)
|
|
45
52
|
|
|
@@ -68,7 +75,7 @@ module ActiveRecord
|
|
|
68
75
|
# # WHERE "authors"."id" IS NOT NULL AND "comments"."id" IS NOT NULL
|
|
69
76
|
def associated(*associations)
|
|
70
77
|
associations.each do |association|
|
|
71
|
-
reflection =
|
|
78
|
+
reflection = scope_association_reflection(association)
|
|
72
79
|
@scope.joins!(association)
|
|
73
80
|
self.not(reflection.table_name => { reflection.association_primary_key => nil })
|
|
74
81
|
end
|
|
@@ -96,13 +103,22 @@ module ActiveRecord
|
|
|
96
103
|
# # WHERE "authors"."id" IS NULL AND "comments"."id" IS NULL
|
|
97
104
|
def missing(*associations)
|
|
98
105
|
associations.each do |association|
|
|
99
|
-
reflection =
|
|
106
|
+
reflection = scope_association_reflection(association)
|
|
100
107
|
@scope.left_outer_joins!(association)
|
|
101
108
|
@scope.where!(reflection.table_name => { reflection.association_primary_key => nil })
|
|
102
109
|
end
|
|
103
110
|
|
|
104
111
|
@scope
|
|
105
112
|
end
|
|
113
|
+
|
|
114
|
+
private
|
|
115
|
+
def scope_association_reflection(association)
|
|
116
|
+
reflection = @scope.klass._reflect_on_association(association)
|
|
117
|
+
unless reflection
|
|
118
|
+
raise ArgumentError.new("An association named `:#{association}` does not exist on the model `#{@scope.name}`.")
|
|
119
|
+
end
|
|
120
|
+
reflection
|
|
121
|
+
end
|
|
106
122
|
end
|
|
107
123
|
|
|
108
124
|
FROZEN_EMPTY_ARRAY = [].freeze
|
|
@@ -153,7 +169,7 @@ module ActiveRecord
|
|
|
153
169
|
#
|
|
154
170
|
# users = User.includes(:address, friends: [:address, :followers])
|
|
155
171
|
#
|
|
156
|
-
# ===
|
|
172
|
+
# === Conditions
|
|
157
173
|
#
|
|
158
174
|
# If you want to add string conditions to your included models, you'll have
|
|
159
175
|
# to explicitly reference them. For example:
|
|
@@ -424,18 +440,23 @@ module ActiveRecord
|
|
|
424
440
|
# adapter this will either use a CASE statement or a built-in function.
|
|
425
441
|
#
|
|
426
442
|
# User.in_order_of(:id, [1, 5, 3])
|
|
427
|
-
# # SELECT "users".* FROM "users"
|
|
443
|
+
# # SELECT "users".* FROM "users"
|
|
444
|
+
# # ORDER BY FIELD("users"."id", 1, 5, 3)
|
|
445
|
+
# # WHERE "users"."id" IN (1, 5, 3)
|
|
428
446
|
#
|
|
429
447
|
def in_order_of(column, values)
|
|
430
448
|
klass.disallow_raw_sql!([column], permit: connection.column_name_with_order_matcher)
|
|
449
|
+
return spawn.none! if values.empty?
|
|
431
450
|
|
|
432
451
|
references = column_references([column])
|
|
433
452
|
self.references_values |= references unless references.empty?
|
|
434
453
|
|
|
435
454
|
values = values.map { |value| type_caster.type_cast_for_database(column, value) }
|
|
436
|
-
|
|
455
|
+
arel_column = column.is_a?(Symbol) ? order_column(column.to_s) : column
|
|
437
456
|
|
|
438
|
-
spawn
|
|
457
|
+
spawn
|
|
458
|
+
.order!(connection.field_ordered_value(arel_column, values))
|
|
459
|
+
.where!(arel_column.in(values))
|
|
439
460
|
end
|
|
440
461
|
|
|
441
462
|
# Replaces any existing order defined on the relation with the specified order.
|
|
@@ -696,12 +717,26 @@ module ActiveRecord
|
|
|
696
717
|
# === no argument
|
|
697
718
|
#
|
|
698
719
|
# If no argument is passed, #where returns a new instance of WhereChain, that
|
|
699
|
-
# can be chained with #not
|
|
720
|
+
# can be chained with WhereChain#not, WhereChain#missing, or WhereChain#associated.
|
|
721
|
+
#
|
|
722
|
+
# Chaining with WhereChain#not:
|
|
700
723
|
#
|
|
701
724
|
# User.where.not(name: "Jon")
|
|
702
725
|
# # SELECT * FROM users WHERE name != 'Jon'
|
|
703
726
|
#
|
|
704
|
-
#
|
|
727
|
+
# Chaining with WhereChain#associated:
|
|
728
|
+
#
|
|
729
|
+
# Post.where.associated(:author)
|
|
730
|
+
# # SELECT "posts".* FROM "posts"
|
|
731
|
+
# # INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
|
732
|
+
# # WHERE "authors"."id" IS NOT NULL
|
|
733
|
+
#
|
|
734
|
+
# Chaining with WhereChain#missing:
|
|
735
|
+
#
|
|
736
|
+
# Post.where.missing(:author)
|
|
737
|
+
# # SELECT "posts".* FROM "posts"
|
|
738
|
+
# # LEFT OUTER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
|
739
|
+
# # WHERE "authors"."id" IS NULL
|
|
705
740
|
#
|
|
706
741
|
# === blank condition
|
|
707
742
|
#
|
|
@@ -388,7 +388,7 @@ module ActiveRecord
|
|
|
388
388
|
end
|
|
389
389
|
|
|
390
390
|
if timestamp
|
|
391
|
-
"#{size}-#{timestamp.utc.
|
|
391
|
+
"#{size}-#{timestamp.utc.to_fs(cache_timestamp_format)}"
|
|
392
392
|
else
|
|
393
393
|
"#{size}"
|
|
394
394
|
end
|
|
@@ -429,10 +429,10 @@ module ActiveRecord
|
|
|
429
429
|
end
|
|
430
430
|
end
|
|
431
431
|
|
|
432
|
-
def _exec_scope(
|
|
432
|
+
def _exec_scope(...) # :nodoc:
|
|
433
433
|
@delegate_to_klass = true
|
|
434
434
|
registry = klass.scope_registry
|
|
435
|
-
_scoping(nil, registry) { instance_exec(
|
|
435
|
+
_scoping(nil, registry) { instance_exec(...) || self }
|
|
436
436
|
ensure
|
|
437
437
|
@delegate_to_klass = false
|
|
438
438
|
end
|
|
@@ -646,6 +646,21 @@ module ActiveRecord
|
|
|
646
646
|
# Schedule the query to be performed from a background thread pool.
|
|
647
647
|
#
|
|
648
648
|
# Post.where(published: true).load_async # => #<ActiveRecord::Relation>
|
|
649
|
+
#
|
|
650
|
+
# When the +Relation+ is iterated, if the background query wasn't executed yet,
|
|
651
|
+
# it will be performed by the foreground thread.
|
|
652
|
+
#
|
|
653
|
+
# Note that {config.active_record.async_query_executor}[https://guides.rubyonrails.org/configuring.html#config-active-record-async-query-executor] must be configured
|
|
654
|
+
# for queries to actually be executed concurrently. Otherwise it defaults to
|
|
655
|
+
# executing them in the foreground.
|
|
656
|
+
#
|
|
657
|
+
# +load_async+ will also fall back to executing in the foreground in the test environment when transactional
|
|
658
|
+
# fixtures are enabled.
|
|
659
|
+
#
|
|
660
|
+
# If the query was actually executed in the background, the Active Record logs will show
|
|
661
|
+
# it by prefixing the log line with <tt>ASYNC</tt>:
|
|
662
|
+
#
|
|
663
|
+
# ASYNC Post Load (0.0ms) (db time 2ms) SELECT "posts".* FROM "posts" LIMIT 100
|
|
649
664
|
def load_async
|
|
650
665
|
return load if !connection.async_enabled?
|
|
651
666
|
|
|
@@ -697,6 +712,7 @@ module ActiveRecord
|
|
|
697
712
|
@to_sql = @arel = @loaded = @should_eager_load = nil
|
|
698
713
|
@offsets = @take = nil
|
|
699
714
|
@cache_keys = nil
|
|
715
|
+
@cache_versions = nil
|
|
700
716
|
@records = nil
|
|
701
717
|
self
|
|
702
718
|
end
|
|
@@ -721,7 +737,7 @@ module ActiveRecord
|
|
|
721
737
|
#
|
|
722
738
|
# User.where(name: 'Oscar').where_values_hash
|
|
723
739
|
# # => {name: "Oscar"}
|
|
724
|
-
def where_values_hash(relation_table_name = klass.table_name)
|
|
740
|
+
def where_values_hash(relation_table_name = klass.table_name) # :nodoc:
|
|
725
741
|
where_clause.to_h(relation_table_name)
|
|
726
742
|
end
|
|
727
743
|
|
|
@@ -741,7 +757,7 @@ module ActiveRecord
|
|
|
741
757
|
# Joins that are also marked for preloading. In which case we should just eager load them.
|
|
742
758
|
# Note that this is a naive implementation because we could have strings and symbols which
|
|
743
759
|
# represent the same association, but that aren't matched by this. Also, we could have
|
|
744
|
-
# nested hashes which partially match, e.g. { a: :b } & { a: [:b, :c] }
|
|
760
|
+
# nested hashes which partially match, e.g. <tt>{ a: :b } & { a: [:b, :c] }</tt>
|
|
745
761
|
def joined_includes_values
|
|
746
762
|
includes_values & joins_values
|
|
747
763
|
end
|
|
@@ -902,7 +918,7 @@ module ActiveRecord
|
|
|
902
918
|
preload_associations(records) unless skip_preloading_value
|
|
903
919
|
|
|
904
920
|
records.each(&:readonly!) if readonly_value
|
|
905
|
-
records.each
|
|
921
|
+
records.each { |record| record.strict_loading!(strict_loading_value) } unless strict_loading_value.nil?
|
|
906
922
|
|
|
907
923
|
records
|
|
908
924
|
end
|
|
@@ -92,16 +92,17 @@ module ActiveRecord
|
|
|
92
92
|
end
|
|
93
93
|
|
|
94
94
|
# Sanitizes a +string+ so that it is safe to use within an SQL
|
|
95
|
-
# LIKE statement. This method uses +escape_character+ to escape all
|
|
95
|
+
# LIKE statement. This method uses +escape_character+ to escape all
|
|
96
|
+
# occurrences of itself, "_" and "%".
|
|
96
97
|
#
|
|
97
|
-
# sanitize_sql_like("100%")
|
|
98
|
-
# # => "100\\%"
|
|
98
|
+
# sanitize_sql_like("100% true!")
|
|
99
|
+
# # => "100\\% true!"
|
|
99
100
|
#
|
|
100
101
|
# sanitize_sql_like("snake_cased_string")
|
|
101
102
|
# # => "snake\\_cased\\_string"
|
|
102
103
|
#
|
|
103
|
-
# sanitize_sql_like("100%", "!")
|
|
104
|
-
# # => "100!%"
|
|
104
|
+
# sanitize_sql_like("100% true!", "!")
|
|
105
|
+
# # => "100!% true!!"
|
|
105
106
|
#
|
|
106
107
|
# sanitize_sql_like("snake_cased_string", "!")
|
|
107
108
|
# # => "snake!_cased!_string"
|
data/lib/active_record/schema.rb
CHANGED
|
@@ -10,7 +10,7 @@ module ActiveRecord
|
|
|
10
10
|
#
|
|
11
11
|
# Usage:
|
|
12
12
|
#
|
|
13
|
-
# ActiveRecord::Schema.define do
|
|
13
|
+
# ActiveRecord::Schema[7.0].define do
|
|
14
14
|
# create_table :authors do |t|
|
|
15
15
|
# t.string :name, null: false
|
|
16
16
|
# end
|
|
@@ -30,32 +30,47 @@ module ActiveRecord
|
|
|
30
30
|
# ActiveRecord::Schema is only supported by database adapters that also
|
|
31
31
|
# support migrations, the two features being very similar.
|
|
32
32
|
class Schema < Migration::Current
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
33
|
+
module Definition
|
|
34
|
+
extend ActiveSupport::Concern
|
|
35
|
+
|
|
36
|
+
module ClassMethods
|
|
37
|
+
# Eval the given block. All methods available to the current connection
|
|
38
|
+
# adapter are available within the block, so you can easily use the
|
|
39
|
+
# database definition DSL to build up your schema (
|
|
40
|
+
# {create_table}[rdoc-ref:ConnectionAdapters::SchemaStatements#create_table],
|
|
41
|
+
# {add_index}[rdoc-ref:ConnectionAdapters::SchemaStatements#add_index], etc.).
|
|
42
|
+
#
|
|
43
|
+
# The +info+ hash is optional, and if given is used to define metadata
|
|
44
|
+
# about the current schema (currently, only the schema's version):
|
|
45
|
+
#
|
|
46
|
+
# ActiveRecord::Schema[7.0].define(version: 2038_01_19_000001) do
|
|
47
|
+
# ...
|
|
48
|
+
# end
|
|
49
|
+
def define(info = {}, &block)
|
|
50
|
+
new.define(info, &block)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def define(info, &block) # :nodoc:
|
|
55
|
+
instance_eval(&block)
|
|
48
56
|
|
|
49
|
-
|
|
50
|
-
|
|
57
|
+
if info[:version].present?
|
|
58
|
+
connection.schema_migration.create_table
|
|
59
|
+
connection.assume_migrated_upto_version(info[:version])
|
|
60
|
+
end
|
|
51
61
|
|
|
52
|
-
|
|
53
|
-
connection.
|
|
54
|
-
connection.assume_migrated_upto_version(info[:version])
|
|
62
|
+
ActiveRecord::InternalMetadata.create_table
|
|
63
|
+
ActiveRecord::InternalMetadata[:environment] = connection.migration_context.current_environment
|
|
55
64
|
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
include Definition
|
|
56
68
|
|
|
57
|
-
|
|
58
|
-
|
|
69
|
+
def self.[](version)
|
|
70
|
+
@class_for_version ||= {}
|
|
71
|
+
@class_for_version[version] ||= Class.new(Migration::Compatibility.find(version)) do
|
|
72
|
+
include Definition
|
|
73
|
+
end
|
|
59
74
|
end
|
|
60
75
|
end
|
|
61
76
|
end
|
|
@@ -74,22 +74,21 @@ module ActiveRecord
|
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
def header(stream)
|
|
77
|
-
stream.puts
|
|
78
|
-
# This file is auto-generated from the current state of the database. Instead
|
|
79
|
-
# of editing this file, please use the migrations feature of Active Record to
|
|
80
|
-
# incrementally modify your database, and then regenerate this schema definition.
|
|
81
|
-
#
|
|
82
|
-
# This file is the source Rails uses to define your schema when running `bin/rails
|
|
83
|
-
# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
|
|
84
|
-
# be faster and is potentially less error prone than running all of your
|
|
85
|
-
# migrations from scratch. Old migrations may fail to apply correctly if those
|
|
86
|
-
# migrations use external dependencies or application code.
|
|
87
|
-
#
|
|
88
|
-
# It's strongly recommended that you check this file into your version control system.
|
|
89
|
-
|
|
90
|
-
ActiveRecord::Schema.define(#{define_params}) do
|
|
91
|
-
|
|
92
|
-
HEADER
|
|
77
|
+
stream.puts <<~HEADER
|
|
78
|
+
# This file is auto-generated from the current state of the database. Instead
|
|
79
|
+
# of editing this file, please use the migrations feature of Active Record to
|
|
80
|
+
# incrementally modify your database, and then regenerate this schema definition.
|
|
81
|
+
#
|
|
82
|
+
# This file is the source Rails uses to define your schema when running `bin/rails
|
|
83
|
+
# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
|
|
84
|
+
# be faster and is potentially less error prone than running all of your
|
|
85
|
+
# migrations from scratch. Old migrations may fail to apply correctly if those
|
|
86
|
+
# migrations use external dependencies or application code.
|
|
87
|
+
#
|
|
88
|
+
# It's strongly recommended that you check this file into your version control system.
|
|
89
|
+
|
|
90
|
+
ActiveRecord::Schema[#{ActiveRecord::Migration.current_version}].define(#{define_params}) do
|
|
91
|
+
HEADER
|
|
93
92
|
end
|
|
94
93
|
|
|
95
94
|
def trailer(stream)
|
|
@@ -48,10 +48,6 @@ module ActiveRecord
|
|
|
48
48
|
super || default_scopes.any? || respond_to?(:default_scope)
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
-
def before_remove_const # :nodoc:
|
|
52
|
-
self.current_scope = nil
|
|
53
|
-
end
|
|
54
|
-
|
|
55
51
|
# Checks if the model has any default scopes. If all_queries
|
|
56
52
|
# is set to true, the method will check if there are any
|
|
57
53
|
# default_scopes for the model where +all_queries+ is true.
|
|
@@ -83,7 +79,7 @@ module ActiveRecord
|
|
|
83
79
|
# <tt>all_queries: true</tt>:
|
|
84
80
|
#
|
|
85
81
|
# class Article < ActiveRecord::Base
|
|
86
|
-
# default_scope { where(blog_id: 1) }, all_queries: true
|
|
82
|
+
# default_scope -> { where(blog_id: 1) }, all_queries: true
|
|
87
83
|
# end
|
|
88
84
|
#
|
|
89
85
|
# Applying a default scope to all queries will ensure that records
|
|
@@ -150,11 +146,13 @@ module ActiveRecord
|
|
|
150
146
|
end
|
|
151
147
|
elsif default_scopes.any?
|
|
152
148
|
evaluate_default_scope do
|
|
153
|
-
default_scopes.inject(relation) do |
|
|
149
|
+
default_scopes.inject(relation) do |combined_scope, scope_obj|
|
|
154
150
|
if execute_scope?(all_queries, scope_obj)
|
|
155
151
|
scope = scope_obj.scope.respond_to?(:to_proc) ? scope_obj.scope : scope_obj.scope.method(:call)
|
|
156
152
|
|
|
157
|
-
|
|
153
|
+
combined_scope.instance_exec(&scope) || combined_scope
|
|
154
|
+
else
|
|
155
|
+
combined_scope
|
|
158
156
|
end
|
|
159
157
|
end
|
|
160
158
|
end
|
|
@@ -47,7 +47,7 @@ module ActiveRecord
|
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
# Works like
|
|
50
|
+
# Works like find_signed, but will raise an +ActiveSupport::MessageVerifier::InvalidSignature+
|
|
51
51
|
# exception if the +signed_id+ has either expired, has a purpose mismatch, is for another record,
|
|
52
52
|
# or has been tampered with. It will also raise an +ActiveRecord::RecordNotFound+ exception if
|
|
53
53
|
# the valid signed id can't find a record.
|
|
@@ -97,7 +97,7 @@ module ActiveRecord
|
|
|
97
97
|
|
|
98
98
|
# Returns a signed id that's generated using a preconfigured +ActiveSupport::MessageVerifier+ instance.
|
|
99
99
|
# This signed id is tamper proof, so it's safe to send in an email or otherwise share with the outside world.
|
|
100
|
-
# It can
|
|
100
|
+
# It can furthermore be set to expire (the default is not to expire), and scoped down with a specific purpose.
|
|
101
101
|
# If the expiration date has been exceeded before +find_signed+ is called, the id won't find the designated
|
|
102
102
|
# record. If a purpose is set, this too must match.
|
|
103
103
|
#
|
data/lib/active_record/store.rb
CHANGED
|
@@ -59,7 +59,7 @@ module ActiveRecord
|
|
|
59
59
|
# u.color = 'green'
|
|
60
60
|
# u.color_changed? # => true
|
|
61
61
|
# u.color_was # => 'black'
|
|
62
|
-
# u.color_change # => ['black', '
|
|
62
|
+
# u.color_change # => ['black', 'green']
|
|
63
63
|
#
|
|
64
64
|
# # Add additional accessors to an existing store through store_accessor
|
|
65
65
|
# class SuperUser < User
|
|
@@ -268,7 +268,7 @@ module ActiveRecord
|
|
|
268
268
|
end
|
|
269
269
|
|
|
270
270
|
def dump(obj)
|
|
271
|
-
@coder.dump
|
|
271
|
+
@coder.dump as_regular_hash(obj)
|
|
272
272
|
end
|
|
273
273
|
|
|
274
274
|
def load(yaml)
|
|
@@ -285,6 +285,11 @@ module ActiveRecord
|
|
|
285
285
|
ActiveSupport::HashWithIndifferentAccess.new
|
|
286
286
|
end
|
|
287
287
|
end
|
|
288
|
+
|
|
289
|
+
private
|
|
290
|
+
def as_regular_hash(obj)
|
|
291
|
+
obj.respond_to?(:to_hash) ? obj.to_hash : {}
|
|
292
|
+
end
|
|
288
293
|
end
|
|
289
294
|
end
|
|
290
295
|
end
|
|
@@ -188,29 +188,31 @@ module ActiveRecord
|
|
|
188
188
|
def prepare_all
|
|
189
189
|
seed = false
|
|
190
190
|
|
|
191
|
-
|
|
191
|
+
each_current_configuration(env) do |db_config|
|
|
192
192
|
ActiveRecord::Base.establish_connection(db_config)
|
|
193
193
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
if ActiveRecord.dump_schema_after_migration
|
|
198
|
-
dump_schema(db_config, ActiveRecord.schema_format)
|
|
199
|
-
end
|
|
200
|
-
rescue ActiveRecord::NoDatabaseError
|
|
201
|
-
create_current(db_config.env_name, db_config.name)
|
|
202
|
-
|
|
203
|
-
if File.exist?(schema_dump_path(db_config))
|
|
204
|
-
load_schema(
|
|
205
|
-
db_config,
|
|
206
|
-
ActiveRecord.schema_format,
|
|
207
|
-
nil
|
|
208
|
-
)
|
|
209
|
-
else
|
|
194
|
+
begin
|
|
195
|
+
# Skipped when no database
|
|
210
196
|
migrate
|
|
211
|
-
end
|
|
212
197
|
|
|
213
|
-
|
|
198
|
+
if ActiveRecord.dump_schema_after_migration
|
|
199
|
+
dump_schema(db_config, ActiveRecord.schema_format)
|
|
200
|
+
end
|
|
201
|
+
rescue ActiveRecord::NoDatabaseError
|
|
202
|
+
create(db_config)
|
|
203
|
+
|
|
204
|
+
if File.exist?(schema_dump_path(db_config))
|
|
205
|
+
load_schema(
|
|
206
|
+
db_config,
|
|
207
|
+
ActiveRecord.schema_format,
|
|
208
|
+
nil
|
|
209
|
+
)
|
|
210
|
+
else
|
|
211
|
+
migrate
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
seed = true
|
|
215
|
+
end
|
|
214
216
|
end
|
|
215
217
|
|
|
216
218
|
ActiveRecord::Base.establish_connection
|
|
@@ -257,8 +259,12 @@ module ActiveRecord
|
|
|
257
259
|
scope = ENV["SCOPE"]
|
|
258
260
|
verbose_was, Migration.verbose = Migration.verbose, verbose?
|
|
259
261
|
|
|
260
|
-
Base.connection.migration_context.migrate(target_version
|
|
261
|
-
|
|
262
|
+
Base.connection.migration_context.migrate(target_version) do |migration|
|
|
263
|
+
if version.blank?
|
|
264
|
+
scope.blank? || scope == migration.scope
|
|
265
|
+
else
|
|
266
|
+
migration.version == version
|
|
267
|
+
end
|
|
262
268
|
end.tap do |migrations_ran|
|
|
263
269
|
Migration.write("No migrations ran. (using #{scope} scope)") if scope.present? && migrations_ran.empty?
|
|
264
270
|
end
|
|
@@ -360,6 +366,7 @@ module ActiveRecord
|
|
|
360
366
|
|
|
361
367
|
def load_schema(db_config, format = ActiveRecord.schema_format, file = nil) # :nodoc:
|
|
362
368
|
file ||= schema_dump_path(db_config, format)
|
|
369
|
+
return unless file
|
|
363
370
|
|
|
364
371
|
verbose_was, Migration.verbose = Migration.verbose, verbose? && ENV["VERBOSE"]
|
|
365
372
|
check_schema_file(file)
|
|
@@ -385,7 +392,7 @@ module ActiveRecord
|
|
|
385
392
|
|
|
386
393
|
file ||= schema_dump_path(db_config)
|
|
387
394
|
|
|
388
|
-
return true unless File.exist?(file)
|
|
395
|
+
return true unless file && File.exist?(file)
|
|
389
396
|
|
|
390
397
|
ActiveRecord::Base.establish_connection(db_config)
|
|
391
398
|
|
|
@@ -398,7 +405,7 @@ module ActiveRecord
|
|
|
398
405
|
def reconstruct_from_schema(db_config, format = ActiveRecord.schema_format, file = nil) # :nodoc:
|
|
399
406
|
file ||= schema_dump_path(db_config, format)
|
|
400
407
|
|
|
401
|
-
check_schema_file(file)
|
|
408
|
+
check_schema_file(file) if file
|
|
402
409
|
|
|
403
410
|
ActiveRecord::Base.establish_connection(db_config)
|
|
404
411
|
|
|
@@ -416,6 +423,8 @@ module ActiveRecord
|
|
|
416
423
|
def dump_schema(db_config, format = ActiveRecord.schema_format) # :nodoc:
|
|
417
424
|
require "active_record/schema_dumper"
|
|
418
425
|
filename = schema_dump_path(db_config, format)
|
|
426
|
+
return unless filename
|
|
427
|
+
|
|
419
428
|
connection = ActiveRecord::Base.connection
|
|
420
429
|
|
|
421
430
|
FileUtils.mkdir_p(db_dir)
|
|
@@ -58,7 +58,6 @@ module ActiveRecord
|
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
args = ["--schema-only", "--no-privileges", "--no-owner"]
|
|
61
|
-
args << "--no-comment" if connection.database_version >= 110_000
|
|
62
61
|
args.concat(["--file", filename])
|
|
63
62
|
|
|
64
63
|
args.concat(Array(extra_flags)) if extra_flags
|
|
@@ -81,7 +80,7 @@ module ActiveRecord
|
|
|
81
80
|
end
|
|
82
81
|
|
|
83
82
|
def structure_load(filename, extra_flags)
|
|
84
|
-
args = ["--set", ON_ERROR_STOP_1, "--quiet", "--no-psqlrc", "--file", filename]
|
|
83
|
+
args = ["--set", ON_ERROR_STOP_1, "--quiet", "--no-psqlrc", "--output", File::NULL, "--file", filename]
|
|
85
84
|
args.concat(Array(extra_flags)) if extra_flags
|
|
86
85
|
args << db_config.database
|
|
87
86
|
run_cmd("psql", args, "loading")
|
|
@@ -86,6 +86,9 @@ module ActiveRecord
|
|
|
86
86
|
include methods
|
|
87
87
|
end
|
|
88
88
|
|
|
89
|
+
# Prevents automatically wrapping each specified test in a transaction,
|
|
90
|
+
# to allow application logic transactions to be tested in a top-level
|
|
91
|
+
# (non-nested) context.
|
|
89
92
|
def uses_transaction(*methods)
|
|
90
93
|
@uses_transaction = [] unless defined?(@uses_transaction)
|
|
91
94
|
@uses_transaction.concat methods.map(&:to_s)
|
|
@@ -134,7 +137,7 @@ module ActiveRecord
|
|
|
134
137
|
@connection_subscriber = ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload|
|
|
135
138
|
spec_name = payload[:spec_name] if payload.key?(:spec_name)
|
|
136
139
|
shard = payload[:shard] if payload.key?(:shard)
|
|
137
|
-
setup_shared_connection_pool
|
|
140
|
+
setup_shared_connection_pool if ActiveRecord.legacy_connection_handling
|
|
138
141
|
|
|
139
142
|
if spec_name
|
|
140
143
|
begin
|
|
@@ -143,10 +146,14 @@ module ActiveRecord
|
|
|
143
146
|
connection = nil
|
|
144
147
|
end
|
|
145
148
|
|
|
146
|
-
if connection
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
149
|
+
if connection
|
|
150
|
+
setup_shared_connection_pool unless ActiveRecord.legacy_connection_handling
|
|
151
|
+
|
|
152
|
+
if !@fixture_connections.include?(connection)
|
|
153
|
+
connection.begin_transaction joinable: false, _lazy: false
|
|
154
|
+
connection.pool.lock_thread = true if lock_threads
|
|
155
|
+
@fixture_connections << connection
|
|
156
|
+
end
|
|
150
157
|
end
|
|
151
158
|
end
|
|
152
159
|
end
|
|
@@ -42,14 +42,14 @@ module ActiveRecord
|
|
|
42
42
|
# or an array of symbols. (e.g. <tt>on: :create</tt> or
|
|
43
43
|
# <tt>on: :custom_validation_context</tt> or
|
|
44
44
|
# <tt>on: [:create, :custom_validation_context]</tt>)
|
|
45
|
-
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine
|
|
45
|
+
# * <tt>:if</tt> - Specifies a method, proc, or string to call to determine
|
|
46
46
|
# if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
|
|
47
47
|
# or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
|
|
48
48
|
# proc or string should return or evaluate to a +true+ or +false+ value.
|
|
49
|
-
# * <tt>:unless</tt> - Specifies a method, proc or string to call to
|
|
49
|
+
# * <tt>:unless</tt> - Specifies a method, proc, or string to call to
|
|
50
50
|
# determine if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
|
|
51
51
|
# or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
|
52
|
-
# method, proc or string should return or evaluate to a +true+ or +false+
|
|
52
|
+
# method, proc, or string should return or evaluate to a +true+ or +false+
|
|
53
53
|
# value.
|
|
54
54
|
def validates_associated(*attr_names)
|
|
55
55
|
validates_with AssociatedValidator, _merge_attributes(attr_names)
|
|
@@ -50,11 +50,11 @@ module ActiveRecord
|
|
|
50
50
|
# or an array of symbols. (e.g. <tt>on: :create</tt> or
|
|
51
51
|
# <tt>on: :custom_validation_context</tt> or
|
|
52
52
|
# <tt>on: [:create, :custom_validation_context]</tt>)
|
|
53
|
-
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if
|
|
53
|
+
# * <tt>:if</tt> - Specifies a method, proc, or string to call to determine if
|
|
54
54
|
# the validation should occur (e.g. <tt>if: :allow_validation</tt>, or
|
|
55
55
|
# <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
|
|
56
56
|
# or string should return or evaluate to a +true+ or +false+ value.
|
|
57
|
-
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
|
|
57
|
+
# * <tt>:unless</tt> - Specifies a method, proc, or string to call to determine
|
|
58
58
|
# if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
|
|
59
59
|
# or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The method,
|
|
60
60
|
# proc or string should return or evaluate to a +true+ or +false+ value.
|
|
@@ -166,14 +166,14 @@ module ActiveRecord
|
|
|
166
166
|
# attribute is +nil+ (default is +false+).
|
|
167
167
|
# * <tt>:allow_blank</tt> - If set to +true+, skips this validation if the
|
|
168
168
|
# attribute is blank (default is +false+).
|
|
169
|
-
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine
|
|
169
|
+
# * <tt>:if</tt> - Specifies a method, proc, or string to call to determine
|
|
170
170
|
# if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
|
|
171
171
|
# or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
|
|
172
172
|
# proc or string should return or evaluate to a +true+ or +false+ value.
|
|
173
|
-
# * <tt>:unless</tt> - Specifies a method, proc or string to call to
|
|
173
|
+
# * <tt>:unless</tt> - Specifies a method, proc, or string to call to
|
|
174
174
|
# determine if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
|
|
175
175
|
# or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
|
176
|
-
# method, proc or string should return or evaluate to a +true+ or +false+
|
|
176
|
+
# method, proc, or string should return or evaluate to a +true+ or +false+
|
|
177
177
|
# value.
|
|
178
178
|
#
|
|
179
179
|
# === Concurrency and integrity
|