What is the difference between using .exists?, and .present? in Ruby?

Ruby on-RailsRuby

Ruby on-Rails Problem Overview


I want to make sure I'm using them for the correct occasion and want to know of any subtleties. They seem to function the same way, which is to check to see if a object field has been defined, when I use them via the console and there isn't a whole lot information online when I did a google search. Thanks!

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

To clarify: neither present? nor exists? are "pure" ruby—they're both from Rails-land.

present?

present? is an ActiveSupport extension to Object. It's usually used as a test for an object's general "falsiness". From the documentation:

> An object is present if it’s not blank?. An object is blank if it’s false, empty, or a whitespace string.

So, for example:

[ "", " ", false, nil, [], {} ].any?(&:present?)
# => false

exists?

exists? is from ActiveResource. From its documentation:

> Asserts the existence of a resource, returning true if the resource is found.

Note.create(:title => 'Hello, world.', :body => 'Nothing more for now...')
Note.exists?(1) # => true

Solution 2 - Ruby on-Rails

The big difference between the two methods, is that when you call present? it initializes ActiveRecord for each record found(!), while exists? does not

to show this I added after_initialize on User. it prints: 'You have initialized an object!'

> User.where(name: 'mike').present?

User Load (8.1ms) SELECT "users".* FROM "users" WHERE "users"."name" = $1 ORDER BY users.id ASC  [["name", 'mike']]
You have initialized an object!
You have initialized an object!

> User.exists?(name: 'mike')

User Exists (2.4ms)  SELECT 1 AS one FROM "users" WHERE "users"."name" = $1 ORDER BY users.id ASC LIMIT 1  [["name", 'mike']]

Solution 3 - Ruby on-Rails

There is a huge difference in performance, and .present? can be up to 10x slower then .exists? depending on the relation you are checking.

This article benchmarks .present? vs .any? vs .exists? and explains why they go from slower to faster, in this order.

In a nutshell, .present? (900ms in the example) will load all records returned, .any? (100ms in the example) will use a SQLCount to see if it's > 0 and .exists? (1ms in the example) is the smart kid that uses SQL LIMIT 1 to just check if there's at least one record, without loading them all neither counting them all.

Solution 4 - Ruby on-Rails

SELECT COUNT(*) would scan the records to get a count.

SELECT 1 would stop after the first match, so their exec time would be very different.

Solution 5 - Ruby on-Rails

The SQL generated by the two are also different.

present?:

Thing.where(name: "Bob").present?
# => SELECT COUNT(*) FROM things WHERE things.name = "Bob";

exists?:

Thing.exists?(name: "Bob")
# => SELECT 1 AS one from things WHERE name ="Bob" limit 1;

They both seem to run the same speed, but may vary given your situation.

Solution 6 - Ruby on-Rails

You can avoid database query by using present?:

all_endorsements_11 = ArtworkEndorsement.where(user_id: 11)
ArtworkEndorsement Load (0.3ms)  SELECT "artwork_endorsements".* FROM "artwork_endorsements" WHERE "artwork_endorsements"."user_id" = $1  [["user_id", 11]]
all_endorsements_11.present?
=> true 
all_endorsements_11.exists?
ArtworkEndorsement Exists (0.4ms)  SELECT  1 AS one FROM "artwork_endorsements" WHERE "artwork_endorsements"."user_id" = $1 LIMIT 1  [["user_id", 11]]
=> true 

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionperseveranceView Question on Stackoverflow
Solution 1 - Ruby on-RailspjeView Answer on Stackoverflow
Solution 2 - Ruby on-RailsavitalView Answer on Stackoverflow
Solution 3 - Ruby on-Railssandre89View Answer on Stackoverflow
Solution 4 - Ruby on-RailsburaksayView Answer on Stackoverflow
Solution 5 - Ruby on-Railsbigtex777View Answer on Stackoverflow
Solution 6 - Ruby on-RailstkhuynhView Answer on Stackoverflow