Count returns 0 without querying if parent is not saved #6978

Merged
merged 1 commit into from Oct 4, 2012

3 participants

@frodsan

Patches CollectionAssociation#count to return 0 without querying
if the parent record is new. Consider the following code:

class Account
  has_many :dossiers
end

class Dossier
  belongs_to :account
end

a = Account.new
a.dossiers.build

# before patch
a.dossiers.count
# SELECT COUNT(*) FROM "dossiers" WHERE "dossiers"."account_id" IS NULL
# => 0

# after
a.dosiers.count # fires without sql query
# => 0

Fixes #1856.

@rafaelfranca
Ruby on Rails member

Is not a good solution call length or size when owner is new_record?.

cc/ @tenderlove

@carlosantoniodasilva
Ruby on Rails member

Just want to point out that count may be only the tip of the iceberg, #5215 shows that all finders and scopes executed against an association actually execute a query, when they probably shouldn't.

@frodsan

@rafaelfranca I think size or length have a different behaviour:

>> a = User.new
=> #<User id: nil, name: nil, created_at: nil, updated_at: nil>
>> a.things.length
=> 0
>> a.things.new
=> #<Thing id: nil, user_id: nil, created_at: nil, updated_at: nil>
>> a.things.length
=> 1
>> a.things.count
   (0.3ms)  SELECT COUNT(*) FROM "things" WHERE "things"."user_id" = $1  [["user_id", nil]]
=> 0
@carlosantoniodasilva
Ruby on Rails member

@frodsan they have:

  • length with always load the objects and use Array#length
  • count will always do a SQL count
  • size will check whether the collection is loaded, and use it, otherwise will do a count.

size should give you the correct value in this case I think.

@rafaelfranca
Ruby on Rails member

Yes. I think count should always do a SQL count. In the case you pointed I think you should use size

@frodsan

updated :)

@rafaelfranca
Ruby on Rails member

I was thinking about this and I think is better to return 0.

size can return a different value and is expected to count do a SQL query, so if the we call count in a new record we should always return 0 because we don't have any data in the database.

@rafaelfranca
Ruby on Rails member

Good. Changelog entry please

@frodsan

done :)

@rafaelfranca rafaelfranca commented on an outdated diff Oct 3, 2012
activerecord/CHANGELOG.md
@@ -1,5 +1,22 @@
## Rails 4.0.0 (unreleased) ##
+* `CollectionAssociation#count` returns 0 without querying if the
+ parent record is new.
+
+ Before:
+
+ person.pets
+ # SELECT COUNT(*) FROM "pets" ...
@rafaelfranca
Ruby on Rails member
rafaelfranca added a line comment Oct 3, 2012

is better to put the full sql with the WHERE people.id IS NULL (I don't know if this is the right SQL

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Francesco Rodriguez Count returns 0 without querying if parent is not saved
Patches `CollectionAssociation#count` to return 0 without querying
if the parent record is new. Consider the following code:

    class Account
      has_many :dossiers
    end

    class Dossier
      belongs_to :account
    end

    a = Account.new
    a.dossiers.build

    # before patch
    a.dossiers.count
    # SELECT COUNT(*) FROM "dossiers" WHERE "dossiers"."account_id" IS NULL
    # => 0

    # after
    a.dosiers.count # fires without sql query
    # => 0

Fixes #1856.
aa202ad
@rafaelfranca rafaelfranca merged commit 3a63fe3 into rails:master Oct 4, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment