Sprawdź, czy istnieje rekord z kontrolera w Railsach

91

W mojej aplikacji Użytkownik może założyć Firmę. Kiedy wyzwalają indexakcję w moim BusinessesControllerChcę sprawdzić, czy Firma jest związana z current_user.id:

  • Jeśli tak: wyświetl firmę.
  • Jeśli nie: przekieruj do newakcji.

Próbowałem tego użyć:

if Business.where(:user_id => current_user.id) == nil
  # no business found
end

Ale zawsze zwraca prawdę, nawet jeśli firma nie istnieje ...

Jak mogę sprawdzić, czy rekord istnieje w mojej bazie danych?

MrYoshiji
źródło
1
Użycie wherezwróci pustą tablicę, jeśli nie ma żadnych rekordów. I []nie równa sięnil
mind.blank
A co z tylko unless Business.find_by_user_id(current_user.id)?
Hengjie
możliwy duplikat Sprawdzania, czy ActiveRecord find zwraca wynik
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Odpowiedzi:

231

Dlaczego twój kod nie działa?

Że wheremetoda zwraca ActiveRecord :: Relacja obiektu (działa jak tablica, która zawiera wyniki Spośród where), to może być pusty, ale to nigdy nie będzienil .

Business.where(id: -1) 
 #=> returns an empty ActiveRecord::Relation ( similar to an array )
Business.where(id: -1).nil? # ( similar to == nil? )
 #=> returns false
Business.where(id: -1).empty? # test if the array is empty ( similar to .blank? )
 #=> returns true

Jak sprawdzić, czy istnieje co najmniej jeden rekord?

Opcja 1: używanie.exists?

if Business.exists?(user_id: current_user.id)
  # same as Business.where(user_id: current_user.id).exists?
  # ...
else
  # ...
end

Opcja 2: używanie .present?(lub .blank?przeciwieństwo .present?)

if Business.where(:user_id => current_user.id).present?
  # less efficiant than using .exists? (see generated SQL for .exists? vs .present?)
else
  # ...
end

Opcja 3: przypisanie zmiennej w instrukcji if

if business = Business.where(:user_id => current_user.id).first
  business.do_some_stuff
else
  # do something else
end

Tę opcję można uznać za zapach kodu przez niektóre lintery (na przykład Rubocop).

Opcja 3b: przypisanie zmiennych

business = Business.where(user_id: current_user.id).first
if business
  # ...
else
  # ...
end

Możesz także użyć .find_by_user_id(current_user.id)zamiast.where(...).first


Najlepsza opcja:

  • Jeśli nie korzystasz z Businessobiektów: opcja 1
  • Jeśli potrzebujesz skorzystać z Businessobiektów: opcja 3
MrYoshiji
źródło
To nie wydawało się działać. Wciąż przechodzi ten test i ładuje indeks html, tak jak w przypadku testu == nil (więc pojawia się błąd: undefined method `name 'for nil: NilClass).
Wypróbuj jako pierwszy przed wywołaniem prezentu
MrYoshiji
Mam ten sam problem
Och, to moja wina, byłem zdezorientowany, musisz przetestowaćblank?
MrYoshiji
Dzięki, że zadziałało! Nie powinienem był zauważyć tego błędu. Czy możesz mi powiedzieć, dlaczego sprawdzenie == nil nie zadziałało?
29

W tym przypadku lubię skorzystać z exists?metody udostępnionej przez ActiveRecord:

Business.exists? user_id: current_user.id
Hamed
źródło
Istnieje? z lub możliwe?
Imran Ahmad
5

z „istnieje?”:

Business.exists? user_id: current_user.id #=> 1 or nil

z jakimkolwiek?':

Business.where(:user_id => current_user.id).any? #=> true or false

Jeśli używasz czegoś z .where, unikaj problemów z celownikami i lepiej używaj .unscoped

Business.unscoped.where(:user_id => current_user.id).any?
user2427993
źródło
Lepiej użyj Business.unscoped.where (: user_id => current_user.id) .pluck (: id) .any? aby uniknąć niepotrzebnego obciążenia relacji dla sprawdzanego obiektu.
Juanin
1

ActiveRecord # gdzie zwróci obiekt ActiveRecord :: Relation (który nigdy nie będzie zerowy). Spróbuj użyć .empty? w związku z testem, czy zwróci jakiekolwiek rekordy.

Puhlze
źródło
1

Kiedy zadzwonisz Business.where(:user_id => current_user.id), otrzymasz tablicę. Ta tablica może nie zawierać żadnych obiektów lub jednego lub wielu obiektów, ale nie będzie miała wartości NULL. Tak więc check == nil nigdy nie będzie prawdziwe.

Możesz spróbować następujących rzeczy:

if Business.where(:user_id => current_user.id).count == 0

Więc sprawdzasz liczbę elementów w tablicy i porównujesz je do zera.

lub możesz spróbować:

if Business.find_by_user_id(current_user.id).nil?

to zwróci jeden lub zero.

marimaf
źródło
1
business = Business.where(:user_id => current_user.id).first
if business.nil?
# no business found
else
# business.ceo = "me"
end
Nino van Hooff
źródło
0

Zrobiłbym to w ten sposób, gdybyś potrzebował zmiennej instancji obiektu do pracy:

if @business = Business.where(:user_id => current_user.id).first
  #Do stuff
else
  #Do stuff
end
user3633260
źródło