activerecord 5.2.0 → 5.2.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 +4 -4
- data/CHANGELOG.md +65 -0
- data/lib/active_record/associations.rb +9 -9
- data/lib/active_record/associations/alias_tracker.rb +1 -1
- data/lib/active_record/associations/association.rb +17 -10
- data/lib/active_record/associations/belongs_to_association.rb +14 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +4 -1
- data/lib/active_record/associations/builder/belongs_to.rb +11 -2
- data/lib/active_record/associations/collection_association.rb +10 -7
- data/lib/active_record/associations/has_many_through_association.rb +1 -1
- data/lib/active_record/associations/has_one_association.rb +8 -0
- data/lib/active_record/associations/has_one_through_association.rb +5 -1
- data/lib/active_record/associations/join_dependency.rb +39 -64
- data/lib/active_record/associations/join_dependency/join_association.rb +12 -18
- data/lib/active_record/associations/join_dependency/join_part.rb +7 -0
- data/lib/active_record/associations/singular_association.rb +4 -10
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/attribute_methods/dirty.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +1 -1
- data/lib/active_record/autosave_association.rb +8 -3
- data/lib/active_record/callbacks.rb +4 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +7 -4
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +3 -12
- data/lib/active_record/connection_adapters/abstract/transaction.rb +23 -14
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +0 -11
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +2 -2
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +0 -3
- data/lib/active_record/counter_cache.rb +17 -13
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/log_subscriber.rb +1 -1
- data/lib/active_record/persistence.rb +1 -1
- data/lib/active_record/query_cache.rb +4 -11
- data/lib/active_record/relation.rb +13 -13
- data/lib/active_record/relation/finder_methods.rb +2 -4
- data/lib/active_record/relation/merger.rb +2 -6
- data/lib/active_record/relation/predicate_builder.rb +6 -5
- data/lib/active_record/relation/query_methods.rb +16 -13
- data/lib/active_record/timestamp.rb +8 -1
- data/lib/active_record/transactions.rb +23 -20
- data/lib/active_record/type/serialized.rb +4 -0
- metadata +8 -8
@@ -6,17 +6,14 @@ module ActiveRecord
|
|
6
6
|
module Associations
|
7
7
|
class JoinDependency # :nodoc:
|
8
8
|
class JoinAssociation < JoinPart # :nodoc:
|
9
|
-
|
10
|
-
|
9
|
+
attr_reader :reflection, :tables
|
10
|
+
attr_accessor :table
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
def initialize(reflection, children, alias_tracker)
|
12
|
+
def initialize(reflection, children)
|
15
13
|
super(reflection.klass, children)
|
16
14
|
|
17
|
-
@
|
18
|
-
@
|
19
|
-
@tables = nil
|
15
|
+
@reflection = reflection
|
16
|
+
@tables = nil
|
20
17
|
end
|
21
18
|
|
22
19
|
def match?(other)
|
@@ -24,14 +21,13 @@ module ActiveRecord
|
|
24
21
|
super && reflection == other.reflection
|
25
22
|
end
|
26
23
|
|
27
|
-
def join_constraints(foreign_table, foreign_klass, join_type,
|
28
|
-
joins
|
29
|
-
tables = tables.reverse
|
24
|
+
def join_constraints(foreign_table, foreign_klass, join_type, alias_tracker)
|
25
|
+
joins = []
|
30
26
|
|
31
27
|
# The chain starts with the target table, but we want to end with it here (makes
|
32
28
|
# more sense in this context), so we reverse
|
33
|
-
chain.reverse_each do |reflection|
|
34
|
-
table = tables
|
29
|
+
reflection.chain.reverse_each.with_index(1) do |reflection, i|
|
30
|
+
table = tables[-i]
|
35
31
|
klass = reflection.klass
|
36
32
|
|
37
33
|
constraint = reflection.build_join_constraint(table, foreign_table)
|
@@ -54,12 +50,10 @@ module ActiveRecord
|
|
54
50
|
joins
|
55
51
|
end
|
56
52
|
|
57
|
-
def
|
58
|
-
tables
|
53
|
+
def tables=(tables)
|
54
|
+
@tables = tables
|
55
|
+
@table = tables.first
|
59
56
|
end
|
60
|
-
|
61
|
-
protected
|
62
|
-
attr_reader :alias_tracker
|
63
57
|
end
|
64
58
|
end
|
65
59
|
end
|
@@ -33,6 +33,13 @@ module ActiveRecord
|
|
33
33
|
children.each { |child| child.each(&block) }
|
34
34
|
end
|
35
35
|
|
36
|
+
def each_children(&block)
|
37
|
+
children.each do |child|
|
38
|
+
yield self, child
|
39
|
+
child.each_children(&block)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
36
43
|
# An Arel::Table for the active_record
|
37
44
|
def table
|
38
45
|
raise NotImplementedError
|
@@ -17,9 +17,8 @@ module ActiveRecord
|
|
17
17
|
replace(record)
|
18
18
|
end
|
19
19
|
|
20
|
-
def build(attributes = {})
|
21
|
-
record = build_record(attributes)
|
22
|
-
yield(record) if block_given?
|
20
|
+
def build(attributes = {}, &block)
|
21
|
+
record = build_record(attributes, &block)
|
23
22
|
set_new_record(record)
|
24
23
|
record
|
25
24
|
end
|
@@ -62,13 +61,8 @@ module ActiveRecord
|
|
62
61
|
replace(record)
|
63
62
|
end
|
64
63
|
|
65
|
-
def _create_record(attributes, raise_error = false)
|
66
|
-
|
67
|
-
raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
|
68
|
-
end
|
69
|
-
|
70
|
-
record = build_record(attributes)
|
71
|
-
yield(record) if block_given?
|
64
|
+
def _create_record(attributes, raise_error = false, &block)
|
65
|
+
record = build_record(attributes, &block)
|
72
66
|
saved = record.save
|
73
67
|
set_new_record(record)
|
74
68
|
raise RecordInvalid.new(record) if !saved && raise_error
|
@@ -114,12 +114,12 @@ module ActiveRecord
|
|
114
114
|
|
115
115
|
# Alias for +changed+
|
116
116
|
def changed_attribute_names_to_save
|
117
|
-
|
117
|
+
mutations_from_database.changed_attribute_names
|
118
118
|
end
|
119
119
|
|
120
120
|
# Alias for +changed_attributes+
|
121
121
|
def attributes_in_database
|
122
|
-
|
122
|
+
mutations_from_database.changed_values
|
123
123
|
end
|
124
124
|
|
125
125
|
private
|
@@ -69,7 +69,7 @@ module ActiveRecord
|
|
69
69
|
if defined?(JRUBY_VERSION)
|
70
70
|
# This form is significantly faster on JRuby, and this is one of our biggest hotspots.
|
71
71
|
# https://github.com/jruby/jruby/pull/2562
|
72
|
-
def _read_attribute(attr_name, &block) # :nodoc
|
72
|
+
def _read_attribute(attr_name, &block) # :nodoc:
|
73
73
|
@attributes.fetch_value(attr_name.to_s, &block)
|
74
74
|
end
|
75
75
|
else
|
@@ -392,7 +392,7 @@ module ActiveRecord
|
|
392
392
|
records -= records_to_destroy
|
393
393
|
end
|
394
394
|
|
395
|
-
records.
|
395
|
+
records.each_with_index do |record, index|
|
396
396
|
next if record.destroyed?
|
397
397
|
|
398
398
|
saved = true
|
@@ -400,8 +400,13 @@ module ActiveRecord
|
|
400
400
|
if autosave != false && (@new_record_before_save || record.new_record?)
|
401
401
|
if autosave
|
402
402
|
saved = association.insert_record(record, false)
|
403
|
-
|
404
|
-
|
403
|
+
elsif !reflection.nested?
|
404
|
+
if reflection.validate?
|
405
|
+
valid = association_valid?(reflection, record, index)
|
406
|
+
saved = valid ? association.insert_record(record, false) : false
|
407
|
+
else
|
408
|
+
association.insert_record(record)
|
409
|
+
end
|
405
410
|
end
|
406
411
|
elsif autosave
|
407
412
|
saved = record.save(validate: false)
|
@@ -498,6 +498,9 @@ module ActiveRecord
|
|
498
498
|
# t.date
|
499
499
|
# t.binary
|
500
500
|
# t.boolean
|
501
|
+
# t.foreign_key
|
502
|
+
# t.json
|
503
|
+
# t.virtual
|
501
504
|
# t.remove
|
502
505
|
# t.remove_references
|
503
506
|
# t.remove_belongs_to
|
@@ -662,19 +665,19 @@ module ActiveRecord
|
|
662
665
|
|
663
666
|
# Adds a foreign key.
|
664
667
|
#
|
665
|
-
#
|
668
|
+
# t.foreign_key(:authors)
|
666
669
|
#
|
667
670
|
# See {connection.add_foreign_key}[rdoc-ref:SchemaStatements#add_foreign_key]
|
668
|
-
def foreign_key(*args)
|
671
|
+
def foreign_key(*args)
|
669
672
|
@base.add_foreign_key(name, *args)
|
670
673
|
end
|
671
674
|
|
672
675
|
# Checks to see if a foreign key exists.
|
673
676
|
#
|
674
|
-
#
|
677
|
+
# t.foreign_key(:authors) unless t.foreign_key_exists?(:authors)
|
675
678
|
#
|
676
679
|
# See {connection.foreign_key_exists?}[rdoc-ref:SchemaStatements#foreign_key_exists?]
|
677
|
-
def foreign_key_exists?(*args)
|
680
|
+
def foreign_key_exists?(*args)
|
678
681
|
@base.foreign_key_exists?(name, *args)
|
679
682
|
end
|
680
683
|
end
|
@@ -741,22 +741,13 @@ module ActiveRecord
|
|
741
741
|
# ====== Creating an index with a specific operator class
|
742
742
|
#
|
743
743
|
# add_index(:developers, :name, using: 'gist', opclass: :gist_trgm_ops)
|
744
|
-
#
|
745
|
-
# generates:
|
746
|
-
#
|
747
|
-
# CREATE INDEX developers_on_name ON developers USING gist (name gist_trgm_ops) -- PostgreSQL
|
744
|
+
# # CREATE INDEX developers_on_name ON developers USING gist (name gist_trgm_ops) -- PostgreSQL
|
748
745
|
#
|
749
746
|
# add_index(:developers, [:name, :city], using: 'gist', opclass: { city: :gist_trgm_ops })
|
750
|
-
#
|
751
|
-
# generates:
|
752
|
-
#
|
753
|
-
# CREATE INDEX developers_on_name_and_city ON developers USING gist (name, city gist_trgm_ops) -- PostgreSQL
|
747
|
+
# # CREATE INDEX developers_on_name_and_city ON developers USING gist (name, city gist_trgm_ops) -- PostgreSQL
|
754
748
|
#
|
755
749
|
# add_index(:developers, [:name, :city], using: 'gist', opclass: :gist_trgm_ops)
|
756
|
-
#
|
757
|
-
# generates:
|
758
|
-
#
|
759
|
-
# CREATE INDEX developers_on_name_and_city ON developers USING gist (name gist_trgm_ops, city gist_trgm_ops) -- PostgreSQL
|
750
|
+
# # CREATE INDEX developers_on_name_and_city ON developers USING gist (name gist_trgm_ops, city gist_trgm_ops) -- PostgreSQL
|
760
751
|
#
|
761
752
|
# Note: only supported by PostgreSQL
|
762
753
|
#
|
@@ -17,11 +17,19 @@ module ActiveRecord
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def committed?
|
20
|
-
@state == :committed
|
20
|
+
@state == :committed || @state == :fully_committed
|
21
|
+
end
|
22
|
+
|
23
|
+
def fully_committed?
|
24
|
+
@state == :fully_committed
|
21
25
|
end
|
22
26
|
|
23
27
|
def rolledback?
|
24
|
-
@state == :rolledback
|
28
|
+
@state == :rolledback || @state == :fully_rolledback
|
29
|
+
end
|
30
|
+
|
31
|
+
def fully_rolledback?
|
32
|
+
@state == :fully_rolledback
|
25
33
|
end
|
26
34
|
|
27
35
|
def fully_completed?
|
@@ -55,10 +63,19 @@ module ActiveRecord
|
|
55
63
|
@state = :rolledback
|
56
64
|
end
|
57
65
|
|
66
|
+
def full_rollback!
|
67
|
+
@children.each { |c| c.rollback! }
|
68
|
+
@state = :fully_rolledback
|
69
|
+
end
|
70
|
+
|
58
71
|
def commit!
|
59
72
|
@state = :committed
|
60
73
|
end
|
61
74
|
|
75
|
+
def full_commit!
|
76
|
+
@state = :fully_committed
|
77
|
+
end
|
78
|
+
|
62
79
|
def nullify!
|
63
80
|
@state = nil
|
64
81
|
end
|
@@ -89,10 +106,6 @@ module ActiveRecord
|
|
89
106
|
records << record
|
90
107
|
end
|
91
108
|
|
92
|
-
def rollback
|
93
|
-
@state.rollback!
|
94
|
-
end
|
95
|
-
|
96
109
|
def rollback_records
|
97
110
|
ite = records.uniq
|
98
111
|
while record = ite.shift
|
@@ -104,10 +117,6 @@ module ActiveRecord
|
|
104
117
|
end
|
105
118
|
end
|
106
119
|
|
107
|
-
def commit
|
108
|
-
@state.commit!
|
109
|
-
end
|
110
|
-
|
111
120
|
def before_commit_records
|
112
121
|
records.uniq.each(&:before_committed!) if @run_commit_callbacks
|
113
122
|
end
|
@@ -146,12 +155,12 @@ module ActiveRecord
|
|
146
155
|
|
147
156
|
def rollback
|
148
157
|
connection.rollback_to_savepoint(savepoint_name)
|
149
|
-
|
158
|
+
@state.rollback!
|
150
159
|
end
|
151
160
|
|
152
161
|
def commit
|
153
162
|
connection.release_savepoint(savepoint_name)
|
154
|
-
|
163
|
+
@state.commit!
|
155
164
|
end
|
156
165
|
|
157
166
|
def full_rollback?; false; end
|
@@ -169,12 +178,12 @@ module ActiveRecord
|
|
169
178
|
|
170
179
|
def rollback
|
171
180
|
connection.rollback_db_transaction
|
172
|
-
|
181
|
+
@state.full_rollback!
|
173
182
|
end
|
174
183
|
|
175
184
|
def commit
|
176
185
|
connection.commit_db_transaction
|
177
|
-
|
186
|
+
@state.full_commit!
|
178
187
|
end
|
179
188
|
end
|
180
189
|
|
@@ -560,17 +560,6 @@ module ActiveRecord
|
|
560
560
|
@max_allowed_packet ||= (show_variable("max_allowed_packet") - bytes_margin)
|
561
561
|
end
|
562
562
|
|
563
|
-
def with_multi_statements
|
564
|
-
previous_flags = @config[:flags]
|
565
|
-
@config[:flags] = Mysql2::Client::MULTI_STATEMENTS
|
566
|
-
reconnect!
|
567
|
-
|
568
|
-
yield
|
569
|
-
ensure
|
570
|
-
@config[:flags] = previous_flags
|
571
|
-
reconnect!
|
572
|
-
end
|
573
|
-
|
574
563
|
def initialize_type_map(m = type_map)
|
575
564
|
super
|
576
565
|
|
@@ -62,6 +62,42 @@ module ActiveRecord
|
|
62
62
|
@connection.next_result while @connection.more_results?
|
63
63
|
end
|
64
64
|
|
65
|
+
def supports_set_server_option?
|
66
|
+
@connection.respond_to?(:set_server_option)
|
67
|
+
end
|
68
|
+
|
69
|
+
def multi_statements_enabled?(flags)
|
70
|
+
if flags.is_a?(Array)
|
71
|
+
flags.include?("MULTI_STATEMENTS")
|
72
|
+
else
|
73
|
+
(flags & Mysql2::Client::MULTI_STATEMENTS) != 0
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def with_multi_statements
|
78
|
+
previous_flags = @config[:flags]
|
79
|
+
|
80
|
+
unless multi_statements_enabled?(previous_flags)
|
81
|
+
if supports_set_server_option?
|
82
|
+
@connection.set_server_option(Mysql2::Client::OPTION_MULTI_STATEMENTS_ON)
|
83
|
+
else
|
84
|
+
@config[:flags] = Mysql2::Client::MULTI_STATEMENTS
|
85
|
+
reconnect!
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
yield
|
90
|
+
ensure
|
91
|
+
unless multi_statements_enabled?(previous_flags)
|
92
|
+
if supports_set_server_option?
|
93
|
+
@connection.set_server_option(Mysql2::Client::OPTION_MULTI_STATEMENTS_OFF)
|
94
|
+
else
|
95
|
+
@config[:flags] = previous_flags
|
96
|
+
reconnect!
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
65
101
|
def exec_stmt_and_free(sql, name, binds, cache_stmt: false)
|
66
102
|
# make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
|
67
103
|
# made since we established the connection
|
@@ -80,8 +80,8 @@ module ActiveRecord
|
|
80
80
|
|
81
81
|
def new_column_from_field(table_name, field)
|
82
82
|
type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
|
83
|
-
if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\(
|
84
|
-
default, default_function = nil,
|
83
|
+
if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\([0-6]?\))?\z/i.match?(field[:Default])
|
84
|
+
default, default_function = nil, field[:Default]
|
85
85
|
else
|
86
86
|
default, default_function = field[:Default], nil
|
87
87
|
end
|
@@ -751,7 +751,7 @@ module ActiveRecord
|
|
751
751
|
|
752
752
|
def data_source_sql(name = nil, type: nil)
|
753
753
|
scope = quoted_scope(name, type: type)
|
754
|
-
scope[:type] ||= "'r','v','m','f'" # (r)elation/table, (v)iew, (m)aterialized view, (f)oreign table
|
754
|
+
scope[:type] ||= "'r','v','m','p','f'" # (r)elation/table, (v)iew, (m)aterialized view, (p)artitioned table, (f)oreign table
|
755
755
|
|
756
756
|
sql = "SELECT c.relname FROM pg_class c LEFT JOIN pg_namespace n ON n.oid = c.relnamespace".dup
|
757
757
|
sql << " WHERE n.nspname = #{scope[:schema]}"
|
@@ -765,7 +765,7 @@ module ActiveRecord
|
|
765
765
|
type = \
|
766
766
|
case type
|
767
767
|
when "BASE TABLE"
|
768
|
-
"'r'"
|
768
|
+
"'r','p'"
|
769
769
|
when "VIEW"
|
770
770
|
"'v','m'"
|
771
771
|
when "FOREIGN TABLE"
|