activerecord 6.1.2 → 6.1.4

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.

Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +180 -2
  3. data/lib/active_record/associations/association.rb +7 -1
  4. data/lib/active_record/associations/belongs_to_association.rb +1 -2
  5. data/lib/active_record/coders/yaml_column.rb +11 -1
  6. data/lib/active_record/connection_adapters.rb +2 -0
  7. data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -1
  8. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +1 -1
  9. data/lib/active_record/connection_adapters/abstract/transaction.rb +14 -3
  10. data/lib/active_record/connection_adapters/abstract_adapter.rb +5 -5
  11. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +10 -6
  12. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +6 -2
  13. data/lib/active_record/connection_adapters/mysql/quoting.rb +17 -2
  14. data/lib/active_record/connection_adapters/pool_manager.rb +5 -1
  15. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  16. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -5
  17. data/lib/active_record/connection_adapters/schema_cache.rb +9 -1
  18. data/lib/active_record/connection_adapters/sql_type_metadata.rb +0 -2
  19. data/lib/active_record/connection_handling.rb +9 -9
  20. data/lib/active_record/core.rb +16 -5
  21. data/lib/active_record/enum.rb +4 -6
  22. data/lib/active_record/fixtures.rb +1 -1
  23. data/lib/active_record/gem_version.rb +1 -1
  24. data/lib/active_record/insert_all.rb +5 -1
  25. data/lib/active_record/migration.rb +1 -1
  26. data/lib/active_record/model_schema.rb +4 -4
  27. data/lib/active_record/railties/databases.rake +3 -2
  28. data/lib/active_record/relation.rb +10 -17
  29. data/lib/active_record/relation/calculations.rb +6 -2
  30. data/lib/active_record/relation/finder_methods.rb +1 -1
  31. data/lib/active_record/relation/predicate_builder.rb +3 -1
  32. data/lib/active_record/relation/query_methods.rb +1 -1
  33. data/lib/active_record/relation/where_clause.rb +17 -14
  34. data/lib/active_record/scoping/default.rb +1 -3
  35. data/lib/active_record/statement_cache.rb +2 -2
  36. data/lib/active_record/test_fixtures.rb +42 -1
  37. data/lib/active_record/validations/numericality.rb +1 -1
  38. data/lib/arel/collectors/bind.rb +2 -2
  39. data/lib/arel/collectors/composite.rb +3 -3
  40. data/lib/arel/collectors/sql_string.rb +1 -1
  41. data/lib/arel/collectors/substitute_binds.rb +1 -1
  42. data/lib/arel/nodes/homogeneous_in.rb +4 -0
  43. data/lib/arel/predications.rb +2 -2
  44. data/lib/arel/visitors/to_sql.rb +1 -1
  45. metadata +13 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4112bd4b4d7a00b26db10332f2f6452d2b6ad1fdf3f2ad50988a8229abac9192
4
- data.tar.gz: 6fbcb021ae1942e307730ef7aaad54d1f594cd52b749d407f8aafe052bee6794
3
+ metadata.gz: 8533ac44f34eb20fbdc7d86aeef22c966a16ebe23e157db652a5bc1d6551429a
4
+ data.tar.gz: 2fe7a2768e779b4b5cd02f9da33231392199313c9acd4a2600a7b10f253ac7bd
5
5
  SHA512:
