Проверка Rails, если запись существует в базе данных
Каков наиболее эффективный способ проверки, будет ли база данных возвращать запись перед ее обработкой. Пример: Truck.where("id = ?", id).select('truck_no').first.truck_no
Это может или не может вернуть грузовик, если грузовик существует. Что является наиболее эффективным способом для меня обеспечить, чтобы страница не сбой при обработке этого запроса. Как бы я справился с этим как в представлении, так и в контроллере, если можно сказать, что я использовал цикл, чтобы пройти через каждый грузовик и распечатать его номер.
Если запись не существует, я хотел бы иметь возможность распечатывать сообщение, а не указывать, что никаких записей не найдено.
Ответы
Ответ 1
Если вы хотите проверить на наличие объекта, почему бы не использовать существует?
if Truck.exists?(10)
# your truck exists in the database
else
# the truck doesn't exist
end
exists?
Преимущество метода заключается в том, что он не выбирает запись из базы данных (то есть быстрее, чем выбор записи). Запрос выглядит так:
SELECT 1 FROM trucks where trucks.id = 10
Вы можете найти больше примеров в документации по Rails для #exists? ,
Ответ 2
Вот как вы можете это проверить.
if Trucks.where(:id => current_truck.id).blank?
# no truck record for this id
else
# at least 1 record for this truck
end
, где возвращает объект ActiveRecord:: Relation (действует как массив, содержащий результаты, где), он может быть пустым, но никогда не быть nil.
Ответ 3
Реализация фактического варианта использования OP
Самое простое решение - объединить проверку и извлечение данных из БД в 1 БД, вместо того, чтобы иметь отдельные вызовы БД. Ваш примерный код близок и передает ваше намерение, но он немного не соответствует вашему фактическому синтаксису.
Если вы просто делаете Truck.where("id = ?", id).select('truck_no').first.truck_no
, и эта запись НЕ существует, она вызывает ошибку nil
при вызове truck_no
, потому что first
может извлечь запись nil
, если не найдено ни одного, соответствующего вашим критериям.
Это потому, что ваш запрос вернет массив объектов, соответствующих вашим критериям, тогда вы сделаете first
в этом массиве, который (если не найдены совпадающие записи) nil
.
Довольно чистое решение:
# Note: using Rails 4 / Ruby 2 syntax
first_truck = Truck.select(:truck_no).find_by(id) # => <Truck id: nil, truck_no: "123"> OR nil if no record matches criteria
if first_truck
truck_number = first_truck.truck_no
# do some processing...
else
# record does not exist with that criteria
end
Я рекомендую использовать чистый синтаксис, который сам "комментирует", чтобы другие точно знали, что вы пытаетесь сделать.
Если вы действительно хотите пройти лишнюю милю, вы можете добавить метод к вашему классу Truck
, который сделает это за вас и передает ваше намерение:
# truck.rb model
class Truck < ActiveRecord::Base
def self.truck_number_if_exists(record_id)
record = Truck.select(:truck_no).find_by(record_id)
if record
record.truck_no
else
nil # explicit nil so other developers know exactly what going on
end
end
end
Тогда вы бы назвали его так:
if truck_number = Truck.truck_number_if_exists(id)
# do processing because record exists and you have the value
else
# no matching criteria
end
Метод ActiveRecord.find_by
будет извлекать первую запись, соответствующую вашим критериям, или возвращает nil
, если запись не найдена с этими критериями. Заметим, что порядок методов find_by
и where
важен; вы должны вызвать select
в модели Truck
. Это происходит потому, что когда вы вызываете метод where
, вы фактически возвращаете объект ActiveRelation
, который не является тем, что вы ищете здесь.
См. API ActiveRecord для метода find_by
Общие решения, использующие 'exists?' Метод
Как уже упоминалось ранее, метод exists?
разработан специально для проверки наличия чего-то. Он не возвращает значение, просто подтверждает, что у БД есть запись, соответствующая некоторым критериям.
Полезно, если вам нужно проверить уникальность или точность некоторой части данных. Приятная часть состоит в том, что он позволяет использовать критерии ActiveRelation(Record?) where(...)
.
Например, если у вас есть модель User
с атрибутом email
, и вам нужно проверить, существует ли электронная почта в дБ:
User.exists?(email: "[email protected]")
Преимущество использования exists?
заключается в том, что запуск SQL-запроса
SELECT 1 AS one FROM "users" WHERE "users"."email" = '[email protected]' LIMIT 1
который более эффективен, чем фактическое возвращение данных.
Если вам нужно фактически получить данные из БД, это не метод для использования. Тем не менее, он отлично подходит для простой проверки, и синтаксис очень ясен, поэтому другие разработчики точно знают, что вы делаете. Использование соответствующего синтаксиса имеет решающее значение для проектов с несколькими разработчиками. Напишите чистый код и пусть сам код "комментирует".
Ответ 4
Вы можете просто сделать:
@truck_no = Truck.where("id = ?", id).pluck(:truck_no).first
Это вернет nil
, если запись не будет найдена, или truck_no
только в первой записи.
Тогда, на ваш взгляд, вы можете просто сделать что-то вроде:
<%= @truck_no || "There are no truck numbers" %>
Если вы хотите получить и отобразить несколько результатов, то в вашем контроллере:
@truck_nos = Truck.where("id = ?", id).pluck(:truck_no)
и на ваш взгляд:
<% truck_nos.each do |truck_no| %>
<%= truck_no %>
<% end %>
<%= "No truck numbers to iterate" if truck_nos.blank? %>
Ответ 5
Если вы просто хотите проверить, существует ли запись или нет. Пойдите с @cristian ответом то есть
Truck.exists?(truck_id) # returns true or false
Но если грузовик выходит, то вы хотите получить доступ к этому грузовику, тогда вам придется снова найти грузовик, что приведет к двум запросам к базе данных. Если это так, перейдите с
@trcuk = Truck.find_by(id: truck_id) #returns nil or truck
@truck.nil? #returns true if no truck is db
@truck.present? #returns true if no truck is db
Ответ 6
Rails имеет метод persisted?
для использования, как вы хотите