activerecord 5.1.3 → 5.1.4.rc1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 665c9955e9a92c7003f1d8e69d22b4d763c28a73
4
- data.tar.gz: 72aa948f6d334ab46b4b1ca8c509962f3a6faed0
3
+ metadata.gz: 0a6eda8b079f4604ae848be44d3c3f272b20cc90
4
+ data.tar.gz: 0244a2cff9dce5220301b717f6aac1690c101de7
5
5
  SHA512:
6
- metadata.gz: 256a3bcc2ab03a608893c438b792df66458369b7ae5cf8c6b9e3ca80836ae64c12c3a97e05c5d51e8642dc504129de9a70f2367537026b18901c7da9e8246ad2
7
- data.tar.gz: 16a897c077082840b0fd5b43cd50938863a9a99715be99a9e04c29e972ae3301ebbd1a1871b0abeb745b119250675c211dda603a69ba8aa67fba50cb5fd06d10
6
+ metadata.gz: ba0aa505e0f08c935c134a4904f65b79861a51b16afd31fb08f713099e61b9e9a7418d79831bbd4eaf9e507b6db0af723396b380300f5fa7e4213d6d5a38ddf7
7
+ data.tar.gz: 3aa924d1ea393fb9f5501c4239617a7fc1f9a1e959d2f9eb6ba194fd89420dc226903b9a2df4297bd2c0c1585c3e7ced24fc83881b0ba88efb9401e277b2c5dc
@@ -1,3 +1,37 @@
1
+ ## Rails 5.1.4.rc1 (August 24, 2017) ##
2
+
3
+ * Ensure `sum` honors `distinct` on `has_many :through` associations
4
+
5
+ Fixes #16791
6
+
7
+ *Aaron Wortham
8
+
9
+ * Fix `COUNT(DISTINCT ...)` with `ORDER BY` and `LIMIT` to keep the existing select list.
10
+
11
+ *Ryuta Kamizono*
12
+
13
+ * Fix `unscoped(where: [columns])` removing the wrong bind values
14
+
15
+ When the `where` is called on a relation after a `or`, unscoping the column of that later `where`, it removed
16
+ bind values used by the `or` instead.
17
+
18
+ ```
19
+ Post.where(id: 1).or(Post.where(id: 2)).where(foo: 3).unscope(where: :foo).to_sql
20
+ # Currently:
21
+ # SELECT "posts".* FROM "posts" WHERE ("posts"."id" = 2 OR "posts"."id" = 3)
22
+ # With fix:
23
+ # SELECT "posts".* FROM "posts" WHERE ("posts"."id" = 1 OR "posts"."id" = 2)
24
+ ```
25
+
26
+ *Maxime Handfield Lapointe*
27
+
28
+ * When a `has_one` association is destroyed by `dependent: destroy`,
29
+ `destroyed_by_association` will now be set to the reflection, matching the
30
+ behaviour of `has_many` associations.
31
+
32
+ *Lisa Ugray*
33
+
34
+
1
35
  ## Rails 5.1.3 (August 03, 2017) ##
2
36
 
3
37
  * No changes.
@@ -222,13 +222,6 @@ module ActiveRecord
222
222
  autoload :CollectionAssociation
223
223
  autoload :ForeignAssociation
224
224
  autoload :CollectionProxy
225
-
226
- autoload :BelongsToAssociation
227
- autoload :BelongsToPolymorphicAssociation
228
- autoload :HasManyAssociation
229
- autoload :HasManyThroughAssociation
230
- autoload :HasOneAssociation
231
- autoload :HasOneThroughAssociation
232
225
  autoload :ThroughAssociation
233
226
 
234
227
  module Builder #:nodoc:
@@ -243,6 +236,13 @@ module ActiveRecord
243
236
  end
244
237
 
245
238
  eager_autoload do
