activerecord 6.0.0.beta1 → 6.0.0.beta2

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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +99 -2
  3. data/lib/active_record.rb +7 -0
  4. data/lib/active_record/associations/association.rb +17 -0
  5. data/lib/active_record/associations/collection_association.rb +5 -6
  6. data/lib/active_record/associations/collection_proxy.rb +12 -41
  7. data/lib/active_record/associations/has_many_association.rb +1 -9
  8. data/lib/active_record/associations/join_dependency/join_association.rb +11 -6
  9. data/lib/active_record/associations/preloader/association.rb +3 -4
  10. data/lib/active_record/associations/preloader/through_association.rb +9 -20
  11. data/lib/active_record/callbacks.rb +3 -3
  12. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +25 -12
  13. data/lib/active_record/connection_adapters/abstract/database_statements.rb +17 -9
  14. data/lib/active_record/connection_adapters/abstract/query_cache.rb +6 -1
  15. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +5 -2
  16. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +47 -33
  17. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +16 -8
  18. data/lib/active_record/connection_adapters/abstract/transaction.rb +5 -2
  19. data/lib/active_record/connection_adapters/abstract_adapter.rb +6 -4
  20. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +28 -65
  21. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +1 -1
  22. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
  23. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
  24. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +59 -1
  25. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  26. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
  27. data/lib/active_record/connection_adapters/postgresql/quoting.rb +1 -1
  28. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +36 -0
  29. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +98 -89
  30. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +15 -27
  31. data/lib/active_record/connection_adapters/postgresql_adapter.rb +30 -0
  32. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +27 -1
  33. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +8 -5
  34. data/lib/active_record/connection_handling.rb +9 -4
  35. data/lib/active_record/core.rb +13 -1
  36. data/lib/active_record/database_configurations.rb +30 -10
  37. data/lib/active_record/database_configurations/hash_config.rb +1 -1
  38. data/lib/active_record/database_configurations/url_config.rb +9 -4
  39. data/lib/active_record/errors.rb +17 -12
  40. data/lib/active_record/gem_version.rb +1 -1
  41. data/lib/active_record/inheritance.rb +1 -1
  42. data/lib/active_record/middleware/database_selector.rb +75 -0
  43. data/lib/active_record/middleware/database_selector/resolver.rb +90 -0
  44. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  45. data/lib/active_record/migration.rb +1 -1
  46. data/lib/active_record/migration/compatibility.rb +62 -63
  47. data/lib/active_record/persistence.rb +6 -6
  48. data/lib/active_record/querying.rb +2 -3
  49. data/lib/active_record/railtie.rb +9 -0
  50. data/lib/active_record/railties/collection_cache_association_loading.rb +3 -3
  51. data/lib/active_record/reflection.rb +15 -29
  52. data/lib/active_record/relation.rb +86 -15
  53. data/lib/active_record/relation/calculations.rb +2 -4
  54. data/lib/active_record/relation/delegation.rb +1 -1
  55. data/lib/active_record/relation/finder_methods.rb +8 -4
  56. data/lib/active_record/relation/query_attribute.rb +5 -3
  57. data/lib/active_record/relation/query_methods.rb +28 -8
  58. data/lib/active_record/relation/spawn_methods.rb +1 -1
  59. data/lib/active_record/relation/where_clause.rb +1 -5
  60. data/lib/active_record/scoping.rb +6 -7
  61. data/lib/active_record/scoping/default.rb +1 -8
  62. data/lib/active_record/scoping/named.rb +9 -1
  63. data/lib/active_record/test_fixtures.rb +2 -2
  64. data/lib/active_record/timestamp.rb +9 -3
  65. data/lib/active_record/validations/uniqueness.rb +3 -1
  66. data/lib/arel.rb +7 -0
  67. data/lib/arel/nodes/and.rb +1 -1
  68. data/lib/arel/nodes/case.rb +1 -1
  69. metadata +11 -8
@@ -186,11 +186,9 @@ module ActiveRecord
186
186
  relation = apply_join_dependency
187
187
  relation.pluck(*column_names)
188
188
  else
189
- disallow_raw_sql!(column_names)
189
+ klass.disallow_raw_sql!(column_names)
190
190
  relation = spawn
191
- relation.select_values = column_names.map { |cn|
192
- @klass.has_attribute?(cn) || @klass.attribute_alias?(cn) ? arel_attribute(cn) : cn
193
- }
191
+ relation.select_values = column_names
194
192
  result = skip_query_cache_if_necessary { klass.connection.select_all(relation.arel, nil) }
195
193
  result.cast_values(klass.attribute_types)
196
194
  end
@@ -132,7 +132,7 @@ module ActiveRecord
132
132
 
133
133
  private