6
- metadata.gz: eb1830fe0587253ecede381d53dd0be5c8de80070559458653d4a6e149c002a03a3ba37a8723e0e869693500b55ec9956f9f18d2d556884f40d28ac9af0e34f6
7
- data.tar.gz: d78aeab68b5c4d4d0e2d8a315b7175a0257b6e1bb6db82c1ae04551f44540d72ffd122881af9cfb93cf8c0d8d57b6310a5bd303e612e24795f54fc07b777f307
6
+ metadata.gz: e65080023ad359f9782e8c9f40437e0fb961b285cbe9e9ecb8efb8155defd814470a774ef086b5b9911de1c60cb7aa04e4f0006cdaa361344dfb41627f2a3fd3
7
+ data.tar.gz: 3c7e9ac5eea68d2e2ed2d4c6bc6a49f59b026682da56a695426454e20b6f4d25bb1d1dec4ecf651fbf42bce7231cf97a2cbf45751632471ffb7ffe3a6382a460
data/CHANGELOG.md CHANGED
@@ -1,3 +1,181 @@
1
+ ## Rails 6.1.4 (June 24, 2021) ##
2
+
3
+ * Do not try to rollback transactions that failed due to a `ActiveRecord::TransactionRollbackError`.
4
+
5
+ *Jamie McCarthy*
6
+
7
+ * Raise an error if `pool_config` is `nil` in `set_pool_config`.
8
+
9
+ *Eileen M. Uchitelle*
10
+
11
+ * Fix compatibility with `psych >= 4`.
12
+
13
+ Starting in Psych 4.0.0 `YAML.load` behaves like `YAML.safe_load`. To preserve compatibility
14
+ Active Record's schema cache loader and `YAMLColumn` now uses `YAML.unsafe_load` if available.
15
+
16
+ *Jean Boussier*
17
+
18
+ * Support using replicas when using `rails dbconsole`.
19
+
20
+ *Christopher Thornton*
21
+
22
+ * Restore connection pools after transactional tests.
23
+
24
+ *Eugene Kenny*
25
+
26
+ * Change `upsert_all` to fails cleanly for MySQL when `:unique_by` is used.
27
+
28
+ *Bastian Bartmann*
29
+
30
+ * Fix user-defined `self.default_scope` to respect table alias.
31
+
32
+ *Ryuta Kamizono*
33
+
34
+ * Clear `@cache_keys` cache after `update_all`, `delete_all`, `destroy_all`.
35
+
36
+ *Ryuta Kamizono*
37
+
38
+ * Changed Arel predications `contains` and `overlaps` to use
39
+ `quoted_node` so that PostgreSQL arrays are quoted properly.
40
+
41
+ *Bradley Priest*
42
+
43
+ * Fix `merge` when the `where` clauses have string contents.
44
+
45
+ *Ryuta Kamizono*
46
+
47
+ * Fix rollback of parent destruction with nested `dependent: :destroy`.
48
+
49
+ *Jacopo Beschi*
50
+
51
+ * Fix binds logging for `"WHERE ... IN ..."` statements.
52
+
53
+ *Ricardo Díaz*
54
+
55
+ * Handle `false` in relation strict loading checks.
56
+
57
+ Previously when a model had strict loading set to true and then had a
58
+ relation set `strict_loading` to false the false wasn't considered when
59
+ deciding whether to raise/warn about strict loading.
60
+
61
+ ```
62
+ class Dog < ActiveRecord::Base
63
+ self.strict_loading_by_default = true
64
+
65
+ has_many :treats, strict_loading: false
66
+ end
67
+ ```
68
+
69
+ In the example, `dog.treats` would still raise even though
70
+ `strict_loading` was set to false. This is a bug effecting more than
71
+ Active Storage which is why I made this PR superceeding #41461. We need
72
+ to fix this for all applications since the behavior is a little
73
+ surprising. I took the test from ##41461 and the code suggestion from #41453
74
+ with some additions.
75
+
76
+ *Eileen M. Uchitelle*, *Radamés Roriz*
77
+
78
+ * Fix numericality validator without precision.
79
+
80
+ *Ryuta Kamizono*
81
+
82
+ * Fix aggregate attribute on Enum types.
83
+
84
+ *Ryuta Kamizono*
85
+
86
+ * Fix `CREATE INDEX` statement generation for PostgreSQL.
87
+
88
+ *eltongo*
89
+
90
+ * Fix where clause on enum attribute when providing array of strings.
91
+
92
+ *Ryuta Kamizono*
93
+
94
+ * Fix `unprepared_statement` to work it when nesting.
95
+
96
+ *Ryuta Kamizono*
97
+
98
+
99
+ ## Rails 6.1.3.2 (May 05, 2021) ##
100
+
101
+ * No changes.
102
+
103
+
104
+ ## Rails 6.1.3.1 (March 26, 2021) ##
105
+
106
+ * No changes.
107
+
108
+
109
+ ## Rails 6.1.3 (February 17, 2021) ##
110
+
111
+ * Fix the MySQL adapter to always set the right collation and charset
112
+ to the connection session.
113
+
114
+ *Rafael Mendonça França*
115
+
116
+ * Fix MySQL adapter handling of time objects when prepared statements
117
+ are enabled.
118
+
119
+ *Rafael Mendonça França*
120
+
121
+ * Fix scoping in enum fields using conditions that would generate
122
+ an `IN` clause.
123
+
124
+ *Ryuta Kamizono*
125
+
126
+ * Skip optimised #exist? query when #include? is called on a relation
127
+ with a having clause
128
+
129
+ Relations that have aliased select values AND a having clause that
130
+ references an aliased select value would generate an error when
131
+ #include? was called, due to an optimisation that would generate
132
+ call #exists? on the relation instead, which effectively alters
133
+ the select values of the query (and thus removes the aliased select
134
+ values), but leaves the having clause intact. Because the having
135
+ clause is then referencing an aliased column that is no longer
136
+ present in the simplified query, an ActiveRecord::InvalidStatement
137
+ error was raised.
138
+
139
+ An sample query affected by this problem:
140
+
141
+ ```ruby
142
+ Author.select('COUNT(*) as total_posts', 'authors.*')
143
+ .joins(:posts)
144
+ .group(:id)
145
+ .having('total_posts > 2')
146
+ .include?(Author.first)
147
+ ```
148
+
149
+ This change adds an addition check to the condition that skips the
150
+ simplified #exists? query, which simply checks for the presence of
151
+ a having clause.
152
+
153
+ Fixes #41417
154
+
155
+ *Michael Smart*
156
+
157
+ * Increment postgres prepared statement counter before making a prepared statement, so if the statement is aborted
158
+ without Rails knowledge (e.g., if app gets kill -9d during long-running query or due to Rack::Timeout), app won't end
159
+ up in perpetual crash state for being inconsistent with Postgres.
160
+
161
+ *wbharding*, *Martin Tepper*
162
+
163
+
164
+ ## Rails 6.1.2.1 (February 10, 2021) ##
165
+
166
+ * Fix possible DoS vector in PostgreSQL money type
167
+
168
+ Carefully crafted input can cause a DoS via the regular expressions used
169
+ for validating the money format in the PostgreSQL adapter. This patch
170
+ fixes the regexp.
171
+
172
+ Thanks to @dee-see from Hackerone for this patch!
173
+
174
+ [CVE-2021-22880]
175
+
176
+ *Aaron Patterson*
177
+
178
+
1
179
  ## Rails 6.1.2 (February 09, 2021) ##
2
180
 
3
181
  * Fix timestamp type for sqlite3.
@@ -973,14 +1151,14 @@
973
1151
  Deprecated behavior:
974
1152
 
975
1153
  ```ruby
976
- db_config = ActiveRecord::Base.configs_for(env_name: "development", spec_name: "primary")
1154
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: "development", spec_name: "primary")
977
1155
  db_config.spec_name
978
1156
  ```
979
1157
 
980
1158
  New behavior:
981
1159
 
982
1160
  ```ruby
983
- db_config = ActiveRecord::Base.configs_for(env_name: "development", name: "primary")
1161
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: "development", name: "primary")
984
1162
  db_config.name
985
1163
  ```
986
1164
 
@@ -211,7 +211,7 @@ module ActiveRecord
211
211
 
212
212
  private
213
213
  def find_target
214
- if (owner.strict_loading? || reflection.strict_loading?) && owner.validation_context.nil?
214
+ if strict_loading? && owner.validation_context.nil?
215
215
  Base.strict_loading_violation!(owner: owner.class, reflection: reflection)
216
216
  end
217
217
 
@@ -227,6 +227,12 @@ module ActiveRecord
227
227
  sc.execute(binds, klass.connection) { |record| set_inverse_instance(record) }
228
228
  end
229
229
 
230
+ def strict_loading?
231
+ return reflection.strict_loading? if reflection.options.key?(:strict_loading)
232
+
233
+ owner.strict_loading?
234
+ end
235
+
230
236
  # The scope for this association.
231
237
  #
232
238
  # Note that the association_scope is merged into the target_scope only when the
@@ -9,8 +9,7 @@ module ActiveRecord
9
9
 
10
10
  case options[:dependent]
11
11
  when :destroy
12
- target.destroy
13
- raise ActiveRecord::Rollback unless target.destroyed?
12
+ raise ActiveRecord::Rollback unless target.destroy
14
13
  when :destroy_async
15
14
  id = owner.public_send(reflection.foreign_key.to_sym)
16
15
  primary_key_column = reflection.active_record_primary_key.to_sym
@@ -23,7 +23,7 @@ module ActiveRecord
23
23
  def load(yaml)
24
24
  return object_class.new if object_class != Object && yaml.nil?
