activerecord 5.1.5 → 5.1.7
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 +79 -0
- data/lib/active_record/associations/belongs_to_association.rb +1 -1
- data/lib/active_record/associations/builder/belongs_to.rb +2 -1
- data/lib/active_record/attribute_methods/dirty.rb +2 -2
- data/lib/active_record/attribute_mutation_tracker.rb +9 -1
- data/lib/active_record/attribute_set/builder.rb +24 -22
- data/lib/active_record/attribute_set.rb +1 -1
- data/lib/active_record/attributes.rb +1 -1
- data/lib/active_record/callbacks.rb +4 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +3 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +2 -1
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +18 -8
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +11 -1
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +9 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +2 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -1
- data/lib/active_record/counter_cache.rb +10 -12
- data/lib/active_record/errors.rb +18 -12
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +19 -28
- data/lib/active_record/model_schema.rb +5 -5
- data/lib/active_record/persistence.rb +34 -36
- data/lib/active_record/query_cache.rb +6 -6
- data/lib/active_record/relation/calculations.rb +1 -1
- data/lib/active_record/relation/finder_methods.rb +2 -2
- data/lib/active_record/relation/predicate_builder.rb +2 -2
- data/lib/active_record/relation/query_methods.rb +1 -1
- data/lib/active_record/relation.rb +2 -2
- data/lib/active_record/tasks/database_tasks.rb +1 -1
- data/lib/active_record/timestamp.rb +7 -0
- data/lib/active_record/type/serialized.rb +4 -0
- data/lib/active_record/validations/uniqueness.rb +1 -1
- metadata +9 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3761a48d6ad944f4726d6f454c7410ce0fbf30be0dc352eabf0e91bf8dea9944
|
4
|
+
data.tar.gz: 392232a9587e31dd74e1718943feb82f28473f64cb6fe6787fa9f9a164c582c8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4218769b0900a3b0a259ae85ab829eab4b3fad9801d3090d3ab5eca256e090a9c5b27d425d209ed38fda281308597aae4be88d0e15fc08e2eed1bedb80ae1639
|
7
|
+
data.tar.gz: 942951a6f2905cab9ee82620438e8c627bff5185f7769f4f384b049e580f39d549763c0052f6c3b7c71ee66a8f6bc7bdf9767e7108bc7267383f5b3dccd18157
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,84 @@
|
|
1
|
+
## Rails 5.1.7 (March 27, 2019) ##
|
2
|
+
|
3
|
+
* Fix `touch` option to behave consistently with `Persistence#touch` method.
|
4
|
+
|
5
|
+
*Ryuta Kamizono*
|
6
|
+
|
7
|
+
* Back port Rails 5.2 `reverse_order` Arel SQL literal fix.
|
8
|
+
|
9
|
+
*Matt Jones*, *Brooke Kuhlmann*
|
10
|
+
|
11
|
+
* `becomes` should clear the mutation tracker which is created in `after_initialize`.
|
12
|
+
|
13
|
+
Fixes #32867.
|
14
|
+
|
15
|
+
*Ryuta Kamizono*
|
16
|
+
|
17
|
+
|
18
|
+
## Rails 5.1.6.2 (March 11, 2019) ##
|
19
|
+
|
20
|
+
* No changes.
|
21
|
+
|
22
|
+
|
23
|
+
## Rails 5.1.6.1 (November 27, 2018) ##
|
24
|
+
|
25
|
+
* No changes.
|
26
|
+
|
27
|
+
|
28
|
+
## Rails 5.1.6 (March 29, 2018) ##
|
29
|
+
|
30
|
+
* MySQL: Support mysql2 0.5.x.
|
31
|
+
|
32
|
+
*Aaron Stone*
|
33
|
+
|
34
|
+
* Apply time column precision on assignment.
|
35
|
+
|
36
|
+
PR #20317 changed the behavior of datetime columns so that when they
|
37
|
+
have a specified precision then on assignment the value is rounded to
|
38
|
+
that precision. This behavior is now applied to time columns as well.
|
39
|
+
|
40
|
+
Fixes #30301.
|
41
|
+
|
42
|
+
*Andrew White*
|
43
|
+
|
44
|
+
* Normalize time column values for SQLite database.
|
45
|
+
|
46
|
+
For legacy reasons, time columns in SQLite are stored as full datetimes
|
47
|
+
because until #24542 the quoting for time columns didn't remove the date
|
48
|
+
component. To ensure that values are consistent we now normalize the
|
49
|
+
date component to 2001-01-01 on reading and writing.
|
50
|
+
|
51
|
+
*Andrew White*
|
52
|
+
|
53
|
+
* Ensure that the date component is removed when quoting times.
|
54
|
+
|
55
|
+
PR #24542 altered the quoting for time columns so that the date component
|
56
|
+
was removed however it only removed it when it was 2001-01-01. Now the
|
57
|
+
date component is removed irrespective of what the date is.
|
58
|
+
|
59
|
+
*Andrew White*
|
60
|
+
|
61
|
+
* Fix that after commit callbacks on update does not triggered when optimistic locking is enabled.
|
62
|
+
|
63
|
+
*Ryuta Kamizono*
|
64
|
+
|
65
|
+
* `ActiveRecord::Persistence#touch` does not work well when optimistic locking enabled and
|
66
|
+
`locking_column`, without default value, is null in the database.
|
67
|
+
|
68
|
+
*bogdanvlviv*
|
69
|
+
|
70
|
+
* Fix destroying existing object does not work well when optimistic locking enabled and
|
71
|
+
`locking column` is null in the database.
|
72
|
+
|
73
|
+
*bogdanvlviv*
|
74
|
+
|
75
|
+
|
1
76
|
## Rails 5.1.5 (February 14, 2018) ##
|
2
77
|
|
78
|
+
* PostgreSQL: Allow pg-1.0 gem to be used with Active Record.
|
79
|
+
|
80
|
+
*Lars Kanis*
|
81
|
+
|
3
82
|
* Fix `count(:all)` with eager loading and having an order other than the driving table.
|
4
83
|
|
5
84
|
Fixes #31783.
|
@@ -65,7 +65,7 @@ module ActiveRecord
|
|
65
65
|
def update_counters_on_replace(record)
|
66
66
|
if require_counter_update? && different_target?(record)
|
67
67
|
owner.instance_variable_set :@_after_replace_counter_called, true
|
68
|
-
record.increment!(reflection.counter_cache_column)
|
68
|
+
record.increment!(reflection.counter_cache_column, touch: reflection.options[:touch])
|
69
69
|
decrement_counters
|
70
70
|
end
|
71
71
|
end
|
@@ -84,7 +84,8 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
84
84
|
else
|
85
85
|
klass = association.klass
|
86
86
|
end
|
87
|
-
|
87
|
+
primary_key = reflection.association_primary_key(klass)
|
88
|
+
old_record = klass.find_by(primary_key => old_foreign_id)
|
88
89
|
|
89
90
|
if old_record
|
90
91
|
if touch != true
|
@@ -204,12 +204,12 @@ module ActiveRecord
|
|
204
204
|
|
205
205
|
# Alias for `changed`
|
206
206
|
def changed_attribute_names_to_save
|
207
|
-
|
207
|
+
mutations_from_database.changed_attribute_names
|
208
208
|
end
|
209
209
|
|
210
210
|
# Alias for `changed_attributes`
|
211
211
|
def attributes_in_database
|
212
|
-
|
212
|
+
mutations_from_database.changed_values
|
213
213
|
end
|
214
214
|
|
215
215
|
def attribute_was(*)
|
@@ -8,6 +8,10 @@ module ActiveRecord
|
|
8
8
|
@deprecated_forced_changes = Set.new
|
9
9
|
end
|
10
10
|
|
11
|
+
def changed_attribute_names
|
12
|
+
attr_names.select { |attr_name| changed?(attr_name) }
|
13
|
+
end
|
14
|
+
|
11
15
|
def changed_values
|
12
16
|
attr_names.each_with_object({}.with_indifferent_access) do |attr_name, result|
|
13
17
|
if changed?(attr_name)
|
@@ -20,7 +24,7 @@ module ActiveRecord
|
|
20
24
|
attr_names.each_with_object({}.with_indifferent_access) do |attr_name, result|
|
21
25
|
change = change_to_attribute(attr_name)
|
22
26
|
if change
|
23
|
-
result
|
27
|
+
result.merge!(attr_name => change)
|
24
28
|
end
|
25
29
|
end
|
26
30
|
end
|
@@ -82,6 +86,10 @@ module ActiveRecord
|
|
82
86
|
class NullMutationTracker # :nodoc:
|
83
87
|
include Singleton
|
84
88
|
|
89
|
+
def changed_attribute_names(*)
|
90
|
+
[]
|
91
|
+
end
|
92
|
+
|
85
93
|
def changed_values(*)
|
86
94
|
{}
|
87
95
|
end
|
@@ -3,35 +3,30 @@ require "active_record/attribute"
|
|
3
3
|
module ActiveRecord
|
4
4
|
class AttributeSet # :nodoc:
|
5
5
|
class Builder # :nodoc:
|
6
|
-
attr_reader :types, :
|
6
|
+
attr_reader :types, :default_attributes
|
7
7
|
|
8
|
-
def initialize(types,
|
8
|
+
def initialize(types, default_attributes = {})
|
9
9
|
@types = types
|
10
|
-
@
|
11
|
-
@default = default
|
10
|
+
@default_attributes = default_attributes
|
12
11
|
end
|
13
12
|
|
14
13
|
def build_from_database(values = {}, additional_types = {})
|
15
|
-
|
16
|
-
values[always_initialized] = nil
|
17
|
-
end
|
18
|
-
|
19
|
-
attributes = LazyAttributeHash.new(types, values, additional_types, &default)
|
14
|
+
attributes = LazyAttributeHash.new(types, values, additional_types, default_attributes)
|
20
15
|
AttributeSet.new(attributes)
|
21
16
|
end
|
22
17
|
end
|
23
18
|
end
|
24
19
|
|
25
20
|
class LazyAttributeHash # :nodoc:
|
26
|
-
delegate :transform_values, :each_key, :each_value, :fetch, to: :materialize
|
21
|
+
delegate :transform_values, :each_key, :each_value, :fetch, :except, to: :materialize
|
27
22
|
|
28
|
-
def initialize(types, values, additional_types,
|
23
|
+
def initialize(types, values, additional_types, default_attributes, delegate_hash = {})
|
29
24
|
@types = types
|
30
25
|
@values = values
|
31
26
|
@additional_types = additional_types
|
32
27
|
@materialized = false
|
33
|
-
@delegate_hash =
|
34
|
-
@
|
28
|
+
@delegate_hash = delegate_hash
|
29
|
+
@default_attributes = default_attributes
|
35
30
|
end
|
36
31
|
|
37
32
|
def key?(key)
|
@@ -79,22 +74,24 @@ module ActiveRecord
|
|
79
74
|
end
|
80
75
|
|
81
76
|
def marshal_dump
|
82
|
-
|
77
|
+
[@types, @values, @additional_types, @default_attributes, @delegate_hash]
|
83
78
|
end
|
84
79
|
|
85
|
-
def marshal_load(
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
80
|
+
def marshal_load(values)
|
81
|
+
if values.is_a?(Hash)
|
82
|
+
empty_hash = {}.freeze
|
83
|
+
initialize(empty_hash, empty_hash, empty_hash, empty_hash, values)
|
84
|
+
@materialized = true
|
85
|
+
else
|
86
|
+
initialize(*values)
|
87
|
+
end
|
91
88
|
end
|
92
89
|
|
93
90
|
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
94
91
|
# Workaround for Ruby 2.2 "private attribute?" warning.
|
95
92
|
protected
|
96
93
|
|
97
|
-
attr_reader :types, :values, :additional_types, :delegate_hash, :
|
94
|
+
attr_reader :types, :values, :additional_types, :delegate_hash, :default_attributes
|
98
95
|
|
99
96
|
def materialize
|
100
97
|
unless @materialized
|
@@ -117,7 +114,12 @@ module ActiveRecord
|
|
117
114
|
if value_present
|
118
115
|
delegate_hash[name] = Attribute.from_database(name, value, type)
|
119
116
|
elsif types.key?(name)
|
120
|
-
|
117
|
+
attr = default_attributes[name]
|
118
|
+
if attr
|
119
|
+
delegate_hash[name] = attr.dup
|
120
|
+
else
|
121
|
+
delegate_hash[name] = Attribute.uninitialized(name, type)
|
122
|
+
end
|
121
123
|
end
|
122
124
|
end
|
123
125
|
end
|
@@ -3,7 +3,7 @@ require "active_record/attribute_set/yaml_encoder"
|
|
3
3
|
|
4
4
|
module ActiveRecord
|
5
5
|
class AttributeSet # :nodoc:
|
6
|
-
delegate :each_value, :fetch, to: :attributes
|
6
|
+
delegate :each_value, :fetch, :except, to: :attributes
|
7
7
|
|
8
8
|
def initialize(attributes)
|
9
9
|
@attributes = attributes
|
@@ -56,7 +56,7 @@ module ActiveRecord
|
|
56
56
|
# store_listing = StoreListing.new(price_in_cents: '10.1')
|
57
57
|
#
|
58
58
|
# # before
|
59
|
-
# store_listing.price_in_cents # => BigDecimal
|
59
|
+
# store_listing.price_in_cents # => BigDecimal(10.1)
|
60
60
|
#
|
61
61
|
# class StoreListing < ActiveRecord::Base
|
62
62
|
# attribute :price_in_cents, :integer
|
@@ -152,7 +152,8 @@ module ActiveRecord
|
|
152
152
|
end
|
153
153
|
|
154
154
|
def quoted_time(value) # :nodoc:
|
155
|
-
|
155
|
+
value = value.change(year: 2000, month: 1, day: 1)
|
156
|
+
quoted_date(value).sub(/\A\d\d\d\d-\d\d-\d\d /, "")
|
156
157
|
end
|
157
158
|
|
158
159
|
def quoted_binary(value) # :nodoc:
|
@@ -873,15 +873,25 @@ module ActiveRecord
|
|
873
873
|
end
|
874
874
|
|
875
875
|
def mismatched_foreign_key(message)
|
876
|
-
|
877
|
-
|
878
|
-
|
876
|
+
match = %r/
|
877
|
+
(?:CREATE|ALTER)\s+TABLE\s*(?:`?\w+`?\.)?`?(?<table>\w+)`?.+?
|
878
|
+
FOREIGN\s+KEY\s*\(`?(?<foreign_key>\w+)`?\)\s*
|
879
|
+
REFERENCES\s*(`?(?<target_table>\w+)`?)\s*\(`?(?<primary_key>\w+)`?\)
|
880
|
+
/xmi.match(message)
|
881
|
+
|
882
|
+
options = {
|
879
883
|
message: message,
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
884
|
+
}
|
885
|
+
|
886
|
+
if match
|
887
|
+
options[:table] = match[:table]
|
888
|
+
options[:foreign_key] = match[:foreign_key]
|
889
|
+
options[:target_table] = match[:target_table]
|
890
|
+
options[:primary_key] = match[:primary_key]
|
891
|
+
options[:primary_key_column] = column_for(match[:target_table], match[:primary_key])
|
892
|
+
end
|
893
|
+
|
894
|
+
MismatchedForeignKey.new(options)
|
885
895
|
end
|
886
896
|
|
887
897
|
def integer_to_sql(limit) # :nodoc:
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require "active_record/connection_adapters/abstract_mysql_adapter"
|
2
2
|
require "active_record/connection_adapters/mysql/database_statements"
|
3
3
|
|
4
|
-
gem "mysql2", ">= 0.3.18", "< 0.
|
4
|
+
gem "mysql2", ">= 0.3.18", "< 0.6.0"
|
5
5
|
require "mysql2"
|
6
6
|
raise "mysql2 0.4.3 is not supported. Please upgrade to 0.4.4+" if Mysql2::VERSION == "0.4.3"
|
7
7
|
|
@@ -31,7 +31,13 @@ module ActiveRecord
|
|
31
31
|
|
32
32
|
def cast(value)
|
33
33
|
if value.is_a?(::String)
|
34
|
-
value =
|
34
|
+
value = begin
|
35
|
+
@pg_decoder.decode(value)
|
36
|
+
rescue TypeError
|
37
|
+
# malformed array string is treated as [], will raise in PG 2.0 gem
|
38
|
+
# this keeps a consistent implementation
|
39
|
+
[]
|
40
|
+
end
|
35
41
|
end
|
36
42
|
type_cast_array(value, :cast)
|
37
43
|
end
|
@@ -64,6 +70,10 @@ module ActiveRecord
|
|
64
70
|
deserialize(raw_old_value) != new_value
|
65
71
|
end
|
66
72
|
|
73
|
+
def force_equality?(value)
|
74
|
+
value.is_a?(::Array)
|
75
|
+
end
|
76
|
+
|
67
77
|
private
|
68
78
|
|
69
79
|
def type_cast_array(value, method)
|
@@ -122,7 +122,7 @@ module ActiveRecord
|
|
122
122
|
comment = row[5]
|
123
123
|
opclass = row[6]
|
124
124
|
|
125
|
-
using, expressions, where = inddef.scan(/ USING (\w+?) \((.+?)\)(?: WHERE (.+))?\z/).flatten
|
125
|
+
using, expressions, where = inddef.scan(/ USING (\w+?) \((.+?)\)(?: WHERE (.+))?\z/m).flatten
|
126
126
|
|
127
127
|
if indkey.include?(0) || opclass > 0
|
128
128
|
columns = expressions
|
@@ -2,6 +2,14 @@
|
|
2
2
|
gem "pg", ">= 0.18", "< 2.0"
|
3
3
|
require "pg"
|
4
4
|
|
5
|
+
# Use async_exec instead of exec_params on pg versions before 1.1
|
6
|
+
class ::PG::Connection
|
7
|
+
unless self.public_method_defined?(:async_exec_params)
|
8
|
+
remove_method :exec_params
|
9
|
+
alias exec_params async_exec
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
5
13
|
require "active_record/connection_adapters/abstract_adapter"
|
6
14
|
require "active_record/connection_adapters/statement_pool"
|
7
15
|
require "active_record/connection_adapters/postgresql/column"
|
@@ -613,7 +621,7 @@ module ActiveRecord
|
|
613
621
|
type_casted_binds = type_casted_binds(binds)
|
614
622
|
log(sql, name, binds, type_casted_binds) do
|
615
623
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
616
|
-
@connection.
|
624
|
+
@connection.exec_params(sql, type_casted_binds)
|
617
625
|
end
|
618
626
|
end
|
619
627
|
end
|
@@ -7,7 +7,7 @@ require "active_record/connection_adapters/sqlite3/schema_definitions"
|
|
7
7
|
require "active_record/connection_adapters/sqlite3/schema_dumper"
|
8
8
|
require "active_record/connection_adapters/sqlite3/schema_statements"
|
9
9
|
|
10
|
-
gem "sqlite3", "~> 1.3.6"
|
10
|
+
gem "sqlite3", "~> 1.3", ">= 1.3.6"
|
11
11
|
require "sqlite3"
|
12
12
|
|
13
13
|
module ActiveRecord
|
@@ -45,8 +45,12 @@ module ActiveRecord
|
|
45
45
|
reflection = child_class._reflections.values.find { |e| e.belongs_to? && e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? }
|
46
46
|
counter_name = reflection.counter_cache_column
|
47
47
|
|
48
|
-
updates = { counter_name
|
49
|
-
|
48
|
+
updates = { counter_name => object.send(counter_association).count(:all) }
|
49
|
+
|
50
|
+
if touch
|
51
|
+
names = touch if touch != true
|
52
|
+
updates.merge!(touch_attributes_with_time(*names))
|
53
|
+
end
|
50
54
|
|
51
55
|
unscoped.where(primary_key => object.id).update_all(updates)
|
52
56
|
end
|
@@ -66,8 +70,8 @@ module ActiveRecord
|
|
66
70
|
# * +counters+ - A Hash containing the names of the fields
|
67
71
|
# to update as keys and the amount to update the field by as values.
|
68
72
|
# * <tt>:touch</tt> option - Touch timestamp columns when updating.
|
69
|
-
#
|
70
|
-
#
|
73
|
+
# If attribute names are passed, they are updated along with updated_at/on
|
74
|
+
# attributes.
|
71
75
|
#
|
72
76
|
# ==== Examples
|
73
77
|
#
|
@@ -105,7 +109,8 @@ module ActiveRecord
|
|
105
109
|
end
|
106
110
|
|
107
111
|
if touch
|
108
|
-
|
112
|
+
names = touch if touch != true
|
113
|
+
touch_updates = touch_attributes_with_time(*names)
|
109
114
|
updates << sanitize_sql_for_assignment(touch_updates) unless touch_updates.empty?
|
110
115
|
end
|
111
116
|
|
@@ -163,13 +168,6 @@ module ActiveRecord
|
|
163
168
|
def decrement_counter(counter_name, id, touch: nil)
|
164
169
|
update_counters(id, counter_name => -1, touch: touch)
|
165
170
|
end
|
166
|
-
|
167
|
-
private
|
168
|
-
def touch_updates(touch)
|
169
|
-
touch = timestamp_attributes_for_update_in_model if touch == true
|
170
|
-
touch_time = current_time_from_proper_timezone
|
171
|
-
Array(touch).map { |column| [ column, touch_time ] }.to_h
|
172
|
-
end
|
173
171
|
end
|
174
172
|
|
175
173
|
private
|
data/lib/active_record/errors.rb
CHANGED
@@ -115,16 +115,27 @@ module ActiveRecord
|
|
115
115
|
|
116
116
|
# Raised when a foreign key constraint cannot be added because the column type does not match the referenced column type.
|
117
117
|
class MismatchedForeignKey < StatementInvalid
|
118
|
-
def initialize(
|
119
|
-
|
118
|
+
def initialize(
|
119
|
+
adapter = nil,
|
120
|
+
message: nil,
|
121
|
+
sql: nil,
|
122
|
+
binds: nil,
|
123
|
+
table: nil,
|
124
|
+
foreign_key: nil,
|
125
|
+
target_table: nil,
|
126
|
+
primary_key: nil,
|
127
|
+
primary_key_column: nil
|
128
|
+
)
|
120
129
|
if table
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
130
|
+
type = primary_key_column.bigint? ? :bigint : primary_key_column.type
|
131
|
+
msg = <<-EOM.squish
|
132
|
+
Column `#{foreign_key}` on table `#{table}` does not match column `#{primary_key}` on `#{target_table}`,
|
133
|
+
which has type `#{primary_key_column.sql_type}`.
|
134
|
+
To resolve this issue, change the type of the `#{foreign_key}` column on `#{table}` to be :#{type}.
|
135
|
+
(For example `t.#{type} :#{foreign_key}`).
|
125
136
|
EOM
|
126
137
|
else
|
127
|
-
msg = <<-EOM
|
138
|
+
msg = <<-EOM.squish
|
128
139
|
There is a mismatch between the foreign key and primary key column types.
|
129
140
|
Verify that the foreign key column type and the primary key of the associated table match types.
|
130
141
|
EOM
|
@@ -134,11 +145,6 @@ module ActiveRecord
|
|
134
145
|
end
|
135
146
|
super(msg)
|
136
147
|
end
|
137
|
-
|
138
|
-
private
|
139
|
-
def column_type(table, column)
|
140
|
-
@adapter.columns(table).detect { |c| c.name == column }.sql_type
|
141
|
-
end
|
142
148
|
end
|
143
149
|
|
144
150
|
# Raised when a record cannot be inserted or updated because it would violate a not null constraint.
|
@@ -60,13 +60,6 @@ module ActiveRecord
|
|
60
60
|
end
|
61
61
|
|
62
62
|
private
|
63
|
-
|
64
|
-
def increment_lock
|
65
|
-
lock_col = self.class.locking_column
|
66
|
-
previous_lock_value = send(lock_col).to_i
|
67
|
-
send(lock_col + "=", previous_lock_value + 1)
|
68
|
-
end
|
69
|
-
|
70
63
|
def _create_record(attribute_names = self.attribute_names, *)
|
71
64
|
if locking_enabled?
|
72
65
|
# We always want to persist the locking version, even if we don't detect
|
@@ -76,39 +69,37 @@ module ActiveRecord
|
|
76
69
|
super
|
77
70
|
end
|
78
71
|
|
79
|
-
def
|
72
|
+
def _touch_row(attribute_names, time)
|
73
|
+
super
|
74
|
+
ensure
|
75
|
+
clear_attribute_change(self.class.locking_column) if locking_enabled?
|
76
|
+
end
|
77
|
+
|
78
|
+
def _update_row(attribute_names, attempted_action = "update")
|
80
79
|
return super unless locking_enabled?
|
81
|
-
return 0 if attribute_names.empty?
|
82
80
|
|
83
81
|
begin
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
increment_lock
|
89
|
-
|
90
|
-
attribute_names.push(lock_col)
|
82
|
+
locking_column = self.class.locking_column
|
83
|
+
previous_lock_value = read_attribute_before_type_cast(locking_column)
|
84
|
+
attribute_names << locking_column
|
91
85
|
|
92
|
-
|
86
|
+
self[locking_column] += 1
|
93
87
|
|
94
|
-
affected_rows =
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
attributes_for_update(attribute_names).map do |name|
|
99
|
-
[name, _read_attribute(name)]
|
100
|
-
end.to_h
|
88
|
+
affected_rows = self.class.unscoped._update_record(
|
89
|
+
arel_attributes_with_values(attribute_names),
|
90
|
+
self.class.primary_key => id_in_database,
|
91
|
+
locking_column => previous_lock_value
|
101
92
|
)
|
102
93
|
|
103
|
-
|
104
|
-
raise ActiveRecord::StaleObjectError.new(self,
|
94
|
+
if affected_rows != 1
|
95
|
+
raise ActiveRecord::StaleObjectError.new(self, attempted_action)
|
105
96
|
end
|
106
97
|
|
107
98
|
affected_rows
|
108
99
|
|
109
100
|
# If something went wrong, revert the locking_column value.
|
110
101
|
rescue Exception
|
111
|
-
|
102
|
+
self[locking_column] = previous_lock_value.to_i
|
112
103
|
raise
|
113
104
|
end
|
114
105
|
end
|
@@ -128,7 +119,7 @@ module ActiveRecord
|
|
128
119
|
|
129
120
|
if locking_enabled?
|
130
121
|
locking_column = self.class.locking_column
|
131
|
-
relation = relation.where(locking_column =>
|
122
|
+
relation = relation.where(locking_column => read_attribute_before_type_cast(locking_column))
|
132
123
|
end
|
133
124
|
|
134
125
|
relation
|
@@ -332,11 +332,11 @@ module ActiveRecord
|
|
332
332
|
end
|
333
333
|
|
334
334
|
def attributes_builder # :nodoc:
|
335
|
-
@attributes_builder
|
336
|
-
|
337
|
-
|
338
|
-
end
|
335
|
+
unless defined?(@attributes_builder) && @attributes_builder
|
336
|
+
defaults = _default_attributes.except(*(column_names - [primary_key]))
|
337
|
+
@attributes_builder = AttributeSet::Builder.new(attribute_types, defaults)
|
339
338
|
end
|
339
|
+
@attributes_builder
|
340
340
|
end
|
341
341
|
|
342
342
|
def columns_hash # :nodoc:
|
@@ -381,7 +381,7 @@ module ActiveRecord
|
|
381
381
|
# default values when instantiating the Active Record object for this table.
|
382
382
|
def column_defaults
|
383
383
|
load_schema
|
384
|
-
_default_attributes.to_hash
|
384
|
+
_default_attributes.deep_dup.to_hash
|
385
385
|
end
|
386
386
|
|
387
387
|
def _default_attributes # :nodoc:
|
@@ -226,7 +226,8 @@ module ActiveRecord
|
|
226
226
|
def becomes(klass)
|
227
227
|
became = klass.new
|
228
228
|
became.instance_variable_set("@attributes", @attributes)
|
229
|
-
became.instance_variable_set("@mutation_tracker", @mutation_tracker
|
229
|
+
became.instance_variable_set("@mutation_tracker", @mutation_tracker ||= nil)
|
230
|
+
became.instance_variable_set("@mutations_from_database", @mutations_from_database ||= nil)
|
230
231
|
became.instance_variable_set("@changed_attributes", attributes_changed_by_setter)
|
231
232
|
became.instance_variable_set("@new_record", new_record?)
|
232
233
|
became.instance_variable_set("@destroyed", destroyed?)
|
@@ -505,36 +506,12 @@ module ActiveRecord
|
|
505
506
|
MSG
|
506
507
|
end
|
507
508
|
|
508
|
-
|
509
|
-
|
510
|
-
attributes.concat(names)
|
511
|
-
|
512
|
-
unless attributes.empty?
|
513
|
-
changes = {}
|
514
|
-
|
515
|
-
attributes.each do |column|
|
516
|
-
column = column.to_s
|
517
|
-
changes[column] = write_attribute(column, time)
|
518
|
-
end
|
519
|
-
|
520
|
-
primary_key = self.class.primary_key
|
521
|
-
scope = self.class.unscoped.where(primary_key => _read_attribute(primary_key))
|
522
|
-
|
523
|
-
if locking_enabled?
|
524
|
-
locking_column = self.class.locking_column
|
525
|
-
scope = scope.where(locking_column => _read_attribute(locking_column))
|
526
|
-
changes[locking_column] = increment_lock
|
527
|
-
end
|
528
|
-
|
529
|
-
clear_attribute_changes(changes.keys)
|
530
|
-
result = scope.update_all(changes) == 1
|
531
|
-
|
532
|
-
if !result && locking_enabled?
|
533
|
-
raise ActiveRecord::StaleObjectError.new(self, "touch")
|
534
|
-
end
|
509
|
+
attribute_names = timestamp_attributes_for_update_in_model
|
510
|
+
attribute_names |= names.map(&:to_s)
|
535
511
|
|
536
|
-
|
537
|
-
|
512
|
+
unless attribute_names.empty?
|
513
|
+
affected_rows = _touch_row(attribute_names, time)
|
514
|
+
@_trigger_update_callback = affected_rows == 1
|
538
515
|
else
|
539
516
|
true
|
540
517
|
end
|
@@ -554,6 +531,24 @@ module ActiveRecord
|
|
554
531
|
self.class.unscoped.where(self.class.primary_key => id)
|
555
532
|
end
|
556
533
|
|
534
|
+
def _touch_row(attribute_names, time)
|
535
|
+
time ||= current_time_from_proper_timezone
|
536
|
+
|
537
|
+
attribute_names.each do |attr_name|
|
538
|
+
write_attribute(attr_name, time)
|
539
|
+
clear_attribute_change(attr_name)
|
540
|
+
end
|
541
|
+
|
542
|
+
_update_row(attribute_names, "touch")
|
543
|
+
end
|
544
|
+
|
545
|
+
def _update_row(attribute_names, attempted_action = "update")
|
546
|
+
self.class.unscoped._update_record(
|
547
|
+
arel_attributes_with_values(attribute_names),
|
548
|
+
self.class.primary_key => id_in_database
|
549
|
+
)
|
550
|
+
end
|
551
|
+
|
557
552
|
def create_or_update(*args, &block)
|
558
553
|
_raise_readonly_record_error if readonly?
|
559
554
|
result = new_record? ? _create_record(&block) : _update_record(*args, &block)
|
@@ -563,23 +558,26 @@ module ActiveRecord
|
|
563
558
|
# Updates the associated record with values matching those of the instance attributes.
|
564
559
|
# Returns the number of affected rows.
|
565
560
|
def _update_record(attribute_names = self.attribute_names)
|
566
|
-
|
567
|
-
|
568
|
-
|
561
|
+
attribute_names &= self.class.column_names
|
562
|
+
attribute_names = attributes_for_update(attribute_names)
|
563
|
+
|
564
|
+
if attribute_names.empty?
|
565
|
+
affected_rows = 0
|
569
566
|
@_trigger_update_callback = true
|
570
567
|
else
|
571
|
-
|
572
|
-
@_trigger_update_callback =
|
568
|
+
affected_rows = _update_row(attribute_names)
|
569
|
+
@_trigger_update_callback = affected_rows == 1
|
573
570
|
end
|
574
571
|
|
575
572
|
yield(self) if block_given?
|
576
573
|
|
577
|
-
|
574
|
+
affected_rows
|
578
575
|
end
|
579
576
|
|
580
577
|
# Creates a record with values matching those of the instance attributes
|
581
578
|
# and returns its id.
|
582
579
|
def _create_record(attribute_names = self.attribute_names)
|
580
|
+
attribute_names &= self.class.column_names
|
583
581
|
attributes_values = arel_attributes_with_values_for_create(attribute_names)
|
584
582
|
|
585
583
|
new_id = self.class.unscoped.insert attributes_values
|
@@ -5,20 +5,20 @@ module ActiveRecord
|
|
5
5
|
# Enable the query cache within the block if Active Record is configured.
|
6
6
|
# If it's not, it will execute the given block.
|
7
7
|
def cache(&block)
|
8
|
-
if configurations.empty?
|
9
|
-
yield
|
10
|
-
else
|
8
|
+
if connected? || !configurations.empty?
|
11
9
|
connection.cache(&block)
|
10
|
+
else
|
11
|
+
yield
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
15
|
# Disable the query cache within the block if Active Record is configured.
|
16
16
|
# If it's not, it will execute the given block.
|
17
17
|
def uncached(&block)
|
18
|
-
if configurations.empty?
|
19
|
-
yield
|
20
|
-
else
|
18
|
+
if connected? || !configurations.empty?
|
21
19
|
connection.uncached(&block)
|
20
|
+
else
|
21
|
+
yield
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
@@ -112,7 +112,7 @@ module ActiveRecord
|
|
112
112
|
if has_include?(column_name)
|
113
113
|
relation = construct_relation_for_association_calculations
|
114
114
|
|
115
|
-
if operation.to_s.downcase == "count"
|
115
|
+
if operation.to_s.downcase == "count"
|
116
116
|
relation.distinct!
|
117
117
|
# PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
|
118
118
|
if (column_name == :all || column_name.nil?) && select_values.empty?
|
@@ -379,7 +379,7 @@ module ActiveRecord
|
|
379
379
|
|
380
380
|
case conditions
|
381
381
|
when Array, Hash
|
382
|
-
relation.where!(conditions)
|
382
|
+
relation.where!(conditions) unless conditions.empty?
|
383
383
|
else
|
384
384
|
relation.where!(primary_key => conditions) unless conditions == :none
|
385
385
|
end
|
@@ -429,7 +429,7 @@ module ActiveRecord
|
|
429
429
|
raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
|
430
430
|
|
431
431
|
expects_array = ids.first.kind_of?(Array)
|
432
|
-
return
|
432
|
+
return [] if expects_array && ids.first.empty?
|
433
433
|
|
434
434
|
ids = ids.flatten.compact.uniq
|
435
435
|
|
@@ -95,7 +95,7 @@ module ActiveRecord
|
|
95
95
|
next
|
96
96
|
when value.is_a?(Relation)
|
97
97
|
binds += value.bound_attributes
|
98
|
-
when value.is_a?(Range) && !table.type(column_name).
|
98
|
+
when value.is_a?(Range) && !table.type(column_name).force_equality?(value)
|
99
99
|
first = value.begin
|
100
100
|
last = value.end
|
101
101
|
unless first.respond_to?(:infinite?) && first.infinite?
|
@@ -158,7 +158,7 @@ module ActiveRecord
|
|
158
158
|
return if table.associated_with?(column_name)
|
159
159
|
case value
|
160
160
|
when Array, Range
|
161
|
-
table.type(column_name).
|
161
|
+
table.type(column_name).force_equality?(value)
|
162
162
|
else
|
163
163
|
!value.nil? && handler_for(value).is_a?(BasicObjectHandler)
|
164
164
|
end
|
@@ -1079,7 +1079,7 @@ module ActiveRecord
|
|
1079
1079
|
end
|
1080
1080
|
o.split(",").map! do |s|
|
1081
1081
|
s.strip!
|
1082
|
-
s.gsub!(/\sasc\Z/i, " DESC") || s.gsub!(/\sdesc\Z/i, " ASC") || s
|
1082
|
+
s.gsub!(/\sasc\Z/i, " DESC") || s.gsub!(/\sdesc\Z/i, " ASC") || (s << " DESC")
|
1083
1083
|
end
|
1084
1084
|
else
|
1085
1085
|
o
|
@@ -67,7 +67,7 @@ module ActiveRecord
|
|
67
67
|
binds)
|
68
68
|
end
|
69
69
|
|
70
|
-
def _update_record(values,
|
70
|
+
def _update_record(values, constraints) # :nodoc:
|
71
71
|
substitutes, binds = substitute_values values
|
72
72
|
|
73
73
|
scope = @klass.unscoped
|
@@ -76,7 +76,7 @@ module ActiveRecord
|
|
76
76
|
scope.unscope!(where: @klass.inheritance_column)
|
77
77
|
end
|
78
78
|
|
79
|
-
relation = scope.where(
|
79
|
+
relation = scope.where(constraints)
|
80
80
|
bvs = binds + relation.bound_attributes
|
81
81
|
um = relation
|
82
82
|
.arel
|
@@ -120,7 +120,7 @@ module ActiveRecord
|
|
120
120
|
$stderr.puts "Database '#{configuration['database']}' already exists"
|
121
121
|
rescue Exception => error
|
122
122
|
$stderr.puts error
|
123
|
-
$stderr.puts "Couldn't create database
|
123
|
+
$stderr.puts "Couldn't create '#{configuration['database']}' database. Please check your configuration."
|
124
124
|
raise
|
125
125
|
end
|
126
126
|
|
@@ -53,6 +53,13 @@ module ActiveRecord
|
|
53
53
|
end
|
54
54
|
|
55
55
|
class_methods do
|
56
|
+
def touch_attributes_with_time(*names, time: nil)
|
57
|
+
attribute_names = timestamp_attributes_for_update_in_model
|
58
|
+
attribute_names |= names.map(&:to_s)
|
59
|
+
time ||= current_time_from_proper_timezone
|
60
|
+
attribute_names.each_with_object({}) { |attr_name, result| result[attr_name] = time }
|
61
|
+
end
|
62
|
+
|
56
63
|
private
|
57
64
|
def timestamp_attributes_for_create_in_model
|
58
65
|
timestamp_attributes_for_create.select { |c| column_names.include?(c) }
|
@@ -17,7 +17,7 @@ module ActiveRecord
|
|
17
17
|
relation = build_relation(finder_class, attribute, value)
|
18
18
|
if record.persisted?
|
19
19
|
if finder_class.primary_key
|
20
|
-
relation = relation.where.not(finder_class.primary_key => record.id_in_database
|
20
|
+
relation = relation.where.not(finder_class.primary_key => record.id_in_database)
|
21
21
|
else
|
22
22
|
raise UnknownPrimaryKey.new(finder_class, "Can not validate uniqueness for persisted record without primary key.")
|
23
23
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.1.
|
4
|
+
version: 5.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-03-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 5.1.
|
19
|
+
version: 5.1.7
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 5.1.
|
26
|
+
version: 5.1.7
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activemodel
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 5.1.
|
33
|
+
version: 5.1.7
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 5.1.
|
40
|
+
version: 5.1.7
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: arel
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -320,8 +320,8 @@ homepage: http://rubyonrails.org
|
|
320
320
|
licenses:
|
321
321
|
- MIT
|
322
322
|
metadata:
|
323
|
-
source_code_uri: https://github.com/rails/rails/tree/v5.1.
|
324
|
-
changelog_uri: https://github.com/rails/rails/blob/v5.1.
|
323
|
+
source_code_uri: https://github.com/rails/rails/tree/v5.1.7/activerecord
|
324
|
+
changelog_uri: https://github.com/rails/rails/blob/v5.1.7/activerecord/CHANGELOG.md
|
325
325
|
post_install_message:
|
326
326
|
rdoc_options:
|
327
327
|
- "--main"
|
@@ -339,8 +339,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
339
339
|
- !ruby/object:Gem::Version
|
340
340
|
version: '0'
|
341
341
|
requirements: []
|
342
|
-
|
343
|
-
rubygems_version: 2.7.3
|
342
|
+
rubygems_version: 3.0.1
|
344
343
|
signing_key:
|
345
344
|
specification_version: 4
|
346
345
|
summary: Object-relational mapper framework (part of Rails).
|