134
134
  def respond_to_missing?(method, _)
135
- super || @klass.respond_to?(method) || arel.respond_to?(method)
135
+ super || @klass.respond_to?(method)
136
136
  end
137
137
  end
138
138
  end
@@ -307,8 +307,6 @@ module ActiveRecord
307
307
 
308
308
  return false if !conditions || limit_value == 0
309
309
 
310
- conditions = sanitize_forbidden_attributes(conditions)
311
-
312
310
  if eager_loading?
313
311
  relation = apply_join_dependency(eager_loading: false)
314
312
  return relation.exists?(conditions)
@@ -316,7 +314,7 @@ module ActiveRecord
316
314
 
317
315
  relation = construct_relation_for_exists(conditions)
318
316
 
319
- skip_query_cache_if_necessary { connection.select_value(relation.arel, "#{name} Exists") } ? true : false
317
+ skip_query_cache_if_necessary { connection.select_one(relation.arel, "#{name} Exists") } ? true : false
320
318
  end
321
319
 
322
320
  # This method is called whenever no records are found with either a single
@@ -354,7 +352,13 @@ module ActiveRecord
354
352
  end
355
353
 
356
354
  def construct_relation_for_exists(conditions)
357
- relation = except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
355
+ conditions = sanitize_forbidden_attributes(conditions)
356
+
357
+ if distinct_value && offset_value
358
+ relation = limit(1)
359
+ else
360
+ relation = except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
361
+ end
358
362
 
359
363
  case conditions
360
364
  when Array, Hash
@@ -18,8 +18,10 @@ module ActiveRecord
18
18
  end
19
19
 
20
20
  def nil?
21
- !value_before_type_cast.is_a?(StatementCache::Substitute) &&
22
- (value_before_type_cast.nil? || value_for_database.nil?)
21
+ unless value_before_type_cast.is_a?(StatementCache::Substitute)
22
+ value_before_type_cast.nil? ||
23
+ type.respond_to?(:subtype, true) && value_for_database.nil?
24
+ end
23
25
  rescue ::RangeError
24
26
  end
25
27
 
@@ -32,7 +34,7 @@ module ActiveRecord
32
34
  if defined?(@_unboundable)
33
35
  @_unboundable
34
36
  else
35
- value_for_database
37
+ value_for_database unless value_before_type_cast.is_a?(StatementCache::Substitute)
36
38
  @_unboundable = nil
37
39
  end
38
40
  rescue ::RangeError
@@ -1052,11 +1052,13 @@ module ActiveRecord
1052
1052
 
1053
1053
  def arel_columns(columns)
1054
1054
  columns.flat_map do |field|
1055
- if (Symbol === field || String === field) && (klass.has_attribute?(field) || klass.attribute_alias?(field)) && !from_clause.value
1056
- arel_attribute(field)
1057
- elsif Symbol === field
1058
- connection.quote_table_name(field.to_s)
1059
- elsif Proc === field
1055
+ case field
1056
+ when Symbol
1057
+ field = field.to_s
1058
+ arel_column(field) { connection.quote_table_name(field) }
1059
+ when String
1060
+ arel_column(field) { field }
1061
+ when Proc
1060
1062
  field.call
1061
1063
  else
1062
1064
  field
@@ -1064,6 +1066,18 @@ module ActiveRecord
1064
1066
  end
1065
1067
  end
1066
1068
 
1069
+ def arel_column(field)
1070
+ field = klass.attribute_alias(field) if klass.attribute_alias?(field)
1071
+ from = from_clause.name || from_clause.value
1072
+
1073
+ if klass.columns_hash.key?(field) &&
1074
+ (!from || from == table.name || from == connection.quote_table_name(table.name))
1075
+ arel_attribute(field)
1076
+ else
1077
+ yield
1078
+ end
1079
+ end
1080
+
1067
1081
  def reverse_sql_order(order_query)
1068
1082
  if order_query.empty?
1069
1083
  return [arel_attribute(primary_key).desc] if primary_key
@@ -1099,7 +1113,7 @@ module ActiveRecord
1099
1113
  # Uses SQL function with multiple arguments.
1100
1114
  (order.include?(",") && order.split(",").find { |section| section.count("(") != section.count(")") }) ||
1101
1115
  # Uses "nulls first" like construction.
1102
- /nulls (first|last)\Z/i.match?(order)
1116
+ /\bnulls\s+(?:first|last)\b/i.match?(order)
1103
1117
  end
1104
1118
 
1105
1119
  def build_order(arel)
@@ -1145,14 +1159,20 @@ module ActiveRecord
1145
1159
  order_args.map! do |arg|
1146
1160
  case arg
1147
1161
  when Symbol