239
+ autoload :BelongsToAssociation
240
+ autoload :BelongsToPolymorphicAssociation
241
+ autoload :HasManyAssociation
242
+ autoload :HasManyThroughAssociation
243
+ autoload :HasOneAssociation
244
+ autoload :HasOneThroughAssociation
245
+
246
246
  autoload :Preloader
247
247
  autoload :JoinDependency
248
248
  autoload :AssociationScope
@@ -342,17 +342,18 @@ module ActiveRecord
342
342
  # | | belongs_to |
343
343
  # generated methods | belongs_to | :polymorphic | has_one
344
344
  # ----------------------------------+------------+--------------+---------
345
- # other(force_reload=false) | X | X | X
345
+ # other | X | X | X
346
346
  # other=(other) | X | X | X
347
347
  # build_other(attributes={}) | X | | X
348
348
  # create_other(attributes={}) | X | | X
349
349
  # create_other!(attributes={}) | X | | X
350
+ # reload_other | X | X | X
350
351
  #
351
352
  # === Collection associations (one-to-many / many-to-many)
352
353
  # | | | has_many
353
354
  # generated methods | habtm | has_many | :through
354
355
  # ----------------------------------+-------+----------+----------
355
- # others(force_reload=false) | X | X | X
356
+ # others | X | X | X
356
357
  # others=(other,other,...) | X | X | X
357
358
  # other_ids | X | X | X
358
359
  # other_ids=(id,id,...) | X | X | X
@@ -376,6 +377,7 @@ module ActiveRecord
376
377
  # others.exists? | X | X | X
377
378
  # others.distinct | X | X | X
378
379
  # others.reset | X | X | X
380
+ # others.reload | X | X | X
379
381
  #
380
382
  # === Overriding generated methods
381
383
  #
@@ -1188,8 +1190,8 @@ module ActiveRecord
1188
1190
  # <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>.
1189
1191
  #
1190
1192
  # [collection(force_reload = false)]
1191
- # Returns an array of all the associated objects.
1192
- # An empty array is returned if none are found.
1193
+ # Returns a Relation of all the associated objects.
1194
+ # An empty Relation is returned if none are found.
1193
1195
  # [collection<<(object, ...)]
1194
1196
  # Adds one or more objects to the collection by setting their foreign keys to the collection's primary key.
1195
1197
  # Note that this operation instantly fires update SQL without waiting for the save or update call on the
@@ -1246,6 +1248,9 @@ module ActiveRecord
1246
1248
  # [collection.create!(attributes = {})]
1247
1249
  # Does the same as <tt>collection.create</tt>, but raises ActiveRecord::RecordInvalid
1248
1250
  # if the record is invalid.
1251
+ # [collection.reload]
1252
+ # Returns a Relation of all of the associated objects, forcing a database read.
1253
+ # An empty Relation is returned if none are found.
1249
1254
  #
1250
1255
  # === Example
1251
1256
  #
@@ -1265,6 +1270,7 @@ module ActiveRecord
1265
1270
  # * <tt>Firm#clients.build</tt> (similar to <tt>Client.new("firm_id" => id)</tt>)
1266
1271
  # * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save; c</tt>)
1267
1272
  # * <tt>Firm#clients.create!</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save!</tt>)
1273
+ # * <tt>Firm#clients.reload</tt>
1268
1274
  # The declaration can also include an +options+ hash to specialize the behavior of the association.
1269
1275
  #
1270
1276
  # === Scopes
@@ -1407,7 +1413,7 @@ module ActiveRecord
1407
1413
  # +association+ is a placeholder for the symbol passed as the +name+ argument, so
1408
1414
  # <tt>has_one :manager</tt> would add among others <tt>manager.nil?</tt>.
1409
1415
  #
1410
- # [association(force_reload = false)]
1416
+ # [association]
1411
1417
  # Returns the associated object. +nil+ is returned if none is found.
1412
1418
  # [association=(associate)]
1413
1419
  # Assigns the associate object, extracts the primary key, sets it as the foreign key,
