DEV Community

FaxriddinMaxmadiyorov
FaxriddinMaxmadiyorov

Posted on

What’s the Difference Between count, size, and length in Ruby and Ruby on Rails?

In plain Ruby, there’s effectively no difference between count, size, and length when working with arrays or other collection-like objects — they all return the number of elements.

arr = [1, 2, 3]
arr.count   # => 3
arr.size    # => 3
arr.length  # => 3
Enter fullscreen mode Exit fullscreen mode

However, in Ruby on Rails, particularly when dealing with ActiveRecord associations or query objects, these methods behave very differently under the hood — especially in terms of performance and when they trigger database queries.

Understanding these differences is crucial when you're working with large datasets or optimizing performance in a Rails application.

Let's take an example:

users = User.where(active: true)
users.class # User::ActiveRecord_Relation # its returns ActiveRecord, does not execute the query in this stage
Enter fullscreen mode Exit fullscreen mode

At this point, users is an ActiveRecord::Relation, not an array. That means the database query has not been executed yet — it's just a representation of the query to be run later.

This is a key feature of ActiveRecord: lazy loading. The query will only be executed when the data is actually needed — for example, when you iterate over the records, call .to_a, or use .length.

.count

Since users is an ActiveRecord::Relation, calling .count on it will immediately execute a SQL COUNT(*) query to count the number of matching records — without loading the actual records into memory.

[51] pry(main)> users.count
   (0.6ms)  SELECT COUNT(*) FROM "users" WHERE "users"."active" = $1 /*application:Pixie*/  [["active", true]]
=> 32
Enter fullscreen mode Exit fullscreen mode

✅ This is efficient when you only need the number of records, not the records themselves.

⚠️ Note: .count always queries the database, even if the relation was previously loaded.

.length

The .length method always loads the records into memory and then calculates the number of elements by calling Array#length.

users = User.where(active: true)
users.length  # => runs SELECT * FROM users WHERE active = true
Enter fullscreen mode Exit fullscreen mode

This converts the relation into an array and then returns the number of elements.

⚠️ Important: This can be inefficient for large datasets because it loads all matching records into memory, even if you only need the count.

✅ Use .length only when you actually need the full records — for example, if you're going to iterate over them right after.

.size

The .size method is smart — it adapts based on whether the records have already been loaded into memory.

✅ If the records are already loaded, .size simply returns the number of records in memory:

users.loaded?
# => true

users.size
# => 32  (No additional SQL query is executed)
Enter fullscreen mode Exit fullscreen mode

✅ If the records are not yet loaded, .size behaves like .count and runs a SQL COUNT(*) query:

users.loaded?
# => false

users.size
# => Executes:
# SELECT COUNT(*) FROM "users" WHERE "users"."active" = $1
# => 32
Enter fullscreen mode Exit fullscreen mode

This makes .size the most efficient and flexible choice in many cases — it avoids unnecessary queries but still gives an accurate count.

Top comments (1)

Collapse
 
otayor_yusupov_f7783f2303 profile image
Otayor Yusupov

+useful