Rails 中的关注点分离困境

发布于 2024-09-08 07:54:29 字数 1177 浏览 5 评论 0原文

我正在尝试为我的 Rails 应用程序进行日志记录,但对 Rails 中使用的哲学存在一些困境。我的应用程序有 Link 模型,其中 has_many Hits:

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、引用者、用户代理等),因此我需要将请求对象传递给模型,但我认为这不符合到“关注点分离”并模糊了 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

尽管后一种情况使测试变得更容易(我不需要在模型中模拟请求)规格)-这似乎不太正确。

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

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

I'm trying to make logging for my rails app and have some dilemmas over philosophy used in rails. My app has Link model which has_many Hits:

class Link < AR::Base
  has_many :hits
end

class Hit < AR::Base
  belongs_to :link
end

Now each time the link is being hit, I call hit! method to record a request on the link (to keep the controller skinny I make the model fat):

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

Now here's where I'm confused. I want to record the data that came with request object (like remote ip, referrer, user agent, etc.) so I need to pass request object down to model, but I believe that this does not conform to "separation of concerns" and blurs responsibility lines in MVC design pattern (of course, correct me if I'm wrong). Also if I'll create a Hit object in controller itself, then I'm making skinny model and fat controller:

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

Although the latter case makes testing much easier (I don't need to mock request in model specs) - it just doesn't seem right.

Any advice on this - much appreciated.

P.S. extract_data_from_request(req) method is placed in appropriate places where needed. It returns a hash of needed attributes for Hit object.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

笨死的猪 2024-09-15 07:54:29

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

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

控制器具有一定的编排职责。在一个人体内创造一个物体并不是一种令人发指的罪行。毕竟,我们一直在 create 操作中执行此操作。

Personally I would be wary of over-thinking these things too much.

The concept of a hit is very much tied to a website or web application, as is the concept of a (HTTP) request. The fat controller anti-pattern is more about having lengthy controller actions that contain ActiveRecord find statements and business logic (often characterised by if/elsif/else blocks) that can easily be extracted into the model.

Controllers have certain orchestration responsibilities. Creating an object within one isn't a heinous crime. After all, we do it all the time in our create actions.

乜一 2024-09-15 07:54:29

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

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

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

Yeah, i'd agree with John. The concept of a request would normally be a 'controller thing' but in this case your model is modelling a request, so it's definitely in model territory in this case. Effectively once the request object crosses the boundary from controller into model it's just another object, with no special properties: it's no longer concerned with the process of getting and responding to html requests, it's just an object that you can do whatever you want with.

One thing to be wary of, though, is that in ruby arguments are passed by reference. That means that the request object you are manipulating in your model is THE SAME OBJECT as the one being dealt with in the controller. I may be being overly paranoid (or just plain wrong) but you might want to pass a duplicate of it to the model rather than the actual request itself. ie

class LinksController < ApplicationController
  def hit
    link = Link.find(params[:id])
    link.hit!(request.dup)
  end
end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文