@@ -1424,6 +1430,8 @@ module ActiveRecord
1424
1430
  # [create_association!(attributes = {})]
1425
1431
  # Does the same as <tt>create_association</tt>, but raises ActiveRecord::RecordInvalid
1426
1432
  # if the record is invalid.
1433
+ # [reload_association]
1434
+ # Returns the associated object, forcing a database read.
1427
1435
  #
1428
1436
  # === Example
1429
1437
  #
@@ -1433,6 +1441,7 @@ module ActiveRecord
1433
1441
  # * <tt>Account#build_beneficiary</tt> (similar to <tt>Beneficiary.new("account_id" => id)</tt>)
1434
1442
  # * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save; b</tt>)
1435
1443
  # * <tt>Account#create_beneficiary!</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save!; b</tt>)
1444
+ # * <tt>Account#reload_beneficiary</tt>
1436
1445
  #
1437
1446
  # === Scopes
1438
1447
  #
@@ -1539,7 +1548,7 @@ module ActiveRecord
1539
1548
  # +association+ is a placeholder for the symbol passed as the +name+ argument, so
1540
1549
  # <tt>belongs_to :author</tt> would add among others <tt>author.nil?</tt>.
1541
1550
  #
1542
- # [association(force_reload = false)]
1551
+ # [association]
1543
1552
  # Returns the associated object. +nil+ is returned if none is found.
1544
1553
  # [association=(associate)]
1545
1554
  # Assigns the associate object, extracts the primary key, and sets it as the foreign key.
@@ -1553,6 +1562,8 @@ module ActiveRecord
1553
1562
  # [create_association!(attributes = {})]
1554
1563
  # Does the same as <tt>create_association</tt>, but raises ActiveRecord::RecordInvalid
1555
1564
  # if the record is invalid.
1565
+ # [reload_association]
1566
+ # Returns the associated object, forcing a database read.
1556
1567
  #
1557
1568
  # === Example
1558
1569
  #
@@ -1562,6 +1573,7 @@ module ActiveRecord
1562
1573
  # * <tt>Post#build_author</tt> (similar to <tt>post.author = Author.new</tt>)
1563
1574
  # * <tt>Post#create_author</tt> (similar to <tt>post.author = Author.new; post.author.save; post.author</tt>)
1564
1575
  # * <tt>Post#create_author!</tt> (similar to <tt>post.author = Author.new; post.author.save!; post.author</tt>)
1576
+ # * <tt>Post#reload_author</tt>
1565
1577
  # The declaration can also include an +options+ hash to specialize the behavior of the association.
1566
1578
  #
1567
1579
  # === Scopes
@@ -1701,9 +1713,9 @@ module ActiveRecord
1701
1713
  # +collection+ is a placeholder for the symbol passed as the +name+ argument, so
1702
1714
  # <tt>has_and_belongs_to_many :categories</tt> would add among others <tt>categories.empty?</tt>.
1703
1715
  #
1704
- # [collection(force_reload = false)]
1705
- # Returns an array of all the associated objects.
1706
- # An empty array is returned if none are found.
1716
+ # [collection]
1717
+ # Returns a Relation of all the associated objects.
1718
+ # An empty Relation is returned if none are found.
1707
1719
  # [collection<<(object, ...)]
1708
1720
  # Adds one or more objects to the collection by creating associations in the join table
1709
1721
  # (<tt>collection.push</tt> and <tt>collection.concat</tt> are aliases to this method).
@@ -1741,6 +1753,9 @@ module ActiveRecord
1741
1753
  # Returns a new object of the collection type that has been instantiated
1742
1754
  # with +attributes+, linked to this object through the join table, and that has already been
1743
1755
  # saved (if it passed the validation).
1756
+ # [collection.reload]
1757
+ # Returns a Relation of all of the associated objects, forcing a database read.
1758
+ # An empty Relation is returned if none are found.
1744
1759
  #
