61

我想确保我在正确的场合使用它们,并想知道任何微妙之处。它们的功能似乎相同,即检查是否已定义对象字段,当我通过控制台使用它们时,当我进行谷歌搜索时,在线信息并不多。谢谢!

4

6 回答 6

88

澄清一下:“纯”红宝石既不是present?也不exists?是——它们都来自 Rails-land。

当下?

present?是 ActiveSupport 的扩展Object。它通常用作测试对象的一般“虚假性”。从文档中

一个对象是present如果它不是blank?。一个对象是blankfalse空的还是空白字符串。

因此,例如:

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

存在吗?

exists?来自 ActiveResource。从其文档中

断言资源的存在,如果找到资源则返回 true。

Note.create(:title => 'Hello, world.', :body => 'Nothing more for now...')
Note.exists?(1) # => true
于 2012-11-01T22:58:08.057 回答
27

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

为了显示这一点,我在 User 上添加了 after_initialize。它打印:“你已经初始化了一个对象!”

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?(名称:'mike')

User Exists (2.4ms)  SELECT 1 AS one FROM "users" WHERE "users"."name" = $1 ORDER BY users.id ASC LIMIT 1  [["name", 'mike']]
于 2015-05-12T13:53:01.787 回答
20

性能存在巨大差异,根据您正在检查的关系,.present?可能会慢 10 倍。.exists?

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

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

于 2017-05-04T05:20:55.253 回答
9

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

SELECT 1将在第一场比赛后停止,因此他们的执行时间会非常不同。

于 2016-09-29T15:50:39.240 回答
2

两者生成的SQL也不同。

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;

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

于 2014-10-24T04:30:46.283 回答
-3

您可以使用以下方法避免数据库查询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 
于 2017-02-15T19:49:42.293 回答