PO rzeczywisty przypadek użycia roztworu
Najprostszym rozwiązaniem jest łączenie czek i odzyskiwanie danych DB w 1 Zapytanie DB zamiast oddzielnych wywołań DB. Twój przykładowy kod jest bliski i przekazuje twoje intencje, ale jest trochę poza rzeczywistą składnią.
Jeśli proste zrobić Truck.where("id = ?", id).select('truck_no').first.truck_no
i ten rekord nie istnieje, będzie rzucać się błąd nil
kiedy zadzwonić truck_no
ponieważ first
może pobrać nil
rekord, jeśli nie odnajdzie pasujących do Twoich kryteriów.
Dzieje się tak, ponieważ zapytanie zwróci tablicę obiektów spełniających kryteria, a następnie wykona się first
w tej tablicy, która (jeśli nie znaleziono pasujących rekordów) to nil
.
Dość czyste rozwiązanie:
# 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
polecam czystą składnię, że „komentarze” tak samo inni wiedzą dokładnie, co chcesz robić.
Jeśli naprawdę chcesz, aby przejść dodatkowe mile, można dodać metodę do klasy Truck
że robi to dla ciebie i przekazuje swój zamiar:
# 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's going on
end
end
end
Wtedy to nazwać tak:
if truck_number = Truck.truck_number_if_exists(id)
# do processing because record exists and you have the value
else
# no matching criteria
end
Metoda ActiveRecord.find_by
pobierze pierwszy rekord, który odpowiada Twoim kryteriom lub zwróci nil
, jeśli nie zostanie znaleziony żaden rekord z tymi kryteriami. Zauważ, że kolejność metod find_by
i where
jest ważna; musisz zadzwonić pod numer select
w modelu Truck
. Dzieje się tak, ponieważ po wywołaniu metody where
faktycznie zwracasz obiekt ActiveRelation
, który nie jest tym, czego szukasz.
See ActiveRecord API for 'find_by' method
rozwiązania ogólne używając 'istnieje? metoda
Jak już wspomnieli niektórzy z innych autorów, metoda exists?
została zaprojektowana specjalnie w celu sprawdzenia, czy coś istnieje. Nie zwraca wartości, tylko potwierdza, że DB ma rekord, który pasuje do niektórych kryteriów.
Jest to przydatne, jeśli trzeba zweryfikować unikalność lub dokładność niektórych danych. Dobrą rzeczą jest to, że pozwala ci użyć kryteriów ActiveRelation(Record?) where(...)
.
Na przykład, jeśli masz User
model z atrybutem email
i trzeba sprawdzić, czy e-mail już istnieje w dB:
User.exists?(email: "[email protected]")
Zaletą korzystania exists?
to, że zapytanie SQL prowadzony jest
SELECT 1 AS one FROM "users" WHERE "users"."email" = '[email protected]' LIMIT 1
który jest bardziej wydajny niż faktycznie przekazujących dane.
Jeśli potrzebujesz rzeczywiście warunkowo pobrać dane z DB, nie jest to metoda użycia. Jednak sprawdza się doskonale przy prostym sprawdzaniu, a składnia jest bardzo jasna, więc inni deweloperzy dokładnie wiedzą, co robisz. Używanie odpowiedniej składni ma kluczowe znaczenie w projektach z wieloma programistami. Napisz czysty kod i pozwól, aby kod sam się "skomentował".
która wersja szynach jesteś stronie? – Shaunak
Czy istnieje przegląd?metoda http://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-exists-3F – cristian