/ / Objektorientierte Methode, um keine Überprüfungen auf Assoziationen in Schienen durchzuführen - Ruby-on-Rails, Ruby

Objektorientierte Methode zur Überprüfung von Assoziationen in Schienen - Ruby-on-Rails, Ruby

Ich habe Sandi Metz gesehen " nichts ist etwas Präsentation jetzt ein paar Mal. Mir ist klar, dass ich in meinen Rails-Projekten überall keine Überprüfungen durchführe, aber ich weiß nicht, wie ich keine Überprüfungen vermeiden und wie ich es objektorientiert machen soll, wenn es um Assoziationen geht.

Betrachten Sie diese Assoziationen:

#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

Ich greife nach einem Benutzer:

@user = User.find(1)

Und ich möchte seinen Blog finden:

@user.blog
=> nil

Es kehrt zurück nil hier weil das user zufällig nicht zugeordnet zu haben blog, also der folgende Code würde die Anwendung beschädigen, wenn ich dafür so etwas mache user:

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

Die einfache Lösung besteht darin, dies nicht objektorientiert zu tun und nur eine Nullprüfung durchzuführen (dies ist jedoch das, was wir vermeiden möchten, da ansonsten Nullprüfungen absolut überall in der Anwendung vorhanden sind):

@user.blog.title if @user.blog

Das Durchführen von Nullprüfungen wird umständlicher und prozeduraler, je tiefer Sie durch die folgenden Assoziationen gehen:

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

Was ist die objektorientierte Methode, um Nullprüfungen für Assoziationen zu vermeiden?

Schienen sind mir bekannt " versuche Methode, obwohl Metz das nicht zu empfehlen schien try Methode. Vielleicht aber, wenn es um Assoziationen in Schienen geht: try ist die beste Option?

Antworten:

6 für die Antwort № 1

Es gibt eine Programmier-Design-Richtlinie namens Das Gesetz von Demeter

So wenden Sie es auf Ihre Schienenmodelle an:

#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

Und jetzt können Sie dies tun:

@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

Bitte lesen Sie den folgenden Link für Referenzen:


2 für die Antwort № 2

Es gibt ein schickes Juwel andand was ich in solchen Fällen benutze. Normalerweise müssten Sie schreiben:

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

andand gem implementiert ein generisches Nullmuster. andand erweitert Object um eine Methode andand, das ein Objekt zurückgibt, für das es aufgerufen wurde, es sei denn, es ist null. Im Fall von nil wird das NullPatern-Objekt zurückgegeben, um nil für alle Methodenaufrufe mit method_missing magic zurückzugeben.

@user.blog.andand.title

Es ist noch leistungsfähiger, wenn Sie mehr Bedingungen überprüfen müssen:

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

wird:

@user.blog.andand.title.andand.capitalize

1 für die Antwort № 3

Ich denke, das könnte eine Option sein

Ich würde ... benutzen: rescue Methode
Vorsicht: Diese Methode fängt Ausnahmen ab und reagiert entsprechend. Verwenden Sie dies nicht, wenn Sie auf Ausnahmen anders reagieren müssen. Ich hoffe, Sie verstehen

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

Beispiel:

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

Eine andere Option wäre .try Methode; http://apidock.com/rails/Object/try

.try ist definiert in Rails also nicht verfügbar sein aus 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

try gibt beim Aufruf von nil nil zurück, unabhängig davon, ob es auf die Methode reagiert:

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