1745
1760
  # === Example
1746
1761
  #
@@ -1759,6 +1774,7 @@ module ActiveRecord
1759
1774
  # * <tt>Developer#projects.exists?(...)</tt>
1760
1775
  # * <tt>Developer#projects.build</tt> (similar to <tt>Project.new("developer_id" => id)</tt>)
1761
1776
  # * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new("developer_id" => id); c.save; c</tt>)
1777
+ # * <tt>Developer#projects.reload</tt>
1762
1778
  # The declaration may include an +options+ hash to specialize the behavior of the association.
1763
1779
  #
1764
1780
  # === Scopes
@@ -66,11 +66,11 @@ module ActiveRecord
66
66
  foreign_key = join_keys.foreign_key
67
67
 
68
68
  value = transform_value(owner[foreign_key])
69
- scope = scope.where(table.name => { key => value })
69
+ scope = apply_scope(scope, table, key, value)
70
70
 
71
71
  if reflection.type
72
72
  polymorphic_type = transform_value(owner.class.base_class.name)
73
- scope = scope.where(table.name => { reflection.type => polymorphic_type })
73
+ scope = apply_scope(scope, table, reflection.type, polymorphic_type)
74
74
  end
75
75
 
76
76
  scope
@@ -89,10 +89,10 @@ module ActiveRecord
89
89
 
90
90
  if reflection.type
91
91
  value = transform_value(next_reflection.klass.base_class.name)
92
- scope = scope.where(table.name => { reflection.type => value })
92
+ scope = apply_scope(scope, table, reflection.type, value)
93
93
  end
94
94
 
95
- scope = scope.joins(join(foreign_table, constraint))
95
+ scope.joins!(join(foreign_table, constraint))
96
96
  end
97
97
 
98
98
  class ReflectionProxy < SimpleDelegator # :nodoc:
@@ -163,6 +163,14 @@ module ActiveRecord
163
163
  scope
164
164
  end
165
165
 
166
+ def apply_scope(scope, table, key, value)
167
+ if scope.table == table
168
+ scope.where!(key => value)
169
+ else
170
+ scope.where!(table.name => { key => value })
171
+ end
172
+ end
173
+
166
174
  def eval_scope(klass, table, scope, owner)
167
175
  predicate_builder = PredicateBuilder.new(TableMetadata.new(klass, table))
168
176
  ActiveRecord::Relation.create(klass, table, predicate_builder).instance_exec(owner, &scope)
@@ -53,11 +53,14 @@ module ActiveRecord
53
53
  pk_type = reflection.association_primary_key_type
54
54
  ids = Array(ids).reject(&:blank?)
55
55
  ids.map! { |i| pk_type.cast(i) }
56
- records = klass.where(reflection.association_primary_key => ids).index_by do |r|
57
- r.send(reflection.association_primary_key)
56
+
57
+ primary_key = reflection.association_primary_key
58
+ records = klass.where(primary_key => ids).index_by do |r|
59
+ r.public_send(primary_key)
58
60
  end.values_at(*ids).compact
61
+
59
62
  if records.size != ids.size
60
- klass.all.raise_record_not_found_exception!(ids, records.size, ids.size, reflection.association_primary_key)
63
+ klass.all.raise_record_not_found_exception!(ids, records.size, ids.size, primary_key)
61
64
  else
62
65
  replace(records)
63
66
  end
@@ -56,6 +56,7 @@ module ActiveRecord
56
56
  when :delete
57
57
  target.delete
58
58
  when :destroy
59
+ target.destroyed_by_association = reflection
59
60
  target.destroy
60
61
  when :nullify
61
62
  target.update_columns(reflection.foreign_key => nil) if target.persisted?
@@ -78,6 +79,7 @@ module ActiveRecord
78
79
  when :delete
79
80
  target.delete
80
81
  when :destroy
82
+ target.destroyed_by_association = reflection
81
83
  target.destroy
