Rails,挂钩到控制器

时间:2016-05-14 11:25:23

标签: ruby-on-rails plugins hook metaprogramming activesupport

好的,这是我的问题:

我有一个HomeController的动作,比如index,它会为我的网站呈现一个目标网页。该站点还有许多其他控制器,可以实现各种其他功能的操作。

我想在我的主页上使用动态导航栏,而我正在寻找的是HomeController#index转到我应用中的每个其他控制器并调用一个特定的方法,该方法将返回并反对链接详细信息,例如,HomeController#index将转到ContactController并调用方法get_link,该方法将返回如下内容:

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

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

我尝试通过模块中的元编程并使用 included 钩子方法(从Sitepoint tutorial获取我的引用)来做到这一点。但那没用。然后我在某处读到了我可能必须使用 ActiveSupport::Concern 来实现这种功能,但我不知道该怎么做。我曾经使用像Drupal和WordPress这样的PHP CMS,但是他们使用钩子实现了这个,这或多或少是我在这里寻找的。有什么想法吗?

2 个答案:

答案 0 :(得分:2)

在Rails风格中,MVC控制器不是一堆杂项垃圾的倾销场所。事实上,控制器的唯一公共方法是与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路由器或控制器测试实例化。虽然您可以创建类方法并在控制器上调用它们,但这也是一个巨大的反模式。

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

所以你解决了这样的情况:

  • 查看部分
  • 帮助方法
  • initializers / config

如何解决问题取决于用例 - 内容是静态的,还是构建CMS之类的东西?

答案 1 :(得分:0)

首先,您需要急切加载所有控制器:

Rails.application.eager_load!

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

controllers = ApplicationController.descendants

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

controllers[0].get_link

请注意,方法应声明为类方法:

def self.get_link
end

这可能会减慢你的应用程序,因为它急于加载所有东西。总的来说,在我看来,这似乎不是一个好主意,因为你的应用程序中的控制器几乎是静态的。考虑使用路径助手,例如contact_path。查看Rails Routing Docs了解详情。