find vs find_by vs where


127

我是新手。我看到有很多找到记录的方法:

  1. find_by_<columnname>(<columnvalue>)
  2. find(:first, :conditions => { <columnname> => <columnvalue> }
  3. where(<columnname> => <columnvalue>).first

而且看起来它们所有人最终都生成完全相同的SQL。另外,我认为查找多个记录也是如此:

  1. find_all_by_<columnname>(<columnvalue>)
  2. find(:all, :conditions => { <columnname> => <columnvalue> }
  3. where(<columnname> => <columnvalue>)

是否有经验法则或推荐使用哪个准则?

Answers:


103

使用您认为最适合自己需求的任何一种。

find方法通常用于按ID检索行:

Model.find(1)

值得注意的是,find如果您提供的属性找不到项目,则将引发异常。使用where(如下所述,如果找不到该属性,它将返回一个空数组),以避免引发异常。

find通常将的其他用途替换为以下内容:

Model.all
Model.first

find_by当您在列中搜索信息时,它用作帮助程序,并且使用命名约定映射到此类信息。例如,如果name数据库中有一个命名列,则可以使用以下语法:

Model.find_by(name: "Bob")

.where 更重要的是,它使您可以在常规助手不使用时使用更复杂的逻辑,并且它返回与您的条件匹配的项目数组(否则返回空数组)。


62
find_by未弃用,但语法有所变化。从find_by_name("Bob")find_by(:name, "Bob")
Brian Morearty 2014年

61
@BrianMorearty我相信你的意思find_by(name: "Bob")
MCB

1
@BrianMorearty我找不到任何已find_by_...被弃用的证据,您有消息来源吗?这似乎find_byfind_by_...都仍然在Rails的支持4
丹尼斯

4
@Dennis,您是正确的,它没有被弃用,这就是我所说的。但是当我说“但语法有所变化”时,我可能会更加清楚。我的意思是,“但是现在也可以使用新的语法。” 有关新语法,请参见MCB的更正。
Brian Morearty 2014年

3
这是提到在轨4.0版本“的所有动态的方法除了find_by _...和find_by _...已过时!”的更多细节edgeguides.rubyonrails.org/...
穆克什·辛格Rathaur

131

其中,返回的ActiveRecord ::关系

现在看一下find_by实现:

def find_by
  where(*args).take
end

如您所见,find_bywhere相同但它仅返回一条记录。此方法应用于获取1条记录,而某些情况下应用于获取所有记录。


1
find_by返回一个对象,而其中返回一个集合。
Kick Buttowski

当查询值超出范围,find_by将拯救::RangeErrorwhere(*args) 和回报为零。
方兴

34

Model.find

1-参数:要查找的对象的ID。

2-如果找到:它返回对象(仅一个对象)。

3-如果未找到:引发ActiveRecord::RecordNotFound异常。

Model.find_by

1-参数:键/值

例:

User.find_by name: 'John', email: 'john@doe.com'

2-如果找到:返回对象。

3-如果找不到:返回nil

注意:如果您想增加ActiveRecord::RecordNotFound使用量find_by!

Model.where

1-参数:与 find_by

2-如果找到:返回ActiveRecord::Relation包含一个或多个与参数匹配的记录。

3-如果未找到:则返回Empty ActiveRecord::Relation


31

有之间的差异find,并find_byfind返回如果没有找到,而一个错误find_by将返回null。

有时,如果您有类似的方法find_by email: "haha"(而不是),则更容易阅读.where(email: some_params).first


17

从Rails 4开始,您可以执行以下操作:

User.find_by(name: 'Bob')

find_by_name在Rails 3中等效。

#where#find和时使用#find_by


2
阿吉斯,我同意你的看法,但我一直在寻找在互联网上,我们为什么要使用find_by而不是find_by_<column_name>。我需要它来回答某人。
KULKING 2014年

Agis,您是否有任何消息来源支持您关于不再使用find_by_nameRails 4的主张?据我所知,它并没有被弃用
丹尼斯

有一种简单的方法可以做到,但是说名称中包含通配符,例如find_by(name: "Rob*")
Batman

1
@Dennis可以同时使用它们,它们是有效的。我更喜欢新语法,因为API更直观,恕我直言。这就是我自己设计的方式:)
Agis

8

接受的答案通常涵盖了一切,但我想补充一点,只是柜面你打算工作,像更新的方式模型,您检索一条记录(其id不知道),然后find_by是的方式,因为它检索记录并且不将其放入数组中

irb(main):037:0> @kit = Kit.find_by(number: "3456")
  Kit Load (0.9ms)  SELECT "kits".* FROM "kits" WHERE "kits"."number" = 
 '3456' LIMIT 1
=> #<Kit id: 1, number: "3456", created_at: "2015-05-12 06:10:56",   
updated_at: "2015-05-12 06:10:56", job_id: nil>

irb(main):038:0> @kit.update(job_id: 2)
(0.2ms)  BEGIN Kit Exists (0.4ms)  SELECT 1 AS one FROM "kits" WHERE  
("kits"."number" = '3456' AND "kits"."id" != 1) LIMIT 1 SQL (0.5ms)   
UPDATE "kits" SET "job_id" = $1, "updated_at" = $2 WHERE  "kits"."id" = 
1  [["job_id", 2], ["updated_at", Tue, 12 May 2015 07:16:58 UTC +00:00]] 
(0.6ms)  COMMIT => true

但是如果使用,where则无法直接更新

irb(main):039:0> @kit = Kit.where(number: "3456")
Kit Load (1.2ms)  SELECT "kits".* FROM "kits" WHERE "kits"."number" =  
'3456' => #<ActiveRecord::Relation [#<Kit id: 1, number: "3456", 
created_at: "2015-05-12 06:10:56", updated_at: "2015-05-12 07:16:58", 
job_id: 2>]>