25
25
  return yaml unless yaml.is_a?(String) && yaml.start_with?("---")
26
- obj = YAML.load(yaml)
26
+ obj = yaml_load(yaml)
27
27
 
28
28
  assert_valid_value(obj, action: "load")
29
29
  obj ||= object_class.new if object_class != Object
@@ -44,6 +44,16 @@ module ActiveRecord
44
44
  rescue ArgumentError
45
45
  raise ArgumentError, "Cannot serialize #{object_class}. Classes passed to `serialize` must have a 0 argument constructor."
46
46
  end
47
+
48
+ if YAML.respond_to?(:unsafe_load)
49
+ def yaml_load(payload)
50
+ YAML.unsafe_load(payload)
51
+ end
52
+ else
53
+ def yaml_load(payload)
54
+ YAML.load(payload)
55
+ end
56
+ end
47
57
  end
48
58
  end
49
59
  end
@@ -12,6 +12,8 @@ module ActiveRecord
12
12
  autoload :PoolConfig
13
13
  autoload :PoolManager
14
14
  autoload :LegacyPoolManager
15
+ autoload :SchemaCache
16
+ autoload :Deduplicable
15
17
 
16
18
  autoload_at "active_record/connection_adapters/abstract/schema_definitions" do
17
19
  autoload :IndexDefinition
@@ -395,7 +395,7 @@ module ActiveRecord
395
395
 
396
396
  # Inserts the given fixture into the table. Overridden in adapters that require
397
397
  # something beyond a simple insert (e.g. Oracle).
398
- # Most of adapters should implement `insert_fixtures_set` that leverages bulk SQL insert.
398
+ # Most of adapters should implement +insert_fixtures_set+ that leverages bulk SQL insert.
399
399
  # We keep this method to provide fallback
400
400
  # for databases like sqlite that do not support bulk inserts.
401
401
  def insert_fixture(fixture, table_name)
@@ -94,8 +94,8 @@ module ActiveRecord
94
94
  sql = ["CREATE"]
95
95
  sql << "UNIQUE" if index.unique
96
96
  sql << "INDEX"
97
- sql << "IF NOT EXISTS" if o.if_not_exists
98
97
  sql << o.algorithm if o.algorithm
98
+ sql << "IF NOT EXISTS" if o.if_not_exists
99
99
  sql << index.type if index.type
100
100
  sql << "#{quote_column_name(index.name)} ON #{quote_table_name(index.table)}"
101
101
  sql << "USING #{index.using}" if supports_index_using? && index.using
@@ -33,6 +33,10 @@ module ActiveRecord
33
33
  @state == :fully_rolledback
34
34
  end
35
35
 
36
+ def invalidated?
37
+ @state == :invalidated
38
+ end
39
+
36
40
  def fully_completed?
37
41
  completed?
38
42
  end
@@ -51,6 +55,11 @@ module ActiveRecord
51
55
  @state = :fully_rolledback
52
56
  end
53
57
 
58
+ def invalidate!
59
+ @children&.each { |c| c.invalidate! }
60
+ @state = :invalidated
61
+ end
62
+
54
63
  def commit!
55
64
  @state = :committed
56
65
  end
@@ -299,7 +308,7 @@ module ActiveRecord
299
308
  def rollback_transaction(transaction = nil)
300
309
  @connection.lock.synchronize do
301
310
  transaction ||= @stack.pop
302
- transaction.rollback
311
+ transaction.rollback unless transaction.state.invalidated?
303
312
  transaction.rollback_records
304
313
  end
305
314
  end
@@ -312,15 +321,17 @@ module ActiveRecord
312
321
  ret
313
322
  rescue Exception => error
314
323
  if transaction
324
+ transaction.state.invalidate! if error.is_a? ActiveRecord::TransactionRollbackError
315
325
  rollback_transaction
316
326
  after_failure_actions(transaction, error)
317
327
  end
328
+
318
329
  raise
319
330
  ensure
320
331
  if transaction
321
332
  if error
322
- # @connection still holds an open transaction, so we must not
323
- # put it back in the pool for reuse
333
+ # @connection still holds an open or invalid transaction, so we must not
334
+ # put it back in the pool for reuse.
324
335
  @connection.throw_away! unless transaction.state.rolledback?
325
336
  else
326
337
  if Thread.current.status == "aborting"
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "set"
4
- require "active_record/connection_adapters/schema_cache"
5
4
  require "active_record/connection_adapters/sql_type_metadata"
6
5
  require "active_record/connection_adapters/abstract/schema_dumper"
7
6
  require "active_record/connection_adapters/abstract/schema_creation"
@@ -116,10 +115,10 @@ module ActiveRecord
116
115
  # Returns true if the connection is a replica.
117
116
  #
118
117
  # If the application is using legacy handling, returns
119
- # true if `connection_handler.prevent_writes` is set.
118
+ # true if +connection_handler.prevent_writes+ is set.
120
119
  #
121
120
  # If the application is using the new connection handling
122
- # will return true based on `current_preventing_writes`.
121
+ # will return true based on +current_preventing_writes+.
123
122
  def preventing_writes?
124
123
  return true if replica?
125
124
  return ActiveRecord::Base.connection_handler.prevent_writes if ActiveRecord::Base.legacy_connection_handling
@@ -154,9 +153,10 @@ module ActiveRecord
154
153
  end
155
154
  end
156
155
 
157
- def prepared_statements
156
+ def prepared_statements?
158
157
  @prepared_statements && !prepared_statements_disabled_cache.include?(object_id)
159
158
  end
159
+ alias :prepared_statements :prepared_statements?
160
160
 
161
161
  def prepared_statements_disabled_cache # :nodoc:
162
162
  Thread.current[:ar_prepared_statements_disabled_cache] ||= Set.new
@@ -250,7 +250,7 @@ module ActiveRecord
250
250
  end
251
251
 
252
252
  def unprepared_statement
253
- cache = prepared_statements_disabled_cache.add(object_id) if @prepared_statements
253
+ cache = prepared_statements_disabled_cache.add?(object_id) if @prepared_statements
254
254
  yield
255
255
  ensure
256
256
  cache&.delete(object_id)
@@ -751,11 +751,6 @@ module ActiveRecord
751
751
  wait_timeout = 2147483 unless wait_timeout.is_a?(Integer)
752
752
  variables["wait_timeout"] = wait_timeout
753
753
 
754
- # Set the collation of the connection character set.
755
- if @config[:collation]
756
- variables["collation_connection"] = @config[:collation]
757
- end
758
-
759
754
  defaults = [":default", :default].to_set
