2015-10-06 5 views
7

Kilka razy oglądałem prezentację Sandi Metz 'nothing is something. Zdaję sobie sprawę, że robię zerowe kontrole w całym miejscu w moich projektach szyn, ale nie wiem, jak uniknąć zerowych kontroli i jak to zrobić w sposób zorientowany obiektowo, jeśli chodzi o skojarzenia.Obiektowy sposób przeprowadzania zerowej kontroli powiązań w szynach

Rozważ te skojarzenia:

#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 

łapię użytkownika:

@user = User.find(1) 

I chcę, aby znaleźć jego blog:

@user.blog 
    => nil 

Zwraca nil tutaj, bo to user dzieje nie mieć żadnego powiązanego blog, więc w następujący sposób: Kod Skrzydło złamie wniosek, jeśli zrobiłem coś podobnego do tego user:

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

Prostym rozwiązaniem jest zrobić to tak non-obiektowego i po prostu zrobić nil czek (ale to jest to, co chcemy w celu uniknięcia, ponieważ w przeciwnym razie sprawdza nil są absolutnie wszędzie w aplikacji):

@user.blog.title if @user.blog 

Doing kontrole zerowe staje się bardziej kłopotliwe i proceduralny głębiej idziesz przez stowarzyszenia takie jak poniżej:

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

Jaki jest obiektowy sposób unikania zerowej kontroli stowarzyszeń?

Jestem świadomy szyn "try method, choć Metz nie polecał metody try. Być może jednak, jeśli chodzi o skojarzenia w szynach: try jest najlepszą opcją?

+0

** tylko sugestia: * * Zamiast wypalania '@user.b loguj za każdym razem, możesz umieścić go w zmiennej typu '@user_blog = @ user.blog' i sprawdzić jego obecność wszędzie tam, gdzie jest to wymagane:' @ user_blog.present? ' – Abhi

Odpowiedz

6

Istnieje programowania projektowania wytyczne nazywa The Law of Demeter

ten sposób aby zastosować go do swoich modeli szyn:

#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 

I teraz można to zrobić:

@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 

Proszę przeczytać poniższy link do referencji:

+0

Świetnie, naprawiłeś to sam –

1

myślę, że to mogłoby być opcje

użyłbym: rescue metodę
Uwaga: metoda ta łapie wyjątki i reaguje odpowiednio; Nie używaj tego, jeśli chcesz inaczej reagować na wyjątki.Mam nadzieję, że rozumiesz

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

Przykład:

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 '' 
=> "" 

Inną opcją byłoby .try metoda; http://apidock.com/rails/Object/try

.try jest zdefiniowana w Rails więc nie być dostępne z 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 

spróbować zwraca nil, gdy wezwał zera, niezależnie od tego, czy odpowiada ona metody:

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

Jest taki sprytny klejnot andand, którego używam w takich przypadkach. Normalnie trzeba by napisać:

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

andand gem realizuje ogólny wzór zerowej. andand rozszerza obiekt za pomocą metody andand, która zwraca obiekt, do którego został wywołany, chyba że jest zerowy. W przypadku zera zwracany jest obiekt NullPatern, który zwraca zero dla wszystkich wywołań metod za pomocą magii method_missing.

@user.blog.andand.title 

Jest nawet mocniejszy kiedy trzeba sprawdzić kilka warunków:

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

staje:

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

Sprawdziłem klejnot' andand' i wydaje się gem 'andand' robi dokładnie to, co już robi metoda' try' w szynach. 'try' pojawił się na szynach w wersji 2.3.2, która była w 2010 roku. Pierwsze wydanie klejnotu' andand' ukazało się w 2008 roku, więc myślę, że to, co się stało, było 'andand' było świetną opcją, dopóki' try' nie nadszedł i został wbudowany w szyny. – Neil

Powiązane problemy