delegate
方法似乎是在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.present?
但是这是一个零检查,我们希望避免零检查,否则它们将绝对是应用程序中的任何位置。
所以你可以这样做,这适用于demeter定律并且效果很好:
# open up app/models/user.rb
class User < ActiveRecord::Base
belongs_to :blog
delegate :title, to: :blog, prefix: true, allow_nil: true #add this
end
现在我们可以做到这一点,这很好,因为如果user
没有blog
,则只返回nil
而不是错误:undefined method 'title' for nil:NilClass
:
@user = User.find(1)
@user.blog_title
很好,这很有效,我们避免了零检查。但是如果我们想抓住相关的hash_tag.tag_name
呢?如果nil不是问题,我们可以这样做:
@user = User.find(1)
@user.blog_title.hash_tag.tag_name
这不仅会破坏demeter的规律,而且因为nil 是一个问题而且相关的hash_tag对象可能不存在,我们有一天会再次遇到错误:undefined method 'title' for nil:NilClass
。
我试图再次打开User
类并为委托添加嵌套目标,但它对我不起作用:
# again: open up app/models/user.rb
class User < ActiveRecord::Base
belongs_to :blog
delegate :title, to: :blog, prefix: true, allow_nil: true
delegate :tag_name, to: :'blog.hash_tag', prefix: true, allow_nil: true #doesn't work
end
显然我的语法已关闭,因为它不喜欢我将此嵌套目标指定为::'blog.hash_tag'
。
我想做的是能够说:@user.blog_hash_tag_tag_name
。代表可以这样做吗?
我检查了Delegate documentation。我没有看到它提到多个协会,就像我目前的情况一样。
答案 0 :(得分:5)
作为个人观点,@user.blog_hash_tag_tag_name
看起来很可怕。
也就是说,想要在用户级别定义两个委托也违反了LoD,因为您正在使用来自用户类的博客内部工作的知识(事实上它属于hash_tag)。
如果您想使用委托,则应添加到课程User
delegate :hash_tag_tag_name, to: :blog, prefix: true, allow_nil: true
和课程Blog
delegate :tag_name, to: :hash_tag, prefix: true, allow_nil: true
答案 1 :(得分:1)
我建议你使用Null Object Pattern,这在https://github.com/avdi/naught gem中实现得非常好(查看它的文档,它摇滚!)和他的ActiveRecord对应物 https://github.com/Originate/active_null。