760
755
 
761
756
  # Make MySQL reject illegal values rather than truncating or blanking them, see
@@ -775,6 +770,15 @@ module ActiveRecord
775
770
  end
776
771
  sql_mode_assignment = "@@SESSION.sql_mode = #{sql_mode}, " if sql_mode
777
772
 
773
+ # NAMES does not have an equals sign, see
774
+ # https://dev.mysql.com/doc/refman/en/set-names.html
775
+ # (trailing comma because variable_assignments will always have content)
776
+ if @config[:encoding]
777
+ encoding = +"NAMES #{@config[:encoding]}"
778
+ encoding << " COLLATE #{@config[:collation]}" if @config[:collation]
779
+ encoding << ", "
780
+ end
781
+
778
782
  # Gather up all of the SET variables...
779
783
  variable_assignments = variables.map do |k, v|
780
784
  if defaults.include?(v)
@@ -786,7 +790,7 @@ module ActiveRecord
786
790
  end.compact.join(", ")
787
791
 
788
792
  # ...and send them all in one query
789
- execute("SET #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
793
+ execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
790
794
  end
791
795
 
792
796
  def column_definitions(table_name) # :nodoc:
@@ -23,8 +23,12 @@ module ActiveRecord
23
23
  @name_to_pool_config[shard]
24
24
  end
25
25
 
26
- def set_pool_config(_, shard, pool_config)
27
- @name_to_pool_config[shard] = pool_config
26
+ def set_pool_config(role, shard, pool_config)
27
+ if pool_config
28
+ @name_to_pool_config[shard] = pool_config
29
+ else
30
+ raise ArgumentError, "The `pool_config` for the :#{role} role and :#{shard} shard was `nil`. Please check your configuration. If you want your writing role to be something other than `:writing` set `config.active_record.writing_role` in your application configuration. The same setting should be applied for the `reading_role` if applicable."
31
+ end
28
32
  end
29
33
  end
30
34
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/time_with_zone"
4
+
3
5
  module ActiveRecord
4
6
  module ConnectionAdapters
5
7
  module MySQL
@@ -69,10 +71,23 @@ module ActiveRecord
69
71
  private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
70
72
 
71
73
  private
74
+ # Override +_type_cast+ we pass to mysql2 Date and Time objects instead
75
+ # of Strings since mysql2 is able to handle those classes more efficiently.
72
76
  def _type_cast(value)
73
77
  case value
74
- when Date, Time then value
75
- else super
78
+ when ActiveSupport::TimeWithZone
79
+ # We need to check explicitly for ActiveSupport::TimeWithZone because
80
+ # we need to transform it to Time objects but we don't want to
81
+ # transform Time objects to themselves.
82
+ if ActiveRecord::Base.default_timezone == :utc
83
+ value.getutc
84
+ else
85
+ value.getlocal
86
+ end
87
+ when Date, Time
88
+ value
89
+ else
90
+ super
76
91
  end
77
92
  end
78
93
  end
@@ -36,7 +36,11 @@ module ActiveRecord
36
36
  end
37
37
 
38
38
  def set_pool_config(role, shard, pool_config)
39
- @name_to_role_mapping[role][shard] = pool_config
39
+ if pool_config
40
+ @name_to_role_mapping[role][shard] = pool_config
41
+ else
42
+ raise ArgumentError, "The `pool_config` for the :#{role} role and :#{shard} shard was `nil`. Please check your configuration. If you want your writing role to be something other than `:writing` set `config.active_record.writing_role` in your application configuration. The same setting should be applied for the `reading_role` if applicable."
43
+ end
40
44
  end
41
45
  end
42
46
  end
@@ -26,9 +26,9 @@ module ActiveRecord
26
26
 
27
27
  value = value.sub(/^\((.+)\)$/, '-\1') # (4)
28
28
  case value
29
- when /^-?\D*[\d,]+\.\d{2}$/ # (1)
29
+ when /^-?\D*+[\d,]+\.\d{2}$/ # (1)
30
30
  value.gsub!(/[^-\d.]/, "")
31
- when /^-?\D*[\d.]+,\d{2}$/ # (2)
31
+ when /^-?\D*+[\d.]+,\d{2}$/ # (2)
32
32
  value.gsub!(/[^-\d,]/, "").sub!(/,/, ".")
33
33
  end
34
34
 
@@ -227,11 +227,7 @@ module ActiveRecord
227
227
  end
228
228
 
229
229
  def next_key
230
- "a#{@counter + 1}"
231
- end
232
-
233
- def []=(sql, key)
234
- super.tap { @counter += 1 }
230
+ "a#{@counter += 1}"
235
231
  end
236
232
 
237
233
  private
@@ -9,7 +9,15 @@ module ActiveRecord
9
9
  return unless File.file?(filename)
10
10
 
11
11
  read(filename) do |file|
12
- filename.include?(".dump") ? Marshal.load(file) : YAML.load(file)
12
+ if filename.include?(".dump")
13
+ Marshal.load(file)
14
+ else
15
+ if YAML.respond_to?(:unsafe_load)
16
+ YAML.unsafe_load(file)
17
+ else
18
+ YAML.load(file)
19
+ end
20
+ end
13
21
  end
14
22
  end
15
23
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_record/connection_adapters/deduplicable"
4
-
5
3
  module ActiveRecord
6
4
  # :stopdoc:
7
5
  module ConnectionAdapters
@@ -114,7 +114,7 @@ module ActiveRecord
114
114
  #
115
115
  # If only a role is passed, Active Record will look up the connection
116
116
  # based on the requested role. If a non-established role is requested
117
- # an `ActiveRecord::ConnectionNotEstablished` error will be raised:
117
+ # an +ActiveRecord::ConnectionNotEstablished+ error will be raised:
118
118
  #
119
119
  # ActiveRecord::Base.connected_to(role: :writing) do
120
120
  # Dog.create! # creates dog using dog writing connection
@@ -125,7 +125,7 @@ module ActiveRecord
125
125
  # end
126
126
  #
127
127
  # When swapping to a shard, the role must be passed as well. If a non-existent
128
- # shard is passed, an `ActiveRecord::ConnectionNotEstablished` error will be
128
+ # shard is passed, an +ActiveRecord::ConnectionNotEstablished+ error will be
129
129
  # raised.
130
130
  #
131
131
  # When a shard and role is passed, Active Record will first lookup the role,
@@ -178,11 +178,11 @@ module ActiveRecord
178
178
  end
179
179
  end
180
180
 
181
- # Connects a role and/or shard to the provided connection names. Optionally `prevent_writes`
182
- # can be passed to block writes on a connection. `reading` will automatically set
183
- # `prevent_writes` to true.
181
+ # Connects a role and/or shard to the provided connection names. Optionally +prevent_writes+
182
+ # can be passed to block writes on a connection. +reading+ will automatically set
183
+ # +prevent_writes+ to true.
184
184
  #
185
- # `connected_to_many` is an alternative to deeply nested `connected_to` blocks.
185
+ # +connected_to_many+ is an alternative to deeply nested +connected_to+ blocks.
186
186
  #
187
187
  # Usage:
188
188
  #
@@ -216,7 +216,7 @@ module ActiveRecord
216
216
  # being used. For example, when booting a console in readonly mode.
217
217
  #
218
218
  # It is not recommended to use this method in a request since it
219
- # does not yield to a block like `connected_to`.
219
+ # does not yield to a block like +connected_to+.
220
220
  def connecting_to(role: default_role, shard: default_shard, prevent_writes: false)
221
221
  if legacy_connection_handling
222
222
  raise NotImplementedError, "`connecting_to` is not available with `legacy_connection_handling`."
@@ -230,13 +230,13 @@ module ActiveRecord
230
230
  # Prevent writing to the database regardless of role.
231
231
  #
232
232
  # In some cases you may want to prevent writes to the database
233
- # even if you are on a database that can write. `while_preventing_writes`
233
+ # even if you are on a database that can write. +while_preventing_writes+
234
234
  # will prevent writes to the database for the duration of the block.
235
235
  #
236
236
  # This method does not provide the same protection as a readonly
237
237
  # user and is meant to be a safeguard against accidental writes.
238
238
  #
239
- # See `READ_QUERY` for the queries that are blocked by this
239
+ # See +READ_QUERY+ for the queries that are blocked by this
240
240
  # method.
241
241
  def while_preventing_writes(enabled = true, &block)
242
242
  if legacy_connection_handling
@@ -408,7 +408,21 @@ module ActiveRecord
408
408
  end
409
409
 
410
410
  # Specifies columns which shouldn't be exposed while calling +#inspect+.
411
- attr_writer :filter_attributes
411
+ def filter_attributes=(filter_attributes)
412
+ @inspection_filter = nil
413
+ @filter_attributes = filter_attributes
414
+ end
415
+
416
+ def inspection_filter # :nodoc:
417
+ if defined?(@filter_attributes)
418
+ @inspection_filter ||= begin
419
+ mask = InspectionMask.new(ActiveSupport::ParameterFilter::FILTERED)
420
+ ActiveSupport::ParameterFilter.new(@filter_attributes, mask: mask)
421
+ end
422
+ else
423
+ superclass.inspection_filter
424
+ end
425
+ end
412
426
 
413
427
  # Returns a string like 'Post(id:integer, title:string, body:text)'
414
428
  def inspect # :nodoc:
@@ -776,10 +790,7 @@ module ActiveRecord
776
790
  private_constant :InspectionMask
777
791
 
778
792
  def inspection_filter
779
- @inspection_filter ||= begin
780
- mask = InspectionMask.new(ActiveSupport::ParameterFilter::FILTERED)
781
- ActiveSupport::ParameterFilter.new(self.class.filter_attributes, mask: mask)
782
- end
793
+ self.class.inspection_filter
783
794
  end
784
795
  end
785
796
  end
@@ -139,22 +139,20 @@ module ActiveRecord
139
139
  mapping.key(subtype.deserialize(value))
140
140
  end
141
141
 
142
- def serializable?(value)
143
- (value.blank? || mapping.has_key?(value) || mapping.has_value?(value)) && super
144
- end
145
-
146
142
  def serialize(value)
147
143
  mapping.fetch(value, value)
148
144
  end
149
145
 
150
146
  def assert_valid_value(value)
151
- unless serializable?(value)
147
+ unless value.blank? || mapping.has_key?(value) || mapping.has_value?(value)
152
148
  raise ArgumentError, "'#{value}' is not a valid #{name}"
153
149
  end
154
150
  end
155
151
 
152
+ attr_reader :subtype
153
+
156
154
  private
157
- attr_reader :name, :mapping, :subtype
155
+ attr_reader :name, :mapping
158
156
  end
159
157
 
160
158
  def enum(definitions)
@@ -181,7 +181,7 @@ module ActiveRecord
181
181
  # end
182
182
  # end
183
183
  #
184
- # If you preload your test database with all fixture data (probably by running `bin/rails db:fixtures:load`)
184
+ # If you preload your test database with all fixture data (probably by running <tt>bin/rails db:fixtures:load</tt>)
185
185
  # and use transactional tests, then you may omit all fixtures declarations in your test cases since
186
186
  # all the data's already there and every case rolls back its changes.
187
187
  #
@@ -9,7 +9,7 @@ module ActiveRecord
9
9
  module VERSION
10
10
  MAJOR = 6
11
11
  MINOR = 1
12
- TINY = 2
12
+ TINY = 4
13
13
  PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -69,7 +69,11 @@ module ActiveRecord
69
69
  attr_reader :scope_attributes
70
70
 
71
71
  def find_unique_index_for(unique_by)
72
- return unique_by if !connection.supports_insert_conflict_target?
72
+ if !connection.supports_insert_conflict_target?
73
+ return if unique_by.nil?
74
+
75
+ raise ArgumentError, "#{connection.class} does not support :unique_by"
76
+ end
73
77
 
74
78
  name_or_columns = unique_by || model.primary_key
75
79
  match = Array(name_or_columns).map(&:to_s)
@@ -320,7 +320,7 @@ module ActiveRecord
320
320
  # +table_name+. Passing a hash containing <tt>:from</tt> and <tt>:to</tt>
321
321
  # as +default_or_changes+ will make this change reversible in the migration.
322
322
  # * <tt>change_column_null(table_name, column_name, null, default = nil)</tt>:
323
- # Sets or removes a +NOT NULL+ constraint on +column_name+. The +null+ flag
323
+ # Sets or removes a <tt>NOT NULL</tt> constraint on +column_name+. The +null+ flag
324
324
  # indicates whether the value can be +NULL+. See
325
325
  # ActiveRecord::ConnectionAdapters::SchemaStatements#change_column_null for
326
326
  # details.
@@ -122,9 +122,9 @@ module ActiveRecord
122
122
  # :singleton-method: immutable_strings_by_default=
123
123
  # :call-seq: immutable_strings_by_default=(bool)
124
124
  #
125
- # Determines whether columns should infer their type as `:string` or
126
- # `:immutable_string`. This setting does not affect the behavior of
127
- # `attribute :foo, :string`. Defaults to false.
125
+ # Determines whether columns should infer their type as +:string+ or
126
+ # +:immutable_string+. This setting does not affect the behavior of
127
+ # <tt>attribute :foo, :string</tt>. Defaults to false.
128
128
 
129
129
  included do
130
130
  mattr_accessor :primary_key_prefix_type, instance_writer: false
@@ -316,7 +316,7 @@ module ActiveRecord
316
316
  # self.ignored_columns = [:category]
317
317
  # end
318
318
  #
319
- # The schema still contains `category`, but now the model omits it, so any meta-driven code or
319
+ # The schema still contains "category", but now the model omits it, so any meta-driven code or
320
320
  # schema caching will not attempt to use the column:
321
321
  #
322
322
  # Project.columns_hash["category"] => nil
@@ -413,8 +413,9 @@ db_namespace = namespace :db do
413
413
  fixture_files = if ENV["FIXTURES"]
414
414
  ENV["FIXTURES"].split(",")
415
415
  else
416
- # The use of String#[] here is to support namespaced fixtures.
417
- Dir["#{fixtures_dir}/**/*.yml"].map { |f| f[(fixtures_dir.size + 1)..-5] }
416
+ files = Dir[File.join(fixtures_dir, "**/*.{yml}")]
417
+ files.reject! { |f| f.start_with?(File.join(fixtures_dir, "files")) }
418
+ files.map! { |f| f[fixtures_dir.to_s.size..-5].delete_prefix("/") }
418
419
  end
419
420
 
420
421
  ActiveRecord::FixtureSet.create_fixtures(fixtures_dir, fixture_files)
@@ -440,13 +440,11 @@ module ActiveRecord
440
440
  def update_all(updates)
441
441
  raise ArgumentError, "Empty list of attributes to change" if updates.blank?
442
442
 
443
- if eager_loading?
444
- relation = apply_join_dependency
445
- return relation.update_all(updates)
446
- end
443
+ arel = eager_loading? ? apply_join_dependency.arel : build_arel
444
+ arel.source.left = table
447
445
 
448
446
  stmt = Arel::UpdateManager.new
449
- stmt.table(arel.join_sources.empty? ? table : arel.source)
447
+ stmt.table(arel.source)
450
448
  stmt.key = table[primary_key]
451
449
  stmt.take(arel.limit)
452
450
  stmt.offset(arel.offset)
@@ -465,7 +463,7 @@ module ActiveRecord
465
463
  stmt.set Arel.sql(klass.sanitize_sql_for_assignment(updates, table.name))
466
464
  end
467
465
 
468
- @klass.connection.update stmt, "#{@klass} Update All"
466
+ klass.connection.update(stmt, "#{klass} Update All").tap { reset }
469
467
  end
470
468
 
471
469
  def update(id = :all, attributes) # :nodoc:
@@ -582,23 +580,18 @@ module ActiveRecord
582
580
  raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
583
581
  end
584
582
 
585
- if eager_loading?
586
- relation = apply_join_dependency
587
- return relation.delete_all
588
- end
583
+ arel = eager_loading? ? apply_join_dependency.arel : build_arel
584
+ arel.source.left = table
589
585
 
590
586
  stmt = Arel::DeleteManager.new
591
- stmt.from(arel.join_sources.empty? ? table : arel.source)
587
+ stmt.from(arel.source)
592
588
  stmt.key = table[primary_key]
593
589
  stmt.take(arel.limit)
594
590
  stmt.offset(arel.offset)
595
591
  stmt.order(*arel.orders)
596
592
  stmt.wheres = arel.constraints
597
593
 
598
- affected = @klass.connection.delete(stmt, "#{@klass} Destroy")
599
-
600
- reset
601
- affected
594
+ klass.connection.delete(stmt, "#{klass} Destroy").tap { reset }
602
595
  end
603
596
 
604
597
  # Finds and destroys all records matching the specified conditions.
@@ -652,6 +645,7 @@ module ActiveRecord
652
645
  @delegate_to_klass = false
653
646
  @to_sql = @arel = @loaded = @should_eager_load = nil
654
647
  @offsets = @take = nil
648
+ @cache_keys = nil
655
649
  @records = [].freeze
656
650
  self
657
651
  end
@@ -683,8 +677,7 @@ module ActiveRecord
683
677
  end
684
678
 
685
679
  def scope_for_create
686
- hash = where_values_hash
687
- hash.delete(klass.inheritance_column) if klass.finder_needs_type_condition?
680
+ hash = where_clause.to_h(klass.table_name, equality_only: true)
688
681
  create_with_value.each { |k, v| hash[k.to_s] = v } unless create_with_value.empty?
689
682
  hash
690
683
  end
@@ -310,6 +310,7 @@ module ActiveRecord
310
310
  type_cast_calculated_value(result.cast_values.first, operation) do |value|
311
311
  type = column.try(:type_caster) ||
312
312
  lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
313
+ type = type.subtype if Enum::EnumType === type
313
314
  type.deserialize(value)
314
315
  end
315
316
  end
@@ -387,8 +388,11 @@ module ActiveRecord
387
388
  key = key_records[key] if associated
388
389
 
389
390
  result[key] = type_cast_calculated_value(row[column_alias], operation) do |value|
390
- type ||= column.try(:type_caster) ||
391
- lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
391
+ unless type
392
+ type = column.try(:type_caster) ||
393
+ lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
394
+ type = type.subtype if Enum::EnumType === type
395
+ end
392
396
  type.deserialize(value)
393
397
  end
394
398
  end
@@ -326,7 +326,7 @@ module ActiveRecord
326
326
  # compared to the records in memory. If the relation is unloaded, an
327
327
  # efficient existence query is performed, as in #exists?.
328
328
  def include?(record)
329
- if loaded? || offset_value || limit_value
329
+ if loaded? || offset_value || limit_value || having_clause.any?
330
330
  records.include?(record)
331
331
  else
332
332
  record.is_a?(klass) && exists?(record.id)
@@ -103,7 +103,9 @@ module ActiveRecord
103
103
 
104
104
  klass ||= AssociationQueryValue
105
105
  queries = klass.new(associated_table, value).queries.map! do |query|
106
- expand_from_hash(query)
106
+ # If the query produced is identical to attributes don't go any deeper.
107
+ # Prevents stack level too deep errors when association and foreign_key are identical.
108
+ query == attributes ? self[key, value] : expand_from_hash(query)
107
109
  end
108
110
 
109
111
  grouping_queries(queries)
@@ -1133,7 +1133,7 @@ module ActiveRecord
1133
1133
  raise ImmutableRelation if defined?(@arel) && @arel
1134
1134
  end
1135
1135
 
1136
- def build_arel(aliases)
1136
+ def build_arel(aliases = nil)
1137
1137
  arel = Arel::SelectManager.new(table)
1138
1138
 
1139
1139
  build_joins(arel.join_sources, aliases)
@@ -58,8 +58,8 @@ module ActiveRecord
58
58
  end
59
59
  end
60
60
 
61
- def to_h(table_name = nil)
62
- equalities(predicates).each_with_object({}) do |node, hash|
61
+ def to_h(table_name = nil, equality_only: false)
62
+ equalities(predicates, equality_only).each_with_object({}) do |node, hash|
63
63
  next if table_name&.!= node.left.relation.name
64
64
  name = node.left.name.to_s
65
65
  value = extract_node_value(node.right)
@@ -103,28 +103,31 @@ module ActiveRecord
103
103
  end
104
104
 
105
105
  def extract_attributes
106
- predicates.each_with_object([]) do |node, attrs|
107
- attr = extract_attribute(node) || begin
108
- node.left if node.equality? && node.left.is_a?(Arel::Predications)
109
- end
110
- attrs << attr if attr
111
- end
106
+ attrs = []
107
+ each_attributes { |attr, _| attrs << attr }
108
+ attrs
112
109
  end
113
110
 
114
111
  protected
115
112
  attr_reader :predicates
116
113
 
117
114
  def referenced_columns
118
- predicates.each_with_object({}) do |node, hash|
115
+ hash = {}
116
+ each_attributes { |attr, node| hash[attr] = node }
117
+ hash
118
+ end
119
+
120
+ private
121
+ def each_attributes
122
+ predicates.each do |node|
119
123
  attr = extract_attribute(node) || begin
120
124
  node.left if equality_node?(node) && node.left.is_a?(Arel::Predications)
121
125
  end
122
126
 
123
- hash[attr] = node if attr
127
+ yield attr, node if attr
124
128
  end
125
129
  end
126
130
 
127
- private
128
131
  def extract_attribute(node)
129
132
  attr_node = nil
130
133
  Arel.fetch_attribute(node) do |attr|
@@ -134,14 +137,14 @@ module ActiveRecord
134
137
  attr_node
135
138
  end
136
139
 
137
- def equalities(predicates)
140
+ def equalities(predicates, equality_only)
138
141
  equalities = []
139
142
 
140
143
  predicates.each do |node|
141
- if equality_node?(node)
144
+ if equality_only ? Arel::Nodes::Equality === node : equality_node?(node)
142
145
  equalities << node
143
146
  elsif node.is_a?(Arel::Nodes::And)
144
- equalities.concat equalities(node.children)
147
+ equalities.concat equalities(node.children, equality_only)
145
148
  end
146
149
  end
147
150
 
@@ -109,9 +109,7 @@ module ActiveRecord
109
109
  if default_scope_override
110
110
  # The user has defined their own default scope method, so call that
111
111
  evaluate_default_scope do
112
- if scope = default_scope
113
- relation.merge!(scope)
114
- end
112
+ relation.scoping { default_scope }
115
113
  end
116
114
  elsif default_scopes.any?
117
115
  evaluate_default_scope do
@@ -80,8 +80,8 @@ module ActiveRecord
80
80
  self
81
81
  end
82
82
 
83
- def add_binds(binds)
84
- @binds.concat binds
83
+ def add_binds(binds, proc_for_binds = nil)
84
+ @binds.concat proc_for_binds ? binds.map(&proc_for_binds) : binds
85
85
  binds.size.times do |i|
86
86
  @parts << ", " unless i == 0
87
87
  @parts << Substitute.new
@@ -111,6 +111,8 @@ module ActiveRecord
111
111
  @fixture_connections = []
112
112
  @@already_loaded_fixtures ||= {}
113
113
  @connection_subscriber = nil
114
+ @legacy_saved_pool_configs = Hash.new { |hash, key| hash[key] = {} }
115
+ @saved_pool_configs = Hash.new { |hash, key| hash[key] = {} }
114
116
 
115
117
  # Load fixtures once and begin transaction.
116
118
  if run_in_transaction?
@@ -169,6 +171,7 @@ module ActiveRecord
169
171
  connection.pool.lock_thread = false
170
172
  end
171
173
  @fixture_connections.clear
174
+ teardown_shared_connection_pool
172
175
  else
173
176
  ActiveRecord::FixtureSet.reset_cache
174
177
  end
@@ -200,8 +203,13 @@ module ActiveRecord
200
203
  return unless writing_pool_manager
201
204
 
202
205
  pool_manager = handler.send(:owner_to_pool_manager)[name]
206
+ @legacy_saved_pool_configs[handler][name] ||= {}
203
207
  pool_manager.shard_names.each do |shard_name|
204
208
  writing_pool_config = writing_pool_manager.get_pool_config(nil, shard_name)
209
+ pool_config = pool_manager.get_pool_config(nil, shard_name)
210
+ next if pool_config == writing_pool_config
211
+
212
+ @legacy_saved_pool_configs[handler][name][shard_name] = pool_config
205
213
  pool_manager.set_pool_config(nil, shard_name, writing_pool_config)
206
214
  end
207
215
  end
@@ -214,8 +222,12 @@ module ActiveRecord
214
222
  pool_manager = handler.send(:owner_to_pool_manager)[name]
215
223
  pool_manager.shard_names.each do |shard_name|
216
224
  writing_pool_config = pool_manager.get_pool_config(ActiveRecord::Base.writing_role, shard_name)
225
+ @saved_pool_configs[name][shard_name] ||= {}
217
226
  pool_manager.role_names.each do |role|
218
- next unless pool_manager.get_pool_config(role, shard_name)
227
+ next unless pool_config = pool_manager.get_pool_config(role, shard_name)
228
+ next if pool_config == writing_pool_config
229
+
230
+ @saved_pool_configs[name][shard_name][role] = pool_config
219
231
  pool_manager.set_pool_config(role, shard_name, writing_pool_config)
220
232
  end
221
233
  end
@@ -223,6 +235,35 @@ module ActiveRecord
223
235
  end
224
236
  end
225
237
 
238
+ def teardown_shared_connection_pool
239
+ if ActiveRecord::Base.legacy_connection_handling
240
+ @legacy_saved_pool_configs.each_pair do |handler, names|
241
+ names.each_pair do |name, shards|
242
+ shards.each_pair do |shard_name, pool_config|
243
+ pool_manager = handler.send(:owner_to_pool_manager)[name]
244
+ pool_manager.set_pool_config(nil, shard_name, pool_config)
245
+ end
246
+ end
247
+ end
248
+ else
249
+ handler = ActiveRecord::Base.connection_handler
250
+
251
+ @saved_pool_configs.each_pair do |name, shards|
252
+ pool_manager = handler.send(:owner_to_pool_manager)[name]
253
+ shards.each_pair do |shard_name, roles|
254
+ roles.each_pair do |role, pool_config|
255
+ next unless pool_manager.get_pool_config(role, shard_name)
256
+
257
+ pool_manager.set_pool_config(role, shard_name, pool_config)
258
+ end
259
+ end
260
+ end
261
+ end
262
+
263
+ @legacy_saved_pool_configs.clear
264
+ @saved_pool_configs.clear
265
+ end
266
+
226
267
  def load_fixtures(config)
227
268
  ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names, config).index_by(&:name)
