Dla każdego elementu tablicy wywołuję w pętli DoSomothing.new(id)
Jeśli nie ma klienta o konkretnym id rzucany jest wyjątek i aplikacja się zatrzymuje.
Jak pomimo wyjątku przejść do przetwarzania następnego klienta?
Jeśli nie ma klienta o id 3, przechodzi do id 5.
Wiem, że można zrobić odwrotnie. Najpierw sprawdzać czy dany klient istnieje a potem jeśli istnieje coś z nim zrobić.
Ale chodzi mi konkretnie o eleganckie obsłużenie błędu.
Przegląda doc na temat exception, rescue itp ale nie bardzo nadal wiem jak to zrobić.
array.each do |id|
begin
DoSth.new(id)
rescue ActiveRecord::RecordNotFound
#record not found - doing nothing:P
end
end
W ten sposób obsłużysz tylko ten wyjątek, o który Ci chodzi - czyli brak id w bazie.
Generalnie nie zaleca się używania wyjątków do kontroli przepływu programu. Wyjątki powinny być czymś nieoczekiwanym. Jeżeli oczekujesz sytuacji w której klienci nie istnieją należy użyć alternatywnych metod, typu przedstawionych przez slawosza.
Jeżeli nie interesują cię brakujace idki możesz zrobić po prostu Client.all(:conditions => {:id => array})
Ja stosujuję >generalnie< jedynie żeby złagodzić przekaz. Mogę oczywiście inaczej. np.
Osoby stosujące Wyjątki do kontroli przepływu w językach wysokiego poziomu(za wyjątkiem pythona) powinny być siłowo reedukowane tak by ujrzały światło.
Lepiej? (dla niekumatych oczywiście żartuję)
A na serio powodów jest kilka:
try/catch jest 10 razy wolniejsze od if-a
try/catch przewija stos i zmienia zakres - w efekcie im większy program tym więcej pamięci try/catch zajmuje szczególnie w ciasnych pętlach.
wyjątki są nazwane tak z konkretnych powodów - powinny być uzywane jedynie do obsługi sytuacji wyjątkowych.
If/else jest o wiele spójniejsze w małych blokach kodu, a przy większych obsługa wyjątku jest zwykle z dala od kodu rzucającego wyjatek, dosyć konkretnie wytrącając z rytmu przy czytaniu kodu.
Walidacje z tego co pamiętam robi się na zasadzie errors.add i większość źródeł w tym domyślny railsyw scaffold używają wzorca:
if record.valid? then ble ble else bla bla
więc bez wyjątków.
PS. Benchmark if vs. exceptions ładnie pokazuje różnicę 10x.
irb(main):010:0> a, b = 0, 0; c, d = 0, 0; Benchmark.bm{|r| r.report("if"){ 100000.times{ rand() < 0.5 ? b+=1 : a+=1 }}; r.report("rescue"){ 100000.times{ (raise(RuntimeError, "Zly los") if rand() >= 0.5; c+=1) rescue d+=1 } } }; p [a,b,c,d]
user system total real
if 0.220000 0.000000 0.220000 ( 0.273861)
rescue 2.130000 0.040000 2.170000 ( 2.365966)
[49990, 50010, 49998, 50002]
=> nil