82
84
  else
83
85
  nullify_owner_attributes(target)
@@ -162,7 +162,7 @@ module ActiveRecord
162
162
  end
163
163
 
164
164
  scope.unscope_values = Array(values[:unscope]) + Array(preload_values[:unscope])
165
- klass.default_scoped.merge(scope)
165
+ klass.scope_for_association.merge(scope)
166
166
  end
167
167
  end
168
168
  end
@@ -13,7 +13,7 @@ module ActiveRecord
13
13
  def target_scope
14
14
  scope = super
15
15
  reflection.chain.drop(1).each do |reflection|
16
- relation = reflection.klass.all
16
+ relation = reflection.klass.scope_for_association
17
17
  scope.merge!(
18
18
  relation.except(:select, :create_with, :includes, :preload, :joins, :eager_load)
19
19
  )
@@ -122,7 +122,7 @@ module ActiveRecord
122
122
 
123
123
  def encode_with(coder)
124
124
  coder["name"] = name
125
- coder["value_before_type_cast"] = value_before_type_cast if value_before_type_cast
125
+ coder["value_before_type_cast"] = value_before_type_cast unless value_before_type_cast.nil?
126
126
  coder["type"] = type if type
127
127
  coder["original_attribute"] = original_attribute if original_attribute
128
128
  coder["value"] = value if defined?(@value)
@@ -4,7 +4,7 @@ require "active_record/attribute_mutation_tracker"
4
4
 
5
5
  module ActiveRecord
6
6
  module AttributeMethods
7
- module Dirty # :nodoc:
7
+ module Dirty
8
8
  extend ActiveSupport::Concern
9
9
 
10
10
  include ActiveModel::Dirty
@@ -68,33 +68,33 @@ module ActiveRecord
68
68
  @mutations_from_database = AttributeMutationTracker.new(@attributes)
69
69
  end
70
70
 
71
- def changes_applied
71
+ def changes_applied # :nodoc:
72
72
  @previous_mutation_tracker = mutation_tracker
73
73
  @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
74
74
  clear_mutation_trackers
75
75
  end
76
76
 
77
- def clear_changes_information
77
+ def clear_changes_information # :nodoc:
78
78
  @previous_mutation_tracker = nil
79
79
  @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
80
80
  forget_attribute_assignments
81
81
  clear_mutation_trackers
82
82
  end
83
83
 
84
- def raw_write_attribute(attr_name, *)
84
+ def raw_write_attribute(attr_name, *) # :nodoc:
85
85
  result = super
86
86
  clear_attribute_change(attr_name)
87
87
  result
88
88
  end
89
89
 
90
- def clear_attribute_changes(attr_names)
90
+ def clear_attribute_changes(attr_names) # :nodoc:
91
91
  super
92
92
  attr_names.each do |attr_name|
93
93
  clear_attribute_change(attr_name)
94
94
  end
95
95
  end
96
96
 
97
- def changed_attributes
97
+ def changed_attributes # :nodoc:
98
98
  # This should only be set by methods which will call changed_attributes
99
99
  # multiple times when it is known that the computed value cannot change.
100
100
  if defined?(@cached_changed_attributes)
@@ -105,14 +105,14 @@ module ActiveRecord
105
105
  end
106
106
  end
107
107
 
108
- def changes
108
+ def changes # :nodoc:
109
109
  cache_changed_attributes do
110
110
  emit_warning_if_needed("changes", "saved_changes")
111
111
  super
112
112
  end
113
113
  end
114
114
 
115
- def previous_changes
115
+ def previous_changes # :nodoc:
116
116
  unless previous_mutation_tracker.equal?(mutations_before_last_save)
117
117
  ActiveSupport::Deprecation.warn(<<-EOW.strip_heredoc)
118
118
  The behavior of `previous_changes` inside of after callbacks is
@@ -124,7 +124,7 @@ module ActiveRecord
124
124
  previous_mutation_tracker.changes