228
269
  end
@@ -4,7 +4,7 @@ module ActiveRecord
4
4
  module Validations
5
5
  class NumericalityValidator < ActiveModel::Validations::NumericalityValidator # :nodoc:
6
6
  def validate_each(record, attribute, value, precision: nil, scale: nil)
7
- precision = [column_precision_for(record, attribute) || BigDecimal.double_fig, BigDecimal.double_fig].min
7
+ precision = [column_precision_for(record, attribute) || Float::DIG, Float::DIG].min
8
8
  scale = column_scale_for(record, attribute)
9
9
  super(record, attribute, value, precision: precision, scale: scale)
10
10
  end
@@ -16,8 +16,8 @@ module Arel # :nodoc: all
16
16
  self
17
17
  end
18
18
 
19
- def add_binds(binds)
20
- @binds.concat binds
19
+ def add_binds(binds, proc_for_binds = nil)
20
+ @binds.concat proc_for_binds ? binds.map(&proc_for_binds) : binds
21
21
  self
22
22
  end
23
23
 
@@ -22,9 +22,9 @@ module Arel # :nodoc: all
22
22
  self
23
23
  end
24
24
 
25
- def add_binds(binds, &block)
26
- left.add_binds(binds, &block)
27
- right.add_binds(binds, &block)
25
+ def add_binds(binds, proc_for_binds = nil, &block)
26
+ left.add_binds(binds, proc_for_binds, &block)
27
+ right.add_binds(binds, proc_for_binds, &block)
28
28
  self
