Rails中关注点困境的分离

时间:2010-07-06 12:02:59

标签: ruby-on-rails separation-of-concerns

我正在尝试为我的rails应用程序进行日志记录,并且在rails中使用哲学方面存在一些困境。我的应用有Link模型has_many Hit s:

class Link < AR::Base
  has_many :hits
end

class Hit < AR::Base
  belongs_to :link
end

现在每次点击链接时,我都会调用hit!方法来记录链接上的请求(为了保持控制器的瘦,我会使模型变胖):

class LinksController < ApplicationController
  def hit
    link = Link.find(params[:id])
    link.hit!(request)
  end
end

class Link < AR::Base
  def hit!(request)
    params = extract_data_from_request(request)
    hits.create(params)
  end
end

现在我在这里感到困惑。我想记录request对象附带的数据(如远程ip,referrer,用户代理等),所以我需要将请求对象传递给模型,但我认为这不符合“分离”关注“并模糊MVC设计模式中的责任线(当然,如果我错了,请纠正我)。此外,如果我将在控制器本身中创建一个Hit对象,那么我正在制作瘦模型和胖控制器:

class LinksController < ApplicationController
  def hit
    hit_params = extract_data_from_request(request)
    Hit.create(hit_params.merge(:link_id => params[:id])
  end
end

虽然后一种情况使测试更容易(我不需要在模型规范中模拟请求) - 但它似乎不正确。

对此有任何建议 - 非常感谢。

P.S。 extract_data_from_request(req)方法放置在需要的适当位置。它返回Hit对象所需属性的哈希值。

2 个答案:

答案 0 :(得分:2)

就个人而言,我会过分思考这些事情。

点击的概念与网站或Web应用程序密切相关,因为(HTTP)请求的概念也是如此。胖控制器反模式更多的是包含冗长的控制器操作,其中包含ActiveRecord查找语句和业务逻辑(通常以if / elsif / else块为特征),可以轻松地将其提取到模特。

控制器具有一定的编排职责。在一个内部创建一个对象并不是一个令人发指的罪行。毕竟,我们会在create行动中一直这样做。

答案 1 :(得分:2)

是的,我同意约翰的意见。请求的概念通常是“控制器事物”,但在这种情况下,您的模型是建模请求,因此在这种情况下它肯定在模型领域。有效地,一旦请求对象跨越从控制器到模型的边界,它就只是另一个对象,没有特殊属性:它不再关注获取和响应html请求的过程,它只是一个对象,你可以做任何你想做的事情。

但要注意的一件事是,ruby参数是通过引用传递的。这意味着您在模型中操作的请求对象是与控制器中处理的对象相同的对象。我可能过于偏执(或者只是完全错误)但你可能想要将它的副本传递给模型而不是实际的请求本身。即

class LinksController < ApplicationController
  def hit
    link = Link.find(params[:id])
    link.hit!(request.dup)
  end
end