125
125
  end
126
126
 
127
- def attribute_changed_in_place?(attr_name)
127
+ def attribute_changed_in_place?(attr_name) # :nodoc:
128
128
  mutation_tracker.changed_in_place?(attr_name)
129
129
  end
130
130
 
@@ -14,7 +14,7 @@ module ActiveRecord
14
14
  column = "#{connection.quote_table_name(collection.table_name)}.#{connection.quote_column_name(timestamp_column)}"
15
15
  select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
16
16
 
17
- if collection.limit_value || collection.offset_value
17
+ if collection.has_limit_or_offset?
18
18
  query = collection.spawn
19
19
  query.select_values = [column]
20
20
  subquery_alias = "subquery_for_cache_key"
@@ -71,12 +71,12 @@ module ActiveRecord
71
71
  @statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
72
72
 
73
73
  if version < "5.1.10"
74
- raise "Your version of MySQL (#{full_version.match(/^\d+\.\d+\.\d+/)[0]}) is too old. Active Record supports MySQL >= 5.1.10."
74
+ raise "Your version of MySQL (#{version_string}) is too old. Active Record supports MySQL >= 5.1.10."
75
75
  end
76
76
  end
77
77
 
78
78
  def version #:nodoc:
79
- @version ||= Version.new(full_version.match(/^\d+\.\d+\.\d+/)[0])
79
+ @version ||= Version.new(version_string)
80
80
  end
81
81
 
82
82
  def mariadb? # :nodoc:
@@ -340,8 +340,8 @@ module ActiveRecord
340
340
 
341
341
  def new_column_from_field(table_name, field) # :nodoc:
342
342
  type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
343
- if type_metadata.type == :datetime && field[:Default] == "CURRENT_TIMESTAMP"
344
- default, default_function = nil, field[:Default]
343
+ if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\(\))?\z/i.match?(field[:Default])
344
+ default, default_function = nil, "CURRENT_TIMESTAMP"
345
345
  else
346
346
  default, default_function = field[:Default], nil
347
347
  end
@@ -914,12 +914,11 @@ module ActiveRecord
914
914
  end
915
915
  end
916
916
 
917
+ def version_string
918
+ full_version.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
919
+ end
920
+
917
921
  class MysqlJson < Type::Internal::AbstractJson # :nodoc:
918
- def changed_in_place?(raw_old_value, new_value)
919
- # Normalization is required because MySQL JSON data format includes
920
- # the space between the elements.
921
- super(serialize(deserialize(raw_old_value)), new_value)
922
- end
923
922
  end
924
923
 
925
924
  class MysqlString < Type::String # :nodoc:
@@ -53,7 +53,7 @@ module ActiveRecord
53
53
  end
54
54
 
55
55
  def extract_expression_for_virtual_column(column)
56
- if mariadb?
56
+ if mariadb? && version < "10.2.5"
57
57
  create_table_info = create_table_info(column.table_name)
58
58
  if %r/#{quote_column_name(column.name)} #{Regexp.quote(column.sql_type)}(?: COLLATE \w+)? AS \((?<expression>.+?)\) #{column.extra}/ =~ create_table_info
59
59
  $~[:expression].inspect
@@ -6,16 +6,6 @@ module ActiveRecord
6
6
  def type
7
7
  :jsonb
8
8
  end
9
-
10
- def changed_in_place?(raw_old_value, new_value)
11
- # Postgres does not preserve insignificant whitespaces when
12
- # round-tripping jsonb columns. This causes some false positives for
13
- # the comparison here. Therefore, we need to parse and re-dump the
14
- # raw value here to ensure the insignificant whitespaces are
15
- # consistent with our encoder's output.
16
- raw_old_value = serialize(deserialize(raw_old_value))
17
- super(raw_old_value, new_value)
18
- end
19
9
  end
20
10
  end
21
11
  end
