【问题标题】:Rails: sharing a controller across two modelsRails:在两个模型之间共享一个控制器
【发布时间】:2015-09-30 09:14:53
【问题描述】:

我有两个模型:

学生 教室

它们都有一个完全相同的操作:它显示每日活动报告。那就是:

/students/1
/classrooms/1

获取相关模型的活动并将其显示在页面上。

为了解决这个问题,我创建了一个ReportsController,它提取了构建报告的所有常见逻辑。

如果我这样离开路线:

/students/1/report
/classrooms/1/report

然后我可以让ReportsController#show 操作为:student_id:classroom_id 查找params 以确定它正在处理的模型类型(用于查询数据库并呈现正确的视图)。

但我希望 URL 更简洁,因此我还更改了我的 routes.rb 文件以将这些模型的 show 操作传递给 reports#show 控制器操作:

resources :students, :classrooms do
  member do
    get :show, to: 'reports#show'
  end
end

这可行,但我不能再依赖params 来确定要使用哪个模型以及要渲染哪个视图。

问题:我应该为模型解析 request.fullpath 吗?或者有没有更好的方法让共享控制器了解它正在使用的模型?

【问题讨论】:

  • 你不能把所有的逻辑都移到模型中并保留 2 个非常简单的控制器动作来调用模型中的方法吗?
  • @abm 我如何避免在学生和教室模型中放置重复的逻辑?逻辑完全一样:他们在 events 表中查询 class_id = foo 或 student_id = bar 的事件。
  • 如果您查询的是events 表,那么您的逻辑应该放在Event 模型中。
  • @abm 对我来说说教室.events 与 events.where(classroom_id: 5) 更有意义

标签: ruby-on-rails controller routing


【解决方案1】:

我会将通用逻辑放在Event 模型中:

#Event Model
class Event < ...
      def self.your_event_method
         #self here will be either student.events or classroom.events 
         #depending on which controller called it
      end
end

class StudentsController < ...
  ...

  def show
    student = Student.find(params[:id])
    student.events.your_event_method
  end

end

class ClassroomsController < ...
  ...

  def show
    classroom = Classroom(params[:id])
    classroom.events.your_event_method
  end

end

【讨论】:

    【解决方案2】:

    将两个 show 方法路由到同一个控制器方法以进行代码重用有点像用翻斗车敲钉子。

    即使您可以通过查看请求 url 找到资源,您也会开始将 ResortsController 拆分为一堆 if 和 switch,甚至在您开始之前。

    一种解决方案是在模块中添加通用操作:

    module Reporting
      extend ActiveSupport::Concern
    
      def show
        # the Student or Classroom should be available as @resource
        render 'reports/show'
      end
    
      included do
        before_action :find_resource, only: [:show]
      end
    
      private
    
      def find_resource
        model = self.try(:resource_class) || guess_resource_class
        @resource = model.find(params[:id])
      end
    
      # This guesses the name of the resource based on the controller name.
      def guess_resource_class
        self.class.name[0..-11].singularize.constantize
      end
    end
    

    class StudentController < ApplicationController
      include Reporting
    end
    
    # Example where resource name cannot be deduced from controller
    class PupilController < ApplicationController
      include Reporting
      private
      def resource_class
        Student
      end
    end
    

    self.class.name[0..-11].singularize.constantize 基本上是 Rails 使用约定优于配置在用户控制器中自动加载User 的方式,即使没有任何代码。

    但是,DRY 控制器最重要的关键是让控制器保持纤细。大多数功能可以移动到模型层或委托给服务对象。

    【讨论】:

    • action 是用于控制器方法的 Rails 习惯用法。模型没有动作——控制器有。模型有方法。
    猜你喜欢
    • 2016-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-22
    相关资源
    最近更新 更多