【问题标题】:How to organize controller in moderately large Rails application?如何在中型 Rails 应用程序中组织控制器?
【发布时间】:2011-03-14 14:03:38
【问题描述】:

我正在开发一个包含很多相关模型的应用程序,并且想听听一些关于如何最好地组织控制器的意见。

以下是我一直在考虑的一些选项:

1) 命名空间控制器。因此,例如,有一个 controllers/admin 目录和一个 controllers/public 目录。这似乎对组织很有吸引力,但也有点做作,因为单个资源通常可能具有明显属于不同目录的操作(例如,显示操作是公共的,而创建操作是管理员的)。所以这意味着将我的一些资源分成两个独立的控制器——一个公共的,一个管理员的。看起来很糟糕。

2) 创建嵌套资源。我只是偶尔使用嵌套资源,因此我并不总是清楚何时最好嵌套资源而不是简单地通过参数明确传递所需的数据。有人对如何最好地使用嵌套资源有一些建议/示例吗?什么时候是个好主意?什么时候是大材小用?

3) 只保留默认的脚手架控制器。在需要的地方创建新的集合/成员操作,并使用 before 过滤器在每个控制器中设置权限。这似乎最吸引人,因为它使事情变得简单。但我有点担心事情会变得一团糟,因为一些控制器可能会因为几个新动作而开始膨胀。

如果有设计大型应用程序经验的人可以在这里提供一些指导,我们将不胜感激。

【问题讨论】:

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


    【解决方案1】:

    此外,看起来嵌套超过一层的资源几乎肯定是个坏主意:

    http://weblog.jamisbuck.org/2007/2/5/nesting-resources

    是的,这是一篇旧文章,但对我来说很有意义。

    如果有人不同意,我想听听为什么。

    【讨论】:

      【解决方案2】:

      为了在我们的应用程序中进行组织,我根据情况做了一些工作。

      首先,关于管理员/用户功能的单独控制器,我会说您可能不想走那条路。我们使用授权和before_filter 来管理应用程序中的权限。我们推出了自己的产品,但事后看来,我们应该使用CanCan。从那里你可以设置这样的东西(这是伪代码,实际语言取决于你如何实现授权):

      before_filter :can_edit_user, :only => [:new, :create, :edit, :update] #or :except => [:index, :show]
      
      protected
      
      def can_edit_user
        redirect_to never_never_land_path unless current_user.has_rights?('edit_user')
      end
      

      或者更高的层次

      before_filter :require_admin, :only [:new, :create]
      

      在你的应用控制器中

      def require_admin
        redirect_to never_never_land_path unless current_user.administrator?
      end
      

      这取决于哪个路由,但我会使用它来授权而不是拆分控制器。

      就名称空间与嵌套资源而言,这取决于具体情况。在我们的几个应用程序中,我们都有。当存在逻辑分离的原因或一组控制器之间将共享功能时,我们使用名称空间。对我们来说,案例和要点是我们将管理功能放在命名空间中,并且在其中我们有用户、角色和其他专有管理功能。

      map.namespace :admin do |admin|
        admin.resources :users
        admin.resources :roles
      end
      

      然后在这些控制器中,我们有一个基本控制器,用于存储我们的共享功能。

      class Admin::Base < ApplicationController
        before_filter :require_admin
      end
      
      class Admin::UsersController < Admin::Base
        def new
         ....
      end
      

      这为我们提供了数据的逻辑分离,并能够通过共享 before_filter 之类的内容来稍微干掉我们的代码。

      如果有一段代码您希望在控制器之间保留一些东西,我们会使用嵌套控制器。我们应用的案例是我们的客户。我们搜索并加载客户,然后在该客户中,他们有订单、票、位置。在该区域内,我们在查看不同选项卡时加载了客户。

      map.resources :customers do |customer|
        customer.resources :tickets
        customer.resources :orders
        customer.resources :locations
      end
      

      这给了我们网址:

      customers/:id
      customers/:customer_id/orders/:id
      customers/:customer_id/tickets/:id
      

      我们从中体验到的其他优势是易于设置菜单系统和选项卡。这些结构非常适合有组织的网站。

      我希望这会有所帮助!

      【讨论】:

      • 太棒了。这正是我所需要的。我特别喜欢使用命名空间并从基本控制器继承的想法。另外,我没有考虑过使用 CanCan,但我肯定会检查一下。谢谢!
      猜你喜欢
      • 2012-02-05
      • 2011-05-19
      • 1970-01-01
      • 2012-11-15
      • 2012-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多