irb(main):040:0> @kit.update(job_id: 3)
ArgumentError: wrong number of arguments (1 for 2)

在这种情况下,您必须像这样指定它

irb(main):043:0> @kit[0].update(job_id: 3)
(0.2ms)  BEGIN Kit Exists (0.6ms)  SELECT 1 AS one FROM "kits" WHERE 
("kits"."number" = '3456' AND "kits"."id" != 1) LIMIT 1 SQL (0.6ms)   
UPDATE "kits" SET "job_id" = $1, "updated_at" = $2 WHERE "kits"."id" = 1  
[["job_id", 3], ["updated_at", Tue, 12 May 2015 07:28:04 UTC +00:00]]
(0.5ms)  COMMIT => true

正是我要找的东西
Paul Brunache

2
@kit = Kit.where(number:“ 3456”)。first-这使您可以直接对其进行更新,因为它在弃用后仍然可以保持更安全
Paul Brunache 2015年

6

除了可接受的答案,以下内容也有效

Model.find()可以接受ID数组,并将返回所有匹配的记录。 Model.find_by_id(123)也接受数组,但只会处理数组中存在的第一个id值

Model.find([1,2,3])
Model.find_by_id([1,2,3])


3

到目前为止给出的答案都还可以。

但是,一个有趣的区别是Model.find按ID进行搜索。如果找到,它将返回一个Model对象(仅一条记录),但抛出ActiveRecord::RecordNotFound否则。

Model.find_by与十分相似Model.find,可让您搜索数据库中的任何列或一组列,但是nil如果没有记录与搜索匹配,它将返回。

Model.where另一方面,返回一个Model::ActiveRecord_Relation对象,该对象就像一个数组,其中包含与搜索匹配的所有记录。如果未找到任何记录,它将返回一个空Model::ActiveRecord_Relation对象。

希望这些可以帮助您决定在任何时间使用哪个。


3

假设我有一个模型 User

  1. User.find(id)

返回其中主键= id的行。返回类型将是User对象。

  1. User.find_by(email:"abc@xyz.com")

在这种情况下,返回具有匹配属性或电子邮件的第一行。返回类型将User再次成为对象。

注意:- User.find_by(email: "abc@xyz.com")类似于User.find_by_email("abc@xyz.com")

  1. User.where(project_id:1)

返回用户表中属性匹配的所有用户。

这里的返回类型将是ActiveRecord::Relation对象。ActiveRecord::Relation类包含Ruby的Enumerable模块,因此您可以像数组一样使用它的对象并在其上遍历。


0

使用任何开源技术的最好的部分是您可以检查它的长度和宽度。 签出此链接

find_by〜>查找符合指定条件的第一条记录。没有隐含的订购,因此,如果订购很重要,则应自行指定。如果未找到任何记录,则返回nil。

find〜>查找符合指定条件的第一条记录,但是如果未找到任何记录,则将引发异常,但这是有意进行的。

请检查以上链接,其中包含以下两个功能的所有说明和用例。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.