29
29
  end
30
30
 
@@ -18,7 +18,7 @@ module Arel # :nodoc: all
18
18
  self
19
19
  end
20
20
 
21
- def add_binds(binds, &block)
21
+ def add_binds(binds, proc_for_binds = nil, &block)
22
22
  self << (@bind_index...@bind_index += binds.size).map(&block).join(", ")
23
23
  self
24
24
  end
@@ -20,7 +20,7 @@ module Arel # :nodoc: all
20
20
  self << quoter.quote(bind)
21
21
  end
22
22
 
23
- def add_binds(binds)
23
+ def add_binds(binds, proc_for_binds = nil)
24
24
  self << binds.map { |bind| quoter.quote(bind) }.join(", ")
25
25
  end
26
26
 
@@ -55,6 +55,10 @@ module Arel # :nodoc: all
55
55
  casted_values
56
56
  end
57
57
 
58
+ def proc_for_binds
59
+ -> value { ActiveModel::Attribute.with_cast_value(attribute.name, value, attribute.type_caster) }
60
+ end
61
+
58
62
  def fetch_attribute(&block)
59
63
  if attribute
60
64
  yield attribute
@@ -207,11 +207,11 @@ module Arel # :nodoc: all
207
207
  end
208
208
 
209
209
  def contains(other)
