铁轨中的脂肪控制器

时间:2012-10-02 20:29:09

标签: ruby-on-rails model-view-controller design-patterns controllers

我开始在railstutorial.org处完成教程 接触框架。我的控制器还不是很怪异,但我可以 请注意,整个教程中未应用Single Responsibility Principal(SRP),因为它超出了本教程的范围。

我有relatively simple controller here。我已经可以看到泄漏到此控制器的不同问题(例如身份验证和授权),其中包含太多的操作。这会为一个控制器分配太多动作。 我偶然发现rails focused controllers解决了其中一个问题 而且看起来很有趣。

这是一个常见的解决方案吗?或者是更好的解决方案?

在.net世界中,我们倾向于使用aspect oriented programming(AOP) 实现清洁Separation of Concerns (SoC)。然而,最近有几个人编写了一个名为Fubu Behaviours的新前端控制器框架。它很好地捕获了请求管道的想法。对我来说越来越有意义的东西。

为了处理请求,我们往往会经历几个步骤(有时候 之后)执行动作。在某些情况下,有条件地结束请求。使用诸如行为,管道或俄罗斯娃娃模式之类的东西似乎很自然。 因此,链中的每个链接都要么是继续还是停止。继承似乎不是最好的解决方案。

有没有类似于rails的内容?它在轨道上有意义吗?

推荐读物也欢迎!

3 个答案:

答案 0 :(得分:2)

我同意你的看法,is_admincorrect_user这些授权功能有点像代码味道。我会删除它们并使用我经常使用的名为CanCan的gem更好地处理它。

它允许您将所有授权规则从控制器中移出到清单(即能力模型)中,只需要控制器通过控制器中的authorize_resource调用启动授权检查。然后,您可以在ApplicationController

中处理简单的重定向
class ApplicationController < ActionController::Base
  rescue_from CanCan::AccessDenied do |exception|
    if current_user
      redirect_to signin_url, :alert => exception.message
    else
      redirect_to root_path, :alert => exception.message
    end
  end
end

除此之外,我会将所有@user = User.find(params[:id])次调用移至before_filter,并清理您的缩进和行动顺序(应为indexnew,{{1} },createshoweditupdate)我认为你的控制器会很好而且很瘦。

答案 1 :(得分:1)

老实说,我无法确定授权/认证是模型还是控制器的工作,人们会给你各种答案。这就像一个灰色区域。

所以我更喜欢那里的Rails惯例,因为这些年来它们已经被证明是值得信赖的。你的控制器对我来说似乎很好,我不会称它们为胖。你可以将这些私人方法转移到帮手。

答案 2 :(得分:0)

对于任何类型的授权逻辑,我实际上会从控制器层中删除它,并将其移到“策略”中。层

使用此gem:https://github.com/NullVoxPopuli/skinny_controllers 它为您提供了两个额外的层

  • 操作
    • 业务逻辑在哪里
  • 政策
    • 授权的地方

自述文件中的一个例子:

module EventOperations
  class Read < SkinnyControllers::Operation::Base
    def run
      # the business logic here is to only check if we will allow this model
      # to be returned
      model if allowed?
    end
  end
end



class EventPolicy < SkinnyControllers::Policy::Base
  # allowed? from the operation delegates to this method
  # here, you could do whatever logic you need to check if the operation
  # is allowed
  def read?(o = object)
    o.is_accessible_to?(user)
  end
end