1148
- arel_attribute(arg).asc
1162
+ arg = arg.to_s
1163
+ arel_column(arg) {
1164
+ Arel.sql(connection.quote_table_name(arg))
1165
+ }.asc
1149
1166
  when Hash
1150
1167
  arg.map { |field, dir|
1151
1168
  case field
1152
1169
  when Arel::Nodes::SqlLiteral
1153
1170
  field.send(dir.downcase)
1154
1171
  else
1155
- arel_attribute(field).send(dir.downcase)
1172
+ field = field.to_s
1173
+ arel_column(field) {
1174
+ Arel.sql(connection.quote_table_name(field))
1175
+ }.send(dir.downcase)
1156
1176
  end
1157
1177
  }
1158
1178
  else
@@ -8,7 +8,7 @@ module ActiveRecord
8
8
  module SpawnMethods
9
9
  # This is overridden by Associations::CollectionProxy
10
10
  def spawn #:nodoc:
11
- @delegate_to_klass ? klass.all : clone
11
+ already_in_scope? ? klass.all : clone
12
12
  end
13
13
 
14
14
  # Merges in the conditions from <tt>other</tt>, if <tt>other</tt> is an ActiveRecord::Relation.
@@ -140,11 +140,7 @@ module ActiveRecord
140
140
 
141
141
  def except_predicates(columns)
142
142
  predicates.reject do |node|
143
- case node
144
- when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
145
- subrelation = (node.left.kind_of?(Arel::Attributes::Attribute) ? node.left : node.right)
146
- columns.include?(subrelation.name.to_s)
147
- end
143
+ Arel.fetch_attribute(node) { |attr| columns.include?(attr.name.to_s) }
148
144
  end
149
145
  end
150
146
 
@@ -23,14 +23,13 @@ module ActiveRecord
23
23
  current_scope
24
24
  end
25
25
 
26
- private
27
- def current_scope(skip_inherited_scope = false)
28
- ScopeRegistry.value_for(:current_scope, self, skip_inherited_scope)
29
- end
26
+ def current_scope(skip_inherited_scope = false)
27
+ ScopeRegistry.value_for(:current_scope, self, skip_inherited_scope)
28
+ end
30
29
 
31
- def current_scope=(scope)
32
- ScopeRegistry.set_value_for(:current_scope, self, scope)
33
- end
30
+ def current_scope=(scope)
31
+ ScopeRegistry.set_value_for(:current_scope, self, scope)
32
+ end
34
33
  end
35
34
 
36
35
  def populate_with_current_scope_attributes # :nodoc:
@@ -31,14 +31,7 @@ module ActiveRecord
31
31
  # Post.limit(10) # Fires "SELECT * FROM posts LIMIT 10"
32
32
  # }
33
33
  def unscoped
34
- block_given? ? _scoping(relation) { yield } : relation
35
- end
36
-
37
- def _scoping(relation) # :nodoc:
38
- previous, self.current_scope = current_scope(true), relation
39
- yield
40
- ensure
41
- self.current_scope = previous
34
+ block_given? ? relation.scoping { yield } : relation
42
35
  end
43
36
 
44
37
  # Are there attributes associated with this scope?
@@ -27,6 +27,14 @@ module ActiveRecord
27
27
  scope = current_scope
28
28
 
29
29
  if scope
30
+ if scope._deprecated_scope_source
31
+ ActiveSupport::Deprecation.warn(<<~MSG.squish)
32
+ Class level methods will no longer inherit scoping from `#{scope._deprecated_scope_source}`
33
+ in Rails 6.1. To continue using the scoped relation, pass it into the block directly.
34
+ To instead access the full set of models, as Rails 6.1 will, use `#{name}.unscoped`.
35
+ MSG
36
+ end
37
+
30
38
  if self == scope.klass
31
39
  scope.clone
32
40
  else
@@ -180,7 +188,7 @@ module ActiveRecord
180
188
 
181
189
  if body.respond_to?(:to_proc)
182
190
  singleton_class.define_method(name) do |*args|
183
- scope = all._exec_scope(*args, &body)
191
+ scope = all._exec_scope(name, *args, &body)
184
192
  scope = scope.extending(extension) if extension
185
193
  scope
186
194
  end
@@ -122,7 +122,7 @@ module ActiveRecord
122
122
  # Begin transactions for connections already established
123
123
  @fixture_connections = enlist_fixture_connections
124
124
  @fixture_connections.each do |connection|
125
- connection.begin_transaction joinable: false
125
+ connection.begin_transaction joinable: false, _lazy: false
126
126
  connection.pool.lock_thread = true if lock_threads
127
127
  end
128
128
 
@@ -138,7 +138,7 @@ module ActiveRecord
138
138
  end
139
139
 
140
140
  if connection && !@fixture_connections.include?(connection)
