Найти 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
User.find(id)
Возвращает строку, где первичный ключ = id. Тип возвращаемого значения - объект User
.
User.find_by(email:"[email protected]")
В этом случае возвращает первую строку с соответствующим атрибутом или адресом электронной почты. Тип возвращаемого значения снова будет объектом User
.
Примечание: - User.find_by(email: "[email protected]")
похож на User.find_by_email("[email protected]")
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>)