Verifique se existe registro do controlador no Rails

90

No meu aplicativo, um usuário pode criar um negócio. Quando eles acionam a indexação no meu BusinessesController, quero verificar se um negócio está relacionado a current_user.id:

  • Se sim: mostre o negócio.
  • Se não: redirecione para a newação.

Eu estava tentando usar isto:

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

Mas sempre retorna verdadeiro mesmo quando o negócio não existe ...

Como posso testar se existe um registro em meu banco de dados?

MrYoshiji
fonte
1
O uso de whereretornará um array vazio se não houver registros. E []não é igualnil
mind.blank
Que tal apenas um unless Business.find_by_user_id(current_user.id)?
Hengjie
possível duplicata de Checking if ActiveRecord find retorna um resultado
Ciro Santilli 郝海东 冠状 病 六四 事件 事件 法轮功

Respostas:

228

Por que seu código não funciona?

O wheremétodo retorna um objeto ActiveRecord :: Relation (age como um array que contém os resultados de where), pode estar vazio, mas nunca estaránil .

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

Como testar se existe pelo menos um registro?

Opção 1: usando.exists?

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

Opção 2: usando .present?(ou .blank?o oposto de .present?)

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

Opção 3: atribuição de variável na instrução if

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

Esta opção pode ser considerada um cheiro de código por alguns linters (Rubocop por exemplo).

Opção 3b: Atribuição de variável

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

Você também pode usar em .find_by_user_id(current_user.id)vez de.where(...).first


Melhor opção:

  • Se você não usar o Business(s) objeto (s): Opção 1
  • Se você precisar usar o Business(s) objeto (s): Opção 3
MrYoshiji
fonte
Isso não pareceu funcionar. Ele continua passando nesse teste e carregando o html de índice como com o teste == nil (então estou recebendo um erro: método indefinido `nome 'para nil: NilClass).
Experimente primeiro antes de ligar para o presente
MrYoshiji
Tenho o mesmo problema
Oh, isso é minha culpa, eu estava confuso, você precisa testar comblank?
MrYoshiji
Obrigado que funcionou! Eu não deveria ter percebido esse erro. Você poderia me dizer por que a verificação == nil não funcionou?
28

Neste caso, gosto de usar o exists?método fornecido pelo ActiveRecord:

Business.exists? user_id: current_user.id
Hamed
fonte
Existe? com OR possível?
Imran Ahmad
5

com 'existe?':

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

com qualquer?':

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

Se você usar algo com .where, certifique-se de evitar problemas com escopos e usar melhor .unscoped

Business.unscoped.where(:user_id => current_user.id).any?
user2427993
fonte
Melhor usar Business.unscoped.where (: user_id => current_user.id) .pluck (: id) .any? para evitar carga desnecessária de relações para o objeto que você está verificando.
Juanin
1

ActiveRecord # onde retornará um objeto ActiveRecord :: Relation (que nunca será nulo). Tente usar .empty? na relação para testar se ele retornará algum registro.

Puhlze
fonte
1

Quando você ligar, Business.where(:user_id => current_user.id)você obterá um array. Este Array pode não ter objetos ou um ou mais objetos, mas não será nulo. Portanto, a verificação == nil nunca será verdadeira.

Você pode tentar o seguinte:

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

Portanto, você verifica o número de elementos na matriz e os compara a zero.

ou você pode tentar:

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

isso retornará um ou nulo.

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

Eu faria isso dessa forma se você precisasse de uma variável de instância do objeto para trabalhar:

if @business = Business.where(:user_id => current_user.id).first
  #Do stuff
else
  #Do stuff
end
usuário 3633260
fonte