2015-10-06 11 views
7

Ho visto la presentazione di Sandi Metz nothing is something un paio di volte. Mi rendo conto di non effettuare controlli nulli ovunque nei miei progetti di rotaie, ma non so come evitare controlli nulli e come farlo in modo orientato agli oggetti quando si tratta di associazioni.Modo orientato agli oggetti per eseguire controlli nulli per le associazioni nei binari

Considerate queste associazioni:

#app/models/user.rb 
class User < ActiveRecord::Base 
    belongs_to :blog 
end 

#app/models/blog.rb 
class Blog < ActiveRecord::Base 
    belongs_to :hash_tag 
    has_one :user 
end 

#app/models/hash_tag.rb 
class HashTag < ActiveRecord::Base 
    has_one :blog 
end 

prendo un utente:

@user = User.find(1) 

e voglio trovare il suo blog:

@user.blog 
    => nil 

Esso restituisce nil qui perché questo user accade per non avere associato blog, quindi il follo Codice dell'ala avrebbe rompere l'applicazione se ho fatto qualcosa di simile per questo user:

@user.blog.title 
    => undefined method `title' for nil:NilClass 

La soluzione semplice è quella di farlo nel modo non orientata agli oggetti e basta fare un assegno pari a zero (ma questo è ciò che vogliamo al fine di evitare, perché i controlli altrimenti nil sono assolutamente ovunque nell'applicazione):

@user.blog.title if @user.blog 

Facendo controlli nil ottiene più ingombrante e procedurale più ci si passa attraverso associazioni come di seguito:

@user = User.find(1) 
if @user.blog && @user.blog.hash_tag #checking for nil twice 
    @user.blog.hash_tag.tag_name 
end 

Qual è il modo orientato agli oggetti per evitare controlli nulli per le associazioni?

Sono a conoscenza dei binari 'try method, sebbene Metz non abbia raccomandato il metodo try. Forse però quando si tratta di associazioni in binari: try è l'opzione migliore?

+0

** Solo un suggerimento: * * Invece di sparare '@user.b log' ogni volta, puoi metterlo in una variabile come '@user_blog = @ user.blog' e controllarne la presenza ovunque richiesto come:' @ user_blog.present? ' – Abhi

risposta

6

C'è programmazione progettazione linea guida chiamato The Law of Demeter

Questo è il modo in per applicarlo ai modelli di rotaie:

#app/models/user.rb 
class User < ActiveRecord::Base 
    belongs_to :blog 
    delegate :title, to: :blog, prefix: true, allow_nil: true 
    # then you can call user.blog_title 
    delegate :tag_name, to: :blog, prefix: true, allow_nil: true 
    # follow LoD 
end 

#app/models/blog.rb 
class Blog < ActiveRecord::Base 
    belongs_to :hash_tag 
    delegate :tag_name, to: :hash_tag, allow_nil: true 
    has_one :user 
end 

E ora si può fare questo:

@user = User.find(1) 
@user.blog_title # no error even if there is no associated blog 
@user.tag_name # no error even if there is no associatd blog or no associated hash_tag object 

Si prega di leggere seguente link per i riferimenti:

+0

Ottimo, l'hai risolto da solo –

1

credo che questo potrebbe essere una delle opzioni

userei: rescue metodo
Attenzione: questo metodo cattura eccezioni e risponde di conseguenza; Non utilizzare questo se è necessario rispondere alle eccezioni in modo diverso.Spero che tu capisca

@user = User.find(1) 
tag_name = @user.blog.hash_tag.tag_name rescue '' # respond with default value 

Esempio:

2.1.1 :001 > var1 = nil 
=> nil 
2.1.1 :002 > my_val = var1.some_method 

NoMethodError: undefined method `some_method' for nil:NilClass 
    from (irb):2 
    from /home/shiva/.rvm/rubies/ruby-2.1.1/bin/irb:11:in `<main>' 

2.1.1 :003 > my_val = var1.some_method rescue '' 
=> "" 

Un'altra opzione sarebbe quella .try metodo; http://apidock.com/rails/Object/try

.try è definito in Rails quindi non essere disponibile fuori Rails

@person.non_existing_method if @person.respond_to?(:non_existing_method) 
# instead use 
@person.try(:non_existing_method) # => returns nil if does not respond_to 

cercano rendimenti nil quando ha invitato nullo indipendentemente dal fatto che risponde al metodo:

nil.try(:to_i) # => nil, rather than 0 
2

C'è una bella gemma andand che uso in casi come questo. Normalmente si avrebbe bisogno di scrivere:

@user.blog && @user.blog.title 

andand gemma implementa modello nullo generico. andand estende Object con un metodo andand, che restituisce un oggetto a cui è stato chiamato a meno che non sia nullo. In caso di zero, l'oggetto NullPatern viene restituito per restituire nil per tutte le chiamate di metodo utilizzando method_missing magic.

@user.blog.andand.title 

E 'ancora più potente quando è necessario controllare più condizioni:

@user.blog && @user.blog.title && @user.blog.title.capitalize 

diventa:

@user.blog.andand.title.andand.capitalize 
+0

Ho esaminato la gemma' andand' e sembra la gemma 'andand' fa esattamente quello che il metodo' try' in rail ha già. 'try' è uscito per binari nella versione 2.3.2 che era nel 2010. La versione iniziale del' andand' gem uscì nel 2008, quindi penso che quello che è successo è 'andand' è stata una grande opzione fino a quando' try' è arrivato ed è stato costruito su rotaie. – Neil

Problemi correlati