find () com nil quando não houver registros


95

No meu programa Rails atual, quando uso algo como

 user = User.find(10)

Quando não houver nenhum usuário com ID = 10, terei exceção como:

ActiveRecord::RecordNotFound: Couldn't find User with ID=10

Posso obter nil em vez de gerar exceção, então quando faço algo como:

unless user = Challenge.find(10)
  puts "some error msg"         
end

Só quero obter nil quando não houver registros e não quiser usar begin / rescue

obrigado


Respostas:


170

Sim, basta fazer:

Challenge.find_by_id(10)

Para Rails 4 e 5:

Challenge.find_by(id: 10)

11
ímpar! Eu nunca teria imaginado que o .find_by_*retorno seria nulo e o .findnão retornaria .
ddavison

Isso mudou no rails 4, consulte esta resposta stackoverflow.com/a/26885027/1438478 para a nova maneira de localizar um item por um atributo específico.
Fralcon

Eu encontrei um problema estranho com o Rails 4.2 onde quando você passa um hash como 'x' para Something.find_by(id: x)ele criar uma instrução SQL com todos os pares atributo / valor do hash como parte da cláusula WHERE. Parece um bug do Rails para mim.
Tilo

Rails (3, 4 ou 5) gera localizadores dinâmicos find_by_...para cada atributo que um modelo inclui :id. Portanto, Challenge.find_by_id(10)deve funcionar independentemente da versão do Rails.
Arta

Conforme especificado por @MohamedIbrahim abaixo, você também pode fazer:Challenge.find(10) rescue nil
Hallgeir Wilhelmsen

31

No Rails 4, os localizadores dinâmicos - como os find_by_idusados ​​na resposta aceita - foram descontinuados.

Seguindo em frente, você deve usar a nova sintaxe:

Challenge.find_by id: 10

4
Caso alguém esteja confuso com isso como eu: Challenge.find_by(id: 10)é a outra maneira de escrever isso
Devin Howard

14

você pode fazer isso um pouco hackeado, basta usar a interface de consulta ActiveRecord.

isso retornará nulo, em vez de gerar uma exceção

  User.where(:id => 10).first

Uma razão para usar isso find_by_idé que ele é portátil do Rails 3 ao 4. No Rails 4, é find_by(:id => 10).
Gene

5

Por que você simplesmente não captura a exceção? Seu caso se parece exatamente com as exceções feitas para:

begin
  user = User.find(10)
rescue ActiveRecord::RecordNotFound
  puts "some error msg"
end

Se você quiser se recuperar do erro no bloco de resgate (por exemplo, definindo um usuário de espaço reservado (padrão nulo)), você pode continuar com seu código abaixo deste bloco. Caso contrário, você pode simplesmente colocar todo o seu código para o "caso feliz" no bloco entre "começar" e "resgatar".


Btw: você nem precisa do begin…endbloco, se você já tem um bloco, como um método de controlador. Nesse caso, a única linha extra de que você precisa é a rescuelinha. Muito mais elegante e fácil de manusear do que verificar nilcom uma ifdeclaração.
Morgler

4

Você pode tentar isso Challenge.exists?(10)


7
será uma solicitação extra de sql
fl00r

Mesmo assim eu acho que é melhor procurar testar
SomeSchmo

use-o se você não se importar com o valor retornado, mas apenas com a presença de um registro no DB
Filip Bartuzi

4

Para aqueles que lutam com mongóide , verifica-se que ambos findefind_by métodos exceções - não importa a versão do Rails!

Há uma opção (ou seja, raise_not_found_error ) que pode ser definida como falsa, mas quando falsey tornafind método, não levanta a exceção também.

Assim, a solução para usuários mongoid é o código nojento:

User.where(id: 'your_id').first # argghhh

O que você acha da solução de resgate nil de mohamed-ibrahim? Parece mais elegante do que .where(email: params[:email]).firstpara mim.
Wylliam Judd

1
Prefiro não usar essa rescuesintaxe, pois ela pode ocultar problemas como erros de digitação
Cristiano Mendonça

Acabei usando a solução de @morgler.
Wylliam Judd

2

tão simples quanto:

user = User.find(10) rescue nil

1
Eu preferiria ser mais específico sobre qual erro se espera que seja resgatado, ActiveRecord :: RecordNotFound neste caso. Conforme apontado nesta resposta por @morgler
luizrogeriocn

2
Pessoalmente, considero esta a melhor resposta. Já estou dizendo ao meu código o que fazer se o usuário não for encontrado emif user...else
Wylliam Judd

0

Você pode usar find_by com o atributo necessário (no seu caso, o id). Isso retornará nil ao invés de dar um erro se o id fornecido não for encontrado.

user = Challenge.find_by_id(id_value)

ou você pode usar o novo formato:

user = Challenge.find_by id: id_value

Você também pode usar where, mas você precisa saber que where retorna uma relação de registro ativo com zero ou mais registros que você precisa usar primeiro para retornar apenas um registro ou nil no caso de retorno de zero registros.

user = Challenge.where(id: id_value).first
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.