Jeśli łańcuch jest pusty, zwraca pewną wartość domyślną

94

Często muszę sprawdzić, czy jakaś wartość jest pusta i napisać „Brak danych” w ten sposób:

@user.address.blank? ? "We don't know user's address" : @user.address

A kiedy mamy około 20-30 pól, które musimy przetworzyć w ten sposób, robi się brzydko.

To, co zrobiłem, to rozszerzona klasa String z ormetodą

class String
  def or(what)
    self.strip.blank? ? what : self
  end
end

@user.address.or("We don't know user's address")

Teraz wygląda lepiej. Ale nadal jest surowy i szorstki

Jak byłoby lepiej rozwiązać mój problem. Może lepiej byłoby rozszerzyć ActiveSupport classlub użyć metody pomocniczej, mixinów lub czegokolwiek innego. Co może mi powiedzieć idealogia ruby, twoje doświadczenie i najlepsze praktyki.

fl00r
źródło

Odpowiedzi:

230

ActiveSupport dodaje presencemetodę do wszystkich obiektów, która zwraca swój odbiornik if present?(przeciwieństwo blank?) i w nilprzeciwnym razie.

Przykład:

host = config[:host].presence || 'localhost'
David Phillips
źródło
2
to jest fajne. Preferowane są domyślne możliwości szyn. Dzięki!
fl00r
Po pierwsze jest to preferowane, ponieważ w moim rozwiązaniu powinienem rozszerzyć co najmniej String, Fixnum i NilClass. I tutaj mogę po prostu użyć czystego kodu bez rowerów
fl00r
12

Phrogz w pewnym sensie podsunął mi pomysł w komentarzu PofMagicfingers, ale co z zastąpieniem | zamiast?

class String
  def |(what)
    self.strip.blank? ? what : self
  end
end

@user.address | "We don't know user's address"
Matt Briggs
źródło
2

Ponieważ robisz to w Ruby on Rails, wygląda na to, że pracujesz z modelem. Jeśli chcesz mieć rozsądną wartość domyślną w całej aplikacji, możesz (na przykład) zastąpić addressmetodę dla swojego Usermodelu.

Nie znam ActiveRecord wystarczająco dobrze, aby zapewnić dobry kod; w Sequelu byłoby to coś takiego:

class User < Sequel::Model
  def address        
    if (val=self[:address]).empty?
      "We don't know user's address"
    else
      val
    end
  end
end

... ale w powyższym przykładzie wydaje się, że będziesz mieszał logikę widoku w swoim modelu, co nie jest dobrym pomysłem.

Phrogz
źródło
Tak, to zły pomysł, aby ustawić wartości domyślne w modelach :) Moje formularze będą płakać
fl00r
2

Twoja metoda lub może mieć niepożądane skutki uboczne, ponieważ wartość alternatywna (domyślna) jest zawsze oceniana, nawet jeśli ciąg nie jest pusty.

Na przykład

@user.address.or User.make_a_long_and_painful_SQL_query_here

dałoby dodatkową pracę, nawet jeśli adres nie jest pusty. Może mógłbyś to trochę zaktualizować (przepraszam za mylącą jedną linijkę, próbując mówić krótko):

class String
  def or what = ""
    self.strip.empty? ? block_given? ? yield : what : self
  end
end

@user.address.or "We don't know user's address"
@user.address.or { User.make_a_long_and_painful_SQL_query_here }
Tonttu
źródło
dobra uwaga. Rozumiem. Ale dlaczego cały kod zostanie wykonany? zobacz:a=2 ; a == 2 ? "ok" : @b = 3 ; @b; #=> nil
fl00r
2
Zostanie on wykonany podczas wykonywania pierwotnego wywołania, a nie z operatorem trójskładnikowym. Wszystkie argumenty zostaną ocenione przy wywołaniu metody.
Tonttu
2

Prawdopodobnie lepiej jest rozszerzyć ActiveRecord lub poszczególne modele zamiast String.

Twoim zdaniem możesz preferować bardziej wyraźny wzór, taki jak

@user.attr_or_default :address, "We don't know the user's address"
maxl0rd
źródło
Czy to część Active Record? Nie znalazłem żadnych odniesień.
cabe56
0

Rubin:

unless my_str.empty? then my_str else 'default' end

RoR:

unless my_str.blank? then my_str else 'default' end
Lucio
źródło