2009-06-27 17 views

risposta

7

Personalmente, vorrei utilizzare il or operatore/parola chiave:

(financial_document.assets or []).length 

In entrambi i casi, .length viene chiamato su un array, dandovi 0 se nil.

7

Il modo meno ripetitivo di gestire questo è garantire che financial_document.assets sia sempre un oggetto non nullo, disponendo che esso contenga un valore sentinella appropriato (ad esempio, una raccolta vuota o un oggetto speciale che ha comportamento degenerato).

Vedere The Null Object Pattern.

0

Stando Ruby, si potrebbe aggiungere un metodo di lunghezza per NilClass e lo hanno tornare sempre 0.

0

si può rendere un po 'più corta:

financial_document.assets ? financial_document.assets.length : '0' 

beca utilizzare

financial_document.assets == !financial_document.assets.nil? 

ma in generale, IMHO non c'è modo meno ripetitivo, solo vari soluzioni alternative. (E questa è una delle cose che non mi piacciono molto in Ruby.) Puoi assicurarti che gli oggetti non siano nulli (come suggeriscono altre persone qui) - ma non puoi farlo ovunque. È possibile eseguire il wrap del codice di controllo nullo nei metodi di supporto o nei blocchi di avvio immediato.

Per esempio, piuttosto che aggiungere il metodo di lunghezza per oggetto nil (che è secondo me un hack sporco), avevo scritto un metodo di supporto - una "lunghezza di getter":

def fd_length(financial_document) 
    financial_document.assets ? financial_document.assets.length : '0' 
end 
3

Caso 1:

financial_document e assets hanno molte relazioni. In questo caso, financial_document.assets restituisce sempre un array. Quindi, financial_document.assets.size ti darebbe 0 se non viene trovato nessun elemento figlio corrispondente, e altrimenti taglia.

Caso 2:

assets è solo un metodo/attributo financial_document. Quindi disporre dell'array di restituzione del metodo assets, in modo da poter sempre richiamare .size su di esso. Proprio come ha fatto notare Joel.

3

In tal caso io uso andand gemma:

financial_document.assets.andand.length || 0 
0

Qualcosa nel modello che restituisce 0 o la lunghezza. Questo ti impedisce di dover fare qualcosa di convalutato secondo te. Cose come questa possono normalmente essere fatte nel modello.

class FinancialDocument 

    def assets_length 
    assets.length.blank? 0 : assets.length 
    end 
end 
3

Un modo più generico per risolvere questo tipo di problemi è quello di aggiungere un metodo di prova per oggetto:

## 
    # @user.name unless @user.nil? 
    # vs 
    # @user.try(:name) 
    # 
    def try(method, *args, &block) 
    return nil unless method 
    return nil if is_a?(NilClass) and [:id, 'id'].include?(method) 
    self.send(method, *args, &block) if respond_to?(method) 
    end 

credo Ruby 1.9 ha già il metodo prova su oggetto.

Quindi financial_document.assets.try(:length).to_i otterrebbe il risultato desiderato. Questo è perché nil.to_i restituisce 0

+0

prova è stata backport in Ruby 1.8 per Rails 2.3 - vedere http://railscasts.com/episodes/152-rails-2-3-extras –

1

financial_document.assets.try (: length) || 0

provare è un metodo che invocherà il metodo dell'oggetto se non è nil altrimenti restituirà solo nil. E provare i metodi nil restituiranno sempre nil invece di lanciare un'eccezione.

http://api.rubyonrails.org/classes/Object.html#method-i-try

Questo è il modo di Ruby per fare questo!

+0

Il modo in Rails, non il modo di Ruby. – Jerph

1

Puoi farlo senza gemme aggiuntive. Ho utilizzato ||, andand, try, ma il seguente aspetto è più semplice. Penso che sia il modo rubino per confermare il modello di oggetto nullo di Dave.

financial_document.assets.to_a.length 
Problemi correlati