154

我是新来的轨道。我看到有很多方法可以找到记录:

  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>)

是否有关于使用哪一个的经验法则或建议?

4

12 回答 12

143

其中返回 ActiveRecord::Relation

现在看一下 find_by 的实现:

def find_by
  where(*args).take
end

如您所见, find_by与where相同,但它只返回一条记录。此方法应用于获取 1 条记录,以及应使用where获取具有某些条件的所有记录。

于 2014-04-03T09:49:47.277 回答
124

编辑: 这个答案已经很老了,自从发表这篇文章以来,已经出现了其他更好的答案。我建议查看@Hossam Khamis 在下面发布的更多详细信息。

使用您认为最适合您需要的任何一种。

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

Model.find(1)

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

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

Model.all
Model.first

find_by当您在列中搜索信息时,它被用作帮助器,它通过命名约定映射到此类。例如,如果您name的数据库中有一个名为的列,您将使用以下语法:

Model.find_by(name: "Bob")

.where更多的是让您在常规助手无法使用的情况下使用更复杂的逻辑,并且它返回一个与您的条件匹配的项目数组(否则返回一个空数组)。

于 2012-06-22T18:17:32.763 回答
51

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

于 2016-12-27T00:32:15.430 回答
34

find和之间有区别,find_by如果find未找到将返回错误,而find_by将返回 null。

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

于 2012-06-22T18:20:56.463 回答
18

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

User.find_by(name: 'Bob')

find_by_name这在 Rails 3中是等价的。

使用#where#find#find_by不够。

于 2014-06-22T13:51:09.887 回答
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
于 2015-05-12T07:36:45.943 回答
7

除了接受的答案外,以下也是有效的

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

Model.find([1,2,3])
Model.find_by_id([1,2,3])
于 2015-08-06T10:46:10.937 回答
7

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

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

Model.find_by非常类似于Model.find并且允许您搜索数据库中的任何列或列组,但nil如果没有记录与搜索匹配,它会返回。

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

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

于 2019-07-12T16:23:43.003 回答
6

假设我有一个模型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模块,因此您可以像数组一样使用它的对象并在其上遍历。

于 2016-10-14T09:07:18.377 回答
5

您列表中的两个 #2 都已被弃用。你仍然可以使用find(params[:id])

通常,where()在大多数情况下都有效。

这是一个很棒的帖子:https ://web.archive.org/web/20150206131559/http://m.onkey.org/active-record-query-interface

于 2012-06-22T18:15:21.440 回答
0

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

find_by ~> 查找符合指定条件的第一条记录。没有隐含的顺序,所以如果顺序很重要,您应该自己指定。如果没有找到记录,则返回 nil。

find ~> 查找符合指定条件的第一条记录,但如果没有找到记录,则会引发异常,但这是故意的。

请查看上面的链接,它包含以下两个功能的所有说明和用例。

于 2020-03-06T04:21:24.857 回答
-5

我个人会推荐使用

where(< columnname> => < columnvalue>)
于 2017-05-03T11:41:16.873 回答