何时(以及如何!)遵守得墨忒耳法则

时间:2014-04-29 20:10:16

标签: ruby-on-rails

老实说,我很困惑。显然你可以在Rails中轻松打结自己,因为你可以非常简单地进行非常复杂的查询,我想我已经发现了这一点。

以下是我的关系:

  

论坛 has_many:belongs_to 主题

     

主题 has_many:belongs_to 帖子

     

主题 has_many:belongs_to 用户

     

用户 has_many:belongs_to 帖子

现在,让我们说当创建一个新帖子时,我想通过电子邮件发送给所有订阅该主题的人发送新帖子。在电子邮件中,我提供了论坛的名称,主题的名称以及帖子本身的名称和正文。我将这些参数传递给负责发送电子邮件的实例方法#notify_all_users

以下是我在PostsController中的表现:

def create
    @user = current_user
    @post = @user.posts.new(parameters)

    if @post.save
        @post.notify_all_users(post: @post, topic: @post.topic, forum: @post.topic.forum)
    end 
end

现在是否违反了德米特定律? forum选项的方法链中有两个点,但dependent :destroyTopic上已设置Post,因此如果帖子不存在,则该帖子不存在主题不存在,如果论坛不存在,则主题不存在,因此任何讨厌的零错误类错误的可能性为零。我是否还应采取措施使其遵守得墨忒耳法则?

就像我说的那样,我已经发现为什么得墨忒耳定律很重要(我想,我不确定)。

我们说我浏览到我的主题页面,其中显示了属于该主题的所有帖子。没有违反demeter的法律!

但是,让我们说我想要在帖子旁边显示每个帖子所有者的用户名,如下所示:

<div> <%= link_to post.user.user_name, post.user %> </div> 
<div> <%= post.body %> </div>

这违反了德米特定律,对吧?

由于我们的主题#show action set @topic,我们循环播放@topic.posts但现在,在该视图中,我们有效地执行了此操作:@topic.post.user.user_name每个帖子。< / p>

现在,LOD这么重要吗?因为如果在主题中恰好有帖子的单个用户被删除,整个应用程序就会停止运行。 Nil nil类错误,因为帖子不再具有用户类(当然,它没有user_name)。

我认为绕过这个问题的方法是在父模型中设置dependent :destory,或者在用户中设置soft_delete,但我发现我只是在挖洞中进一步挖掘。

那么,请问我如何遵守得墨忒耳法则?在这些例子中?我应该如何显示用户的姓名?它应该保存在数据库中吗?因此,当用户创建新帖子时,他的名字实际存储在posts表中?然后,如果用户点击了用户名,如果他被删除,我可以在用户#show action中进行救援ActiveRecord::RecordNotFound

似乎(对我来说)遵守法律的唯一方法是广泛地在数据库中写下我们需要的所有信息。所以我的创建动作看起来应该是这样的:

# post controller
def create

    parameters = post_params.merge(user_name: @user.user_name)        

    @user = current_user
    @post = @user.posts.new(parameters)

    if @post.save
        # redirect passed validations
    else
        # redirect failed validations
    end
end

现在我们可以在视图中执行此操作:

<div> <%= link_to post.user_name, user_path(post.user_id) %> </div> 
<div> <%= post.body %> </div>

其实,就像写作一样:

@topic.post.user_name
@topic.post.user_id

@topic.post.body 

哪个不违反法律。看起来有点不正常的人,当我们能够轻松地使用AR(并保存整个表格列)时,项目只会变得足够复杂以便看到LoD的重要性,但我确实看到了重要性。

1 个答案:

答案 0 :(得分:1)

正如Held所提到的,为你的Post课程添加一个方法。我称之为author_name。因为你的系统有用户,当然,如果你只是看一篇文章,那么问题基本上是&#34;谁写了这个?&#34;而不是&#34;我系统中的哪些用户记录与此特定帖子记录相关联?&#34;

这种间接也可以帮助解决用户删除问题:

当用户被删除时,您可以想象通过该用户的帖子,并在每个帖子上设置author_name(或其他)属性。 E.g。

class User
  # ...
  before_destroy :save_name_to_posts

  private

  def save_name_to_posts
    posts.update_all(author_name: name)
  end
end

现在,在Post模型中,你可以这样做:

# you can just use alias/alias_method for this
def author
  user
end

def author_exists?
  author.present?
end

def author_name
  author_exists? ? user.name : super
end

因此,在您看来,您总是会有一些名称来绑定帖子。您使用author_exists?来检查帖子的作者是否还在,所以如果您要链接到某些内容,则只需link_to(或者您可以使用link_to_if)< / p>

如果您不允许用户更改其名称,您当然可以立即将其添加到Post模型中。但是,如果他们可以更改它,只有在他们即将被删除时(而不是每次更改他们的名字时)运行更新查询,效率会更高。