在Rails中实现NullObject模式

时间:2013-06-15 19:54:09

标签: ruby-on-rails activerecord null-object-pattern

我是一个Post belongs_to :user我要保留已删除用户帖子的应用程序。在查看作者被删除的帖子时,这可能会导致视图出错。我试着这样做:

class Post < ActiveRecord::Base
  belongs_to :author, class_name: 'User', foreign_key: 'user_id'

  def author
    author || NullUser.new
    super
  end
end

这会导致“堆栈级别变深”错误。为什么?我能做到这一点:

class Post < ActiveRecord::Base
  belongs_to :user

  def author
    user || NullUser.new
  end

  def author=(user)
    self.user = user
  end
end

但以这种方式混淆我的协会似乎并不正确。什么是最好的方法呢?

2 个答案:

答案 0 :(得分:13)

要回答你的问题,

1. def author
2.   author || NullUser.new
3.   super
4. end

在第1行中,您正在定义author方法。然后在第2行,你再次调用那个作者方法!这种情况一直在发生,并且你得到的堆栈级别太深了。正确的方法是,

def author
  super || NullUser.new
end

所以你不再在内部调用author方法了。你只是调用超类或返回NullUser。如果您在调用super时收到nil错误,请添加额外的nil检查:

def author
  (super || NullUser.new) rescue NullUser.new
end

救援声明将捕获所有错误,然后返回NullUser.new,因此您不必担心超级抛出错误。

编辑:

处理看起来更好的超级抛出异常的另一种方法:

def author
  (super rescue nil) || NullUser.new
end

答案 1 :(得分:3)

如果您想保留已删除用户的帖子,最好不要真正“删除”它们。

另一种选择是“软删除”。只需添加一个布尔列,说“已删除”或“无效”。

因此,当您要删除用户时,请检查他是否有帖子。如果没有,硬删除他。如果有,软删除。

这样事情就会变得简单和干净。

另一种方法是“窃取”帖子。删除用户时,请在特殊用户帐户下移动所有帖子,然后将其删除。

无论哪种方式,你都不会破坏这种关联。