Найти vs find_by vs где

Я новичок в рельсах. Я вижу, что есть много способов найти запись:

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

И похоже, что все они в конечном итоге генерируют точно такой же SQL. Кроме того, я считаю, что то же самое верно для поиска нескольких записей:

  • find_all_by_<columnname>(<columnvalue>)
  • find(:all, :conditions => { <columnname> => <columnvalue> }
  • where(<columnname> => <columnvalue>)

Есть ли эмпирическое правило или рекомендации по использованию?

Ответ 1

Используйте тот, который вам больше подходит.

Метод find обычно используется для извлечения строки по ID:

Model.find(1)

Стоит отметить, что find выдаст исключение, если элемент не найден по указанному вами атрибуту. Используйте where (как описано ниже, которое будет возвращать пустой массив, если атрибут не найден), чтобы избежать возникновения исключения.

Другие варианты использования find обычно заменяются такими вещами:

Model.all
Model.first

find_by используется в качестве помощника при поиске информации в столбце и сопоставляется с такими соглашениями об именах. Например, если в вашей базе данных есть столбец с именем name, вы должны использовать следующий синтаксис:

Model.find_by(name: "Bob")

.where - это еще одна .where которая позволяет вам использовать немного более сложную логику, когда обычные помощники этого не делают, и возвращает массив элементов, соответствующих вашим условиям (или пустой массив в противном случае).

Ответ 2

, где возвращает ActiveRecord:: Relation

Теперь взгляните на реализацию find_by:

def find_by
  where(*args).take
end

Как вы видите, find_by совпадает с , где, но возвращает только одну запись. Этот метод следует использовать для получения 1 записи и , где следует использовать для получения всех записей с некоторыми условиями.

Ответ 3

Существует разница между find и find_by тем, что find вернет ошибку, если не найдена, тогда как find_by вернет значение null.

Иногда это легче читать, если у вас есть метод типа find_by email: "haha", а не .where(email: some_params).first.

Ответ 4

Model.find

1- Параметр: идентификатор найденного объекта.

2- Если найдено: Он возвращает объект (только один объект).

3- Если не найден: возникает исключение ActiveRecord::RecordNotFound.

Model.find_by

1- Параметр: ключ/значение

Пример:

User.find_by name: 'John', email: '[email protected]'

2- Если найдено: Он возвращает объект.

3- Если не найден: возвращает nil.

Примечание: Если вы хотите поднять ActiveRecord::RecordNotFound, используйте find_by!

Model.where

1- Параметр: тот же, что и find_by

2- Если найдено: Он возвращает ActiveRecord::Relation, содержащий одну или несколько записей, соответствующих параметрам.

3- Если не найден: он возвращает Empty ActiveRecord::Relation.

Ответ 5

С Rails 4 вы можете сделать:

User.find_by(name: 'Bob')

что эквивалентно find_by_name в Rails 3.

Используйте #where, когда #find и #find_by недостаточно.

Ответ 6

Принятый ответ обычно охватывает все это, но я хотел бы добавить что-то, просто вы можете планировать работать с моделью таким образом, как обновление, и вы извлекаете одну запись (чей 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

Ответ 7

Оба # 2 в ваших списках устарели. Вы все равно можете использовать find(params[:id]).

Как правило, where() работает в большинстве ситуаций.

Вот отличный пост: http://m.onkey.org/active-record-query-interface

Ответ 8

Помимо принятого ответа, верно и следующее

Model.find() может принимать массив идентификаторов и возвращать все записи, которые соответствуют. Model.find_by_id(123) также принимает массив, но обрабатывает только первое значение id, присутствующее в массиве

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

Ответ 9

Предположим, у меня есть модель User

  1. User.find(id)

Возвращает строку, где первичный ключ = id. Тип возвращаемого значения - объект User.

  1. User.find_by(email:"[email protected]")

В этом случае возвращает первую строку с соответствующим атрибутом или адресом электронной почты. Тип возвращаемого значения снова будет объектом User.

Примечание: - User.find_by(email: "[email protected]") похож на User.find_by_email("[email protected]")

  1. User.where(project_id:1)

Возвращает всех пользователей в таблице пользователей, где атрибут соответствует.

Здесь возвращаемым типом будет объект ActiveRecord::Relation. Класс ActiveRecord::Relation включает в себя модуль Ruby Enumerable, поэтому вы можете использовать его как массив и перемещаться по нему.

Ответ 10

Ответы, данные до сих пор, все в порядке.

Однако одно интересное отличие состоит в том, что Model.find выполняет поиск по id; если найдено, он возвращает объект Model (только одну запись), но в ActiveRecord::RecordNotFound случае выдает ActiveRecord::RecordNotFound.

Model.find_by очень похож на Model.find и позволяет вам искать любой столбец или группу столбцов в вашей базе данных, но возвращает nil если ни одна запись не соответствует поиску.

Model.where другой стороны, Model.where возвращает объект Model::ActiveRecord_Relation который похож на массив, содержащий все записи, соответствующие запросу. Если запись не найдена, возвращается пустой объект Model::ActiveRecord_Relation.

Я надеюсь, что это поможет вам решить, какой из них использовать в любой момент времени.

Ответ 11

Я лично рекомендую использовать

where(< columnname> => < columnvalue>)