【问题标题】:Rails, hooking into controllersRails,连接到控制器
【发布时间】:2016-05-14 11:25:22
【问题描述】:

好的,这是我的问题:

我有一个HomeController,其中包含一个操作,比如index,它将为我的网站呈现一个登录页面。该站点还有许多其他控制器,用于实现各种其他功能的操作。

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

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

类似地,HomeController#index 会尝试在每个其他控制器上调用get_link,直到它收集到链接对象的Array,然后可以将其传递给视图以呈现导航。

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

【问题讨论】:

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


    【解决方案1】:

    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请求。

    这样的情况你解决了吗:

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

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

    【讨论】:

    • 作为来自 WP 的人,我鼓励您尝试忘记您认为自己了解的有关 Web 开发的所有内容,并尝试以全新的眼光来接触 Rails。 WP 和 Drupal 都有一些非常糟糕的设计决策(尤其是 WP),并且在以正确的方式开发 MVC 应用程序方面几乎没有共同之处。
    • 实际上,我正在尝试构建插件功能,其中每个插件都可以拥有自己的控制器,并且它应该能够通过提供一组链接/路由来为通用导航做出贡献。
    • 对了,你提到的 Drupal 和 WP 设计的问题,是因为你认为它们的可扩展性不高吗?
    • WP 是一个全面的灾难。它基本上是围绕全球一切构建的,并且是自下而上的垃圾大杂烩。但它可以完成工作。 wordpress 的大多数“缩放”问题是它有一个糟糕的自制 ORM,并且你有 SQL 查询从任何地方被触发。如果一开始就有好的设计,Drupal 就不必在每个主要版本中都变得完全不兼容。
    【解决方案2】:

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

    Rails.application.eager_load!
    

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

    controllers = ApplicationController.descendants
    

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

    controllers[0].get_link
    

    请注意,这些方法应该像这样声明为类方法:

    def self.get_link
    end
    

    这可能会降低您的应用程序的速度,因为它会急切地加载所有内容。总的来说,在我看来这不是一个好主意,因为您的应用程序中的控制器几乎是静态的。考虑使用路径助手,例如 contact_path。详情请查看Rails Routing Docs

    【讨论】:

    • 嗯,不知道你可以这样得到后代。我一直认为只有子类应该知道他们的父类是什么:) 无论如何我都会检查一下,谢谢!
    • 是的,这个方法是 Rails 的一部分。如果你想在 vanilla Ruby 中做同样的事情,请查看这个答案:stackoverflow.com/questions/2393697/… 同样,除非你绝对必须这样做,否则使用它可能不是最好的主意:-)
    猜你喜欢
    • 2023-04-09
    • 1970-01-01
    • 2022-08-15
    • 1970-01-01
    • 2013-04-18
    • 2011-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多