141
- connection.begin_transaction joinable: false
141
+ connection.begin_transaction joinable: false, _lazy: false
142
142
  connection.pool.lock_thread = true if lock_threads
143
143
  @fixture_connections << connection
144
144
  end
@@ -101,8 +101,8 @@ module ActiveRecord
101
101
  super
102
102
  end
103
103
 
104
- def _update_record(*args, touch: true, **options)
105
- if touch && should_record_timestamps?
104
+ def _update_record
105
+ if @_touch_record && should_record_timestamps?
106
106
  current_time = current_time_from_proper_timezone
107
107
 
108
108
  timestamp_attributes_for_update_in_model.each do |column|
@@ -110,7 +110,13 @@ module ActiveRecord
110
110
  _write_attribute(column, current_time)
111
111
  end
112
112
  end
113
- super(*args)
113
+
114
+ super
115
+ end
116
+
117
+ def create_or_update(touch: true, **)
118
+ @_touch_record = touch
119
+ super
114
120
  end
115
121
 
116
122
  def should_record_timestamps?
@@ -12,7 +12,7 @@ module ActiveRecord
12
12
  raise ArgumentError, "#{options[:scope]} is not supported format for :scope option. " \
13
13
  "Pass a symbol or an array of symbols instead: `scope: :user_id`"
14
14
  end
15
- super({ case_sensitive: true }.merge!(options))
15
+ super
16
16
  @klass = options[:class]
17
17
  end
18
18
 
@@ -62,6 +62,8 @@ module ActiveRecord
62
62
 
63
63
  if bind.nil?
64
64
  attr.eq(bind)
65
+ elsif !options.key?(:case_sensitive)
66
+ klass.connection.default_uniqueness_comparison(attr, bind)
65
67
  elsif options[:case_sensitive]
66
68
  klass.connection.case_sensitive_comparison(attr, bind)
67
69
  else
@@ -39,6 +39,13 @@ module Arel # :nodoc: all
39
39
  value.is_a?(Arel::Node) || value.is_a?(Arel::Attribute) || value.is_a?(Arel::Nodes::SqlLiteral)
40
40
  end
41
41
 
42
+ def self.fetch_attribute(value)
43
+ case value
44
+ when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
45
+ yield value.left.is_a?(Arel::Attributes::Attribute) ? value.left : value.right
46
+ end
47
+ end
48
+
42
49
  ## Convenience Alias
43
50
  Node = Arel::Nodes::Node
44
51
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Arel # :nodoc: all
4
4
  module Nodes
5
- class And < Arel::Nodes::Node
5
+ class And < Arel::Nodes::NodeExpression
6
6
  attr_reader :children
7
7
 
8
8
  def initialize(children)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Arel # :nodoc: all
4
4
  module Nodes
5
- class Case < Arel::Nodes::Node
5
+ class Case < Arel::Nodes::NodeExpression
6
6
  attr_accessor :case, :conditions, :default
7
7
 
8
8
  def initialize(expression = nil, default = nil)
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.0.0.beta1
4
+ version: 6.0.0.beta2
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: 2019-01-18 00:00:00.000000000 Z
11
+ date: 2019-02-25 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.0.0.beta1
19
+ version: 6.0.0.beta2
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.0.0.beta1
26
+ version: 6.0.0.beta2
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.0.0.beta1
33
+ version: 6.0.0.beta2
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.0.0.beta1
40
+ version: 6.0.0.beta2
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.
@@ -202,6 +202,9 @@ files:
202
202
  - lib/active_record/locking/optimistic.rb
203
203
  - lib/active_record/locking/pessimistic.rb
204
204
  - lib/active_record/log_subscriber.rb
205
+ - lib/active_record/middleware/database_selector.rb
206
+ - lib/active_record/middleware/database_selector/resolver.rb
207
+ - lib/active_record/middleware/database_selector/resolver/session.rb
205
208
  - lib/active_record/migration.rb
206
209
  - lib/active_record/migration/command_recorder.rb
207
210
  - lib/active_record/migration/compatibility.rb
@@ -385,8 +388,8 @@ homepage: http://rubyonrails.org
385
388
  licenses:
386
389
  - MIT
387
390
  metadata:
388
- source_code_uri: https://github.com/rails/rails/tree/v6.0.0.beta1/activerecord
389
- changelog_uri: https://github.com/rails/rails/blob/v6.0.0.beta1/activerecord/CHANGELOG.md
391
+ source_code_uri: https://github.com/rails/rails/tree/v6.0.0.beta2/activerecord
392
+ changelog_uri: https://github.com/rails/rails/blob/v6.0.0.beta2/activerecord/CHANGELOG.md
390
393
  post_install_message:
391
394
  rdoc_options:
392
395
  - "--main"