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 的东西?
好的,这是我的问题:
我有一个 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 的东西?