我已经看了好几次 Sandi Metz 的 nothing is something 演讲。我意识到我在 Rails 项目中的所有地方都进行了 nil 检查,但我不知道如何避免 nil 检查以及如何在涉及关联时以面向对象的方式进行检查。

考虑这些关联:

#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

简单的解决方法是使用非面向对象的方式,只做一个 nil 检查(但这是我们想要避免的,否则 nil 检查在应用程序中绝对无处不在):
@user.blog.title if @user.blog

进行 nil 检查会变得越麻烦和程序越深入,如下所示:
@user = User.find(1)
if @user.blog && @user.blog.hash_tag #checking for nil twice
  @user.blog.hash_tag.tag_name
end

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

我知道 rails 的 try method ,尽管 Metz 似乎不推荐 try 方法。也许当涉及到 rails 中的关联时:try 是最好的选择?

最佳答案

有一个名为 The Law of Demeter 的编程设计指南

这是将它应用到 Rails 模型的方法:

#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

请阅读以下链接以获取引用:
  • http://apidock.com/rails/Module/delegate
  • http://samurails.com/tutorial/rails-delegate-dont-break-the-law-of-demeter/
  • 关于ruby-on-rails - 在 Rails 中对关联进行 nil 检查的面向对象方法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32961073/

    10-14 13:06
    查看更多