Rails委托具有多个关联的方法

时间:2015-10-06 19:01:15

标签: ruby-on-rails ruby rails-activerecord

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。我没有看到它提到多个协会,就像我目前的情况一样。

2 个答案:

答案 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