我想确保我在正确的场合使用它们,并想知道任何微妙之处。它们的功能似乎相同,即检查是否已定义对象字段,当我通过控制台使用它们时,当我进行谷歌搜索时,在线信息并不多。谢谢!
6 回答
澄清一下:“纯”红宝石既不是present?
也不exists?
是——它们都来自 Rails-land。
当下?
present?
是 ActiveSupport 的扩展Object
。它通常用作测试对象的一般“虚假性”。从文档中:
一个对象是
present
如果它不是blank?
。一个对象是blank
、false
空的还是空白字符串。
因此,例如:
[ "", " ", false, nil, [], {} ].any?(&:present?)
# => false
存在吗?
exists?
来自 ActiveResource。从其文档中:
断言资源的存在,如果找到资源则返回 true。
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?
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']]
性能存在巨大差异,根据您正在检查的关系,.present?
可能会慢 10 倍。.exists?
本文.present?
对vs .any?
vs进行了基准测试,.exists?
并解释了为什么它们按此顺序从慢到快。
简而言之,.present?
(示例中为 900ms)将加载所有返回的记录,.any?
(示例中为 100ms)将使用 SQLCount 来查看它是否 > 0 并且.exists?
(示例中为 1ms)是使用 SQL LIMIT 1 的聪明孩子检查是否至少有一条记录,而不是全部加载,也不计算全部。
SELECT COUNT(*)
将扫描记录以获取计数。
SELECT 1
将在第一场比赛后停止,因此他们的执行时间会非常不同。
两者生成的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;
它们的运行速度似乎相同,但根据您的情况可能会有所不同。
您可以使用以下方法避免数据库查询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