@@ -7,8 +7,8 @@ module ActiveRecord
7
7
  module VERSION
8
8
  MAJOR = 5
9
9
  MINOR = 1
10
- TINY = 3
11
- PRE = nil
10
+ TINY = 4
11
+ PRE = "rc1"
12
12
 
13
13
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
14
14
  end
@@ -197,16 +197,8 @@ module ActiveRecord
197
197
  end
198
198
 
199
199
  def klass_join_scope(table, predicate_builder) # :nodoc:
200
- if klass.current_scope && klass.current_scope.values.empty?
201
- klass.unscoped
202
- else
203
- relation = ActiveRecord::Relation.create(
204
- klass,
205
- table,
206
- predicate_builder,
207
- )
208
- klass.send(:build_default_scope, relation)
209
- end
200
+ relation = ActiveRecord::Relation.create(klass, table, predicate_builder)
201
+ klass.scope_for_association(relation)
210
202
  end
211
203
 
212
204
  def constraints
@@ -692,6 +684,10 @@ module ActiveRecord
692
684
  Associations::HasManyAssociation
693
685
  end
694
686
  end
687
+
688
+ def association_primary_key(klass = nil)
689
+ primary_key(klass || self.klass)
690
+ end
695
691
  end
696
692
 
697
693
  class HasOneReflection < AssociationReflection # :nodoc:
@@ -642,6 +642,14 @@ module ActiveRecord
642
642
  "#<#{self.class.name} [#{entries.join(', ')}]>"
643
643
  end
644
644
 
645
+ def empty_scope? # :nodoc:
646
+ @values == klass.unscoped.values
647
+ end
648
+
649
+ def has_limit_or_offset? # :nodoc:
650
+ limit_value || offset_value
651
+ end
652
+
645
653
  protected
646
654
 
647
655
  def load_records(records)
@@ -111,7 +111,7 @@ module ActiveRecord
111
111
  def calculate(operation, column_name)
112
112
  if has_include?(column_name)
113
113
  relation = construct_relation_for_association_calculations
114
- relation = relation.distinct if operation.to_s.downcase == "count"
114
+ relation.distinct! if operation.to_s.downcase == "count"
115
115
 
116
116
  relation.calculate(operation, column_name)
117
117
  else
@@ -194,8 +194,13 @@ module ActiveRecord
194
194
 
195
195
  if operation == "count"
196
196
  column_name ||= select_for_count