210
- Arel::Nodes::Contains.new(self, other)
210
+ Arel::Nodes::Contains.new self, quoted_node(other)
211
211
  end
212
212
 
213
213
  def overlaps(other)
214
- Arel::Nodes::Overlaps.new(self, other)
214
+ Arel::Nodes::Overlaps.new self, quoted_node(other)
215
215
  end
216
216
 
217
217
  def quoted_array(others)
@@ -337,7 +337,7 @@ module Arel # :nodoc: all
337
337
  if values.empty?
338
338
  collector << @connection.quote(nil)
339
339
  else
340
- collector.add_binds(values, &bind_block)
340
+ collector.add_binds(values, o.proc_for_binds, &bind_block)
341
341
  end
342
342
 
343
343
  collector << ")"
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: 6.1.2
4
+ version: 6.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-09 00:00:00.000000000 Z
11
+ date: 2021-06-24 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: 6.1.2
19
+ version: 6.1.4
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: 6.1.2
26
+ version: 6.1.4
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: 6.1.2
33
+ version: 6.1.4
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: 6.1.2
40
+ version: 6.1.4
41
41
  description: Databases on Rails. Build a persistent domain model by mapping database
42
42
  tables to Ruby classes. Strong conventions for associations, validations, aggregations,
43
43
  migrations, and testing come baked-in.
