使用.exists?和.present有什么区别? 在Ruby?

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

我想确保我在正确的场合使用它们,并想知道任何细微之处。 它们似乎以相同的方式起作用,即检查是否已经定义了一个对象字段,当我通过控制台使用它们时,当我进行谷歌搜索时,并没有在线提供大量信息。 谢谢!


澄清一下:present?exists?都不是"纯粹"的红宝石 - 它们都来自Rails-land。

当下?

present?Object的ActiveSupport扩展。它通常用作对象的一般"虚假"的测试。从文档:

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

所以,例如:

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

存在?

exists?来自ActiveResource。从其文件:

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

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


两种方法之间的最大区别在于,当您调用present?时,它会为找到的每条记录(!)初始化ActiveRecord,而exists?则不会

为了表明这一点,我在User上添加了after_initialize。它打印出来:'你已经初始化了一个对象!'

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

1
2
3
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')

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


性能存在巨大差异,.present?可能比.exists?慢10倍,具体取决于您检查的关系。

本文基准.present? vs .any? vs .exists?,并按此顺序解释了为什么它们从慢到快。

简而言之,.present?(在示例中为900ms)将加载返回的所有记录,.any?(在示例中为100ms)将使用SQLCount来查看它是否> 0且.exists?(示例中为1ms)是聪明的孩子使用SQL LIMIT 1来检查是否至少有一条记录,而不加载它们都不计算所有记录。


SELECT COUNT(*)将扫描记录以获得计数。

SELECT 1会在第一场比赛后停止,因此他们的执行时间会有很大差异。


两者生成的SQL也不同。

present?

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

exists?

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

它们似乎都以相同的速度运行,但根据您的情况可能会有所不同。


您可以使用present?来避免数据库查询:

1
2
3
4
5
6
7
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