Rails,连接到控制器

Rails, hooking into controllers

好的,这是我的问题:

我有一个 HomeController 带有一个操作,比如说 index,它会为我的网站呈现一个登陆页面。该站点还有许多其他控制器,它们实现了各种其他功能的操作。

我想要在我的主页上有一个动态导航栏,我正在寻找的是 HomeController#index 转到我的应用程序中的每个其他控制器并调用一个特定的方法,该方法将 return 和具有 link 详细信息的对象,例如,HomeController#index 将转到 ContactController 并调用方法 get_link,该方法将 return 类似于:

{label: "Contact", url: "/contact"}

同样,HomeController#index 会尝试在每个其他控制器上调用 get_link,直到它收集了 Array 个 link 对象,然后可以将这些对象传递给视图进行渲染导航。

我尝试通过模块中的元编程并使用 included 挂钩方法(从 Sitepoint tutorial 获取我的引用)来完成此操作。但这没有用。然后我在某处读到我可能必须使用 ActiveSupport::Concern 来实现这种功能,但我不确定如何去做。我已经在 PHP CMS 上工作过,比如 Drupal 和 WordPress,他们使用钩子实现它,这或多或少是我在这里寻找的。有什么想法吗?

首先你需要预先加载所有控制器:

Rails.application.eager_load!

然后,获取应用中的控制器列表:

controllers = ApplicationController.descendants

从这里你可以调用他们的 class 方法

controllers[0].get_link

请注意,方法应声明为 class 方法,如下所示:

def self.get_link
end

这可能会稍微减慢您的应用程序,因为它会立即加载所有内容。总的来说,这在我看来不是个好主意,因为您应用程序中的控制器几乎是静态的。考虑使用路径助手而不是像 contact_path 这样的例子。查看 Rails Routing Docs 了解详情。

在 Rails 风格中,MVC 控制器不是一堆杂项垃圾的垃圾场。事实上,控制器的唯一 public 方法是对应于 HTTP 请求的操作:

class ThingsController

  before_action :set_thing, except: [:new, :index]

  # THIS IS THE "PUBLIC API" OF THE CONTROLLER:

  # GET /things
  def index
    @things = Thing.all
  end

  # GET /things/:id
  def show
  end

  # EVERYTHING ELSE IS PRIVATE!
  private

    def set_thing
      @thing = Thing.find(params[:id])
    end
end

事实上,控制器只能由 Rails 路由器或您的控制器测试实例化。虽然您可以创建 class 方法并在您的控制器上调用它们,但这也是一个巨大的反模式。

根据 single responsibility pattern,控制器的工作只是在路由层调用时响应 HTTP 请求。

那么这样的案例你解决了吗:

  • 查看部分内容
  • 辅助方法
  • 初始化器/配置

具体如何解决问题取决于用例 - 内容是静态的还是您正在构建类似 CMS 的东西?