@@ -390,11 +390,11 @@ licenses:
390
390
  - MIT
391
391
  metadata:
392
392
  bug_tracker_uri: https://github.com/rails/rails/issues
393
- changelog_uri: https://github.com/rails/rails/blob/v6.1.2/activerecord/CHANGELOG.md
394
- documentation_uri: https://api.rubyonrails.org/v6.1.2/
393
+ changelog_uri: https://github.com/rails/rails/blob/v6.1.4/activerecord/CHANGELOG.md
394
+ documentation_uri: https://api.rubyonrails.org/v6.1.4/
395
395
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
396
- source_code_uri: https://github.com/rails/rails/tree/v6.1.2/activerecord
397
- post_install_message:
396
+ source_code_uri: https://github.com/rails/rails/tree/v6.1.4/activerecord
397
+ post_install_message:
398
398
  rdoc_options:
399
399
  - "--main"
400
400
  - README.rdoc
@@ -411,8 +411,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
411
411
  - !ruby/object:Gem::Version
412
412
  version: '0'
413
413
  requirements: []
414
- rubygems_version: 3.2.3
415
- signing_key:
414
+ rubygems_version: 3.1.2
415
+ signing_key:
416
416
  specification_version: 4
417
417
  summary: Object-relational mapper framework (part of Rails).
418
418
  test_files: []