Подтвердить что ты не робот

Проверка Rails, если запись существует в базе данных

Каков наиболее эффективный способ проверки, будет ли база данных возвращать запись перед ее обработкой. Пример: Truck.where("id = ?", id).select('truck_no').first.truck_no

Это может или не может вернуть грузовик, если грузовик существует. Что является наиболее эффективным способом для меня обеспечить, чтобы страница не сбой при обработке этого запроса. Как бы я справился с этим как в представлении, так и в контроллере, если можно сказать, что я использовал цикл, чтобы пройти через каждый грузовик и распечатать его номер.

Если запись не существует, я хотел бы иметь возможность распечатывать сообщение, а не указывать, что никаких записей не найдено.

4b9b3361

Ответ 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?  для использования, как вы хотите