2009-04-30 30 views
8

我希望能夠根據查詢參數和數據庫中的數據的組合,從一個控制器動作有條件地分派到另一個控制器動作。在沒有HTTP重定向的情況下從另一個控制器動作運行一個控制器動作的正確方法是什麼?

我現在所擁有的是一樣的東西:

class OldController < ApplicationController 
    def old_controller_action 
    if should_use_new_controller 
     new_params = params.dup 
     new_params[:controller] = "new_controller_action" 
     redirect_to new_params 
     return 
    end 
    # rest of old and busted 
    end 
end 

class NewController < ApplicationController 
    def new_controller_action 
    # new hotness 
    end 
end 

這工作得很好,但它發出一個HTTP重定向,這是緩慢的。我希望能夠做到這一點,但在同一個HTTP請求。

有沒有一個乾淨的方法來做到這一點?

編輯:賞金將去誰可以告訴我一個乾淨的方式來做到這一點,離開控制器和他們的行動相對不變(而不是重定向代碼本身)。

回答

13

而不是跨動作調用代碼,將代碼提取到lib /或其他東西,並從兩個控制器調用該代碼。

# lib/foo.rb 
module Foo 
    def self.bar 
    # ... 
    end 
end 

# posts_controller 
def index 
    Foo.bar 
end 

# things_controller 
def index 
    Foo.bar 
end 
+0

是啊,我已經想到了這一點爲好,儘管它不是一個非常令人興奮的選擇,從代碼組織的觀點。 – 2009-04-30 22:32:32

+1

它實際上是好的,因爲它創造從兩個地方是容易測試 – 2013-01-22 03:39:22

7

創建控制器類的一個實例:

@my_other_controller = MyOtherController.new 

然後調用它的方法:

@my_other_controller.some_method(params[:id]) 

我喜歡模塊的想法,但是這應該做的伎倆。

1

我懷疑你想要的選項3,但讓經過第一

選項1的一些替代方案 - 將控制器選擇邏輯成插入正確的鏈接到您的視圖中的幫手。 Benifits - 控制器保持清潔,缺點 - 如果決策邏輯取決於提交的值,這種方法將無法工作。如果URL被外部網站調用,那麼這將不起作用。

選項2 - 將邏輯推回到您的模型中。 Pro's - 保持控制器清潔。缺點 - 如果你有很多sesson,params或render/redirect_to交互,效果不好。

選項3 - 保持在同一個控制器中。我懷疑你正試圖用一些新功能替換一些現有的功能,但只在某些情況下。專業的 - 簡單,並有權訪問您需要的一切。缺點 - 只有在使用相同的控制器時有意義,也就是說,您正在使用同一個實體,例如用戶,地點或公司。

讓我們看一個例子供選擇3.我的鏈接控制器具有管理員比其他用戶完全diferent水煤漿...

class LinksController < ApplicationController 
    #... 

    def new 
    #Check params and db values to make a choice here 
    admin? ? new_admin : new_user 
    end 

    #... 

private 

    def new_admin 
    #All of the good stuff - can use params, flash, etc 
    render :action => 'new_admin'  
    end 

    def new_user 
    #All of the good stuff - can use params, flash, etc 
    render :action => 'new_user' 
    end 

end 
0

如果兩個控制器試圖做同樣的事情,有一個非常好的這應該是一個模型。在您的設計以一個良好的外觀和 - 對不起,我不知道用MVC你的經驗等級 - 薄控制器技術,閱讀起來:

http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model http://www.robbyonrails.com/articles/2007/06/19/put-your-controllers-on-a-diet-already http://andrzejonsoftware.blogspot.com/2008/07/mvc-how-to-write-controllers.html

如果問題是你需要另一個控制器來完成渲染,那麼也許這條路線應該在那裏開始,而且瘦身控制器技術仍然應該保存一天。

-1

這樣做:

class OldController < ApplicationController 
    def old_controller_action 
    if should_use_new_controller 
     new_controller_action 
    end 
    # rest of old and busted 
    end 
end 

和新的控制器

class NewController < OldController 
    def new_controller_action 
    # new hotness 
    end 
end 
0

如果提取控制器之間的普通代碼模塊不適合你的工作,我會用Rack中間件。我還沒有看到使用ActiveRecord中間件內的代碼,但我不知道有任何理由,因爲人們已經使用Redis和喜歡它應該是不可能的。

否則,我認爲你唯一的選擇是重新啓動的東西,如(未經測試,僞例如)請求的處理:

env['REQUEST_URI'] = new_controller_uri_with_your_params 
call(env) 

這類似於集成測試是如何實現的。但我直到你打一個控制器冪等和安全的重新運行這樣不知道,如果一切從call。你可以追蹤源代碼並查看。但即使現在沒什麼問題,它可能會在任何未來版本的導軌或機架中出現故障。

使用中間件會通過讓您攔截請求它已經運行之前避免這種情況。你應該仍然可以通過將你的Rails應用程序解壓到包含在這兩個地方的通用模塊來共享代碼。

老實說,我覺得只是做保理在公共控制器代碼的簡單的事情可能更清潔,但很難知道沒有你的情況的細節,所以我想我會繼續前進,表明這。

相關問題