2015-07-11 78 views
-1

共享控制器我有兩個型號:Rails的:在兩個模型

學生 課堂

他們兩人有確實的同樣的事情一個動作:它顯示日常活動的報告。即:

/students/1 
/classrooms/1 

爲相關模型抓取活動並將其顯示在頁面上。

爲了解決這個問題,我創建了一個ReportsController,它提取了構建報告的所有常見邏輯。

如果我離開的路線是這樣的:

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

這樣我就可以有ReportsController#show行動查找params:student_id:classroom_id,以確定哪些模型類型它在處理(用於查詢數據庫的目的,渲染正確的視圖)。

但我寧願網址,更清潔,所以我也改變了我的routes.rb文件傳遞show行動爲這些車型的reports#show控制器動作:

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

這工作,但我可以不再取決於params來確定要使用哪個模型以及要呈現哪個視圖。

問題:我應該爲模型解析request.fullpath嗎?或者是否有更好的方法讓共享控制器瞭解它正在使用的模型?

+1

你不能把所有的邏輯模型,並保持2只是調用模型方法非常簡單的控制器操作? – AbM

+0

@abm我該如何避免在學生和教室模型中添加重複的邏輯?邏輯完全相同:他們使用classroom_id = foo或student_id = bar查詢事件表中的事件。 –

+0

如果您正在查詢'events'表,那麼您的邏輯應該放在'Event'模型中。 – AbM

回答

0

將兩個show方法都路由到相同的控制器方法以重用代碼有點像用dumptruck敲擊一樣。

即使您可以通過查看請求url來查找資源,您甚至可以在您離開地面之前將ResortsController分割爲一堆ifs和開關。

一種解決方案是增加共同作用的模塊中:

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的是如何使用約定優於配置在你的UsersController自動加載User即使沒有任何代碼。

但DRY控制器的最重要的關鍵是保持你的控制器瘦。大多數功能可以移入模型層或委託給服務對象。

+0

action是一個控制器方法的Rails成語。模型沒有行動 - 控制器。模型有方法。 – max

0

我把常見的邏輯在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