2017-06-06 57 views
0

我有兩個控制器在導軌上有不同的認證方案, 但它們幾乎完全相同。在導軌中封裝控制器邏輯

什麼是最好的方式在軌道封裝 控制器的邏輯在另一個類或助手?

樣品:

def ControllerA < BasicAuthController  
    def create 
    blablacode 
    end 
end 

def ControllerB < TokenAuthController 
    def create 
    blablacode 
    end 
end 

請告訴我正確的方式做到這一點?用代碼創建一個模型? 創建一個幫手?其他?

+0

嗯軌道的方法是定義在相應的輔助文件夾中找到的輔助方法,反正你實際上可以使一個類或模塊代表了你想做的事,如果你去的模塊路徑,你可以在它混控制器 – niceman

+3

這是一個廣泛的問題。這取決於。幫手方法?模塊?遺產?依賴注入?抽象邏輯變成寶石? ...你至少可以展示*你想要清理的代碼是什麼? –

回答

0

簡短的回答,我選擇創建一個助手

從在回答所有建議

  • 創建模塊: 似乎是正確的,但它並沒有覺得不對勁有外 的app邏輯目錄。這不是一個外部模塊或庫,但 東西與我的應用程序的邏輯非常相關。

  • 在一個控制器集成diferents認證: 是一個很好的建議,但我不得不改變我的應用程序的所有邏輯。

  • 創建一個幫手: 在我看來,更好的解決方案,我有一個助手的代碼, 是應用程序目錄中,非常接近從另一個邏輯。

0

我做這樣的事情:

#app/services/my_app/services/authentication.rb 
class MyApp::Services::Authentication 

    class < self 

    def call(params={}) 
     new(params).call 
    end 

    end # Class Methods 

    #============================================================================================== 
    # Instance Methods 
    #============================================================================================== 

    def initialize(params) 
     @params = params 
    end 

    def call 
     ... do a lot of clever stuff 
     ... end by returning true or false 
    end 

    private 

    def params() @params end 

end 

然後:

class FooController < ApplicationController 
    before_action :authenticate 

    def authenticate 
    redirect_to 'some_path' unless MyApp::Services::Authenticate.call(with: 'some_params') 
    end 

end 
+0

'app/services/my_app/services' ?? !! –

+0

是的。我已經看到了一些關於這樣的事情的討論。我不介意愚蠢的目錄結構。我喜歡(我認爲)是MyApp :: Services :: Authentication'命名空間的清晰度。 (可能是因爲我在一堆應用程序中使用了大量的東西,而且我喜歡過多的命名空間的安全帶和吊帶安全性。)但是,我認識到有些人對我們的目錄結構比我更挑剔。給每個人自己。 – jvillian

0

你爲什麼不啓用單一控制器兩種方案?特別是如果唯一的區別是認證。您可以使用兩個app/controllers/concerns來封裝兩種身份驗證方法,而對於只管理其管理的任何資源的單個控制器,可以使用include Auth1和​​。

否則,服務是封裝控制器邏輯的最佳方法。

在您的app文件夾中創建一個名爲services的文件夾並在此處編寫PORO類。假設你在你的應用中有幾個地方你想通過使Stripe支付東西。

# app/services/stripe_service.rb 
module StripeService 
    def customer(args) 
    ... 
    end 

    def pay(amount, customer) 
    ... 
    end 

    def reverse(stripe_txn_id) 
    ... 
    end 
end 
# controller 
StripeService.customer(data) 
=> <#Stripe::Customer> 

或者如果你只需要做一件事。

# app/services/some_thing.rb 
module SomeThing 
    def call 
    # do stuff 
    end 
end 
# controller 
SomeThing.call 
=> # w/e 

如果您需要一個具有多個職責的對象,您可以創建一個類。

class ReportingService 
    def initialize(args) 
    ... 
    end 

    def query 
    ... 
    end 

    def data 
    ... 
    end 

    def to_json 
    ... 
    end 
end 

https://blog.engineyard.com/2014/keeping-your-rails-controllers-dry-with-services

+0

除非我錯了,否則這些方法將成爲實例方法。在這種情況下,您需要執行類似「SomeThing.new.call」的操作。或者可能不是? – jvillian

+0

你是對的,我的壞! – fbelanger

0

最簡單的事情就是讓一個模塊,然後include入其它控制器:

module ControllerMixin 
    def create 
    blablacode 
    end 
end 

剩下的問題,不過,在這裏把這個代碼,這樣它適用於Rails自動加載器,因爲它需要在控制器之前加載。這樣做將是對模塊寫在lib/目錄中的文件,然後添加到自動加載路徑的一種方式(見auto-loading-lib-files-in-rails-4