197
- column_name = primary_key if column_name == :all && distinct
198
- distinct = nil if column_name =~ /\s*DISTINCT[\s(]+/i
197
+ if column_name == :all
198
+ if distinct && !(has_limit_or_offset? && order_values.any?)
199
+ column_name = primary_key
200
+ end
201
+ elsif column_name =~ /\s*DISTINCT[\s(]+/i
202
+ distinct = nil
203
+ end
199
204
  end
200
205
 
201
206
  if group_values.any?
@@ -222,7 +227,7 @@ module ActiveRecord
222
227
  def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
223
228
  column_alias = column_name
224
229
 
225
- if operation == "count" && (limit_value || offset_value)
230
+ if operation == "count" && has_limit_or_offset?
226
231
  # Shortcut when limit is zero.
227
232
  return 0 if limit_value == 0
228
233
 
@@ -234,6 +239,9 @@ module ActiveRecord
234
239
  column = aggregate_column(column_name)
235
240
 
236
241
  select_value = operation_over_aggregate_column(column, operation, distinct)
242
+ if operation == "sum" && distinct
243
+ select_value.distinct = true
244
+ end
237
245
 
238
246
  column_alias = select_value.alias
239
247
  column_alias ||= @klass.connection.column_name_for_operation(operation, select_value)
@@ -361,16 +369,19 @@ module ActiveRecord
361
369
  end
362
370
 
363
371
  def build_count_subquery(relation, column_name, distinct)
364
- column_alias = Arel.sql("count_column")
365
- subquery_alias = Arel.sql("subquery_for_count")
372
+ relation.select_values = [
373
+ if column_name == :all
374
+ distinct ? table[Arel.star] : Arel.sql("1")
375
+ else
376
+ column_alias = Arel.sql("count_column")
377
+ aggregate_column(column_name).as(column_alias)
378
+ end
379
+ ]
366
380
 
367
- aliased_column = aggregate_column(column_name == :all ? 1 : column_name).as(column_alias)
368
- relation.select_values = [aliased_column]
369
- subquery = relation.arel.as(subquery_alias)
381
+ subquery = relation.arel.as(Arel.sql("subquery_for_count"))
382
+ select_value = operation_over_aggregate_column(column_alias || Arel.star, "count", false)
370
383
 
371
- sm = Arel::SelectManager.new relation.engine
372
- select_value = operation_over_aggregate_column(column_alias, "count", distinct)
373
- sm.project(select_value).from(subquery)
384
+ Arel::SelectManager.new(subquery).project(select_value)
374
385
  end
375
386
  end
376
387
  end
@@ -136,10 +136,11 @@ module ActiveRecord
136
136
  binds_index = 0
137
137
 
138
138
  predicates = self.predicates.reject do |node|
139
+ binds_contains = node.grep(Arel::Nodes::BindParam).size if node.is_a?(Arel::Nodes::Node)
140
+
139
141
  except = \
140
142
  case node
141
143
  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
142
- binds_contains = node.grep(Arel::Nodes::BindParam).size
143
144
  subrelation = (node.left.kind_of?(Arel::Attributes::Attribute) ? node.left : node.right)
144
145
  columns.include?(subrelation.name.to_s)
145
146
  end
@@ -29,8 +29,17 @@ module ActiveRecord
29
29
  end
30
30
  end
31
31
 
32
- def default_scoped # :nodoc:
33
- scope = relation
32
+ def scope_for_association(scope = relation) # :nodoc:
33
+ current_scope = self.current_scope
34
+
35
+ if current_scope && current_scope.empty_scope?
36
+ scope
37
+ else
38
+ default_scoped(scope)
39
+ end
40
+ end
41
+
42
+ def default_scoped(scope = relation) # :nodoc:
34
43
  build_default_scope(scope) || scope
35
44
  end
36
45
 
@@ -20,7 +20,7 @@ module ActiveRecord
20
20
  configuration.merge("encoding" => encoding)
21
21
  establish_connection configuration
22
22
  rescue ActiveRecord::StatementInvalid => error
23
- if /database .* already exists/.match?(error.message)
23
+ if error.cause.is_a?(PG::DuplicateDatabase)
24
24
  raise DatabaseAlreadyExists
25
25
  else
26
26
  raise
@@ -24,6 +24,10 @@ module ActiveRecord
24
24
  end
25
25
  end
26
26
 
27
+ def changed_in_place?(raw_old_value, new_value)
28
+ deserialize(raw_old_value) != new_value
29
+ end
30
+
27
31
  def accessor
28
32
  ActiveRecord::Store::StringKeyedHashAccessor
29
33
  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.3
4
+ version: 5.1.4.rc1
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: 2017-08-03 00:00:00.000000000 Z
11
+ date: 2017-08-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: 5.1.3
19
+ version: 5.1.4.rc1
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.3
26
+ version: 5.1.4.rc1
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.3
33
+ version: 5.1.4.rc1
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.3
40
+ version: 5.1.4.rc1
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: arel
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -333,9 +333,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
333
333
  version: 2.2.2
334
334
  required_rubygems_version: !ruby/object:Gem::Requirement
335
335
  requirements:
336
- - - ">="
336
+ - - ">"
337
337
  - !ruby/object:Gem::Version
338
- version: '0'
338
+ version: 1.3.1
339
339
  requirements: []
340
340
  rubyforge_project:
341
341
  rubygems_version: 2.6.12