2015-10-06 56 views
7

我已经看了桑迪梅茨'nothing is something演示文稿几次现在。我意识到我在我的rails项目中遍地都没有检查,但我不知道如何避免零检查,以及如何在关联方面以面向对象的方式进行检查。面向对象的方式做零检查协会在轨道

考虑这些协会:

#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 

我抢用户:

@user = User.find(1) 

而且我想找到他的博客:

@user.blog 
    => nil 

在这里返回nil因为这user情况没有关联blog,所以下面翼码将打破应用程序,如果我做了这样的事情本user

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

简单的解决方法是做到这一点的非面向对象的方式,只是做一个零检查(但是这是我们所希望的为了避免因为否则为零检查是绝对无处不在的应用程序):

@user.blog.title if @user.blog 

做零检查变得更加繁琐,程序越深,你去通过协会象下面这样:

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

避免对关联进行零检查的面向对象的方法是什么?

我知道铁轨'try method,虽然梅斯似乎没有推荐try方法。也许,虽然说到rails中的关联:try是最好的选择吗?

+0

**只是一个建议:* *而不是发射'@user.b日志“,你可以把它放在一个像@user_blog = @ user.blog这样的变量中,然后检查它是否存在,如:@ user_blog.present?' – Abhi

回答

6

还有就是编程称为The Law of Demeter

设计方针这是怎么了将其应用于您的导轨型号:

#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 

现在你可以这样做:

@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 

请阅读以下链接引用:

+0

太棒了,你已经自己修复了 –

1

我觉得这可能是一个选项

我会用:rescue方法
注意:此方法捕获异常并做出相应的响应;如果您需要以不同的方式响应异常,请不要使用它。我希望你明白

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

例子:

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

另一种选择是.try方法; http://apidock.com/rails/Object/try

.tryRails定义,因此无法提供出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 

尝试在零称为不管它响应方法时返回nil:

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

有一个漂亮的宝石andand我在这种情况下使用。通常你需要写:

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

andand gem实现了泛型null模式。 andand使用方法andand扩展对象,该方法返回它被调用的对象,除非它为零。如果为零,则使用method_missing magic返回NullPatern对象以返回所有方法调用的nil。

@user.blog.andand.title 

当你需要检查更多的条件,这更是如虎添翼:

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

变为:

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

我查看了'andand' gem,它出现了'andand' gem完成了rails中的'try'方法。在2010年的2.3.2版本中''try'出现了。'andand' gem的最初版本在2008年推出,所以我认为发生的事情是'andand'是一个很好的选择,直到'try'出现并建成了铁轨。 – Neil