2010-10-22 75 views
0

我正在使用Rails 2.3.2,但我相信這也適用於較新的版本。我想在ApplicationController中定義一個自定義操作。但是,我不想將自定義路由添加到使用此操作的每個控制器子類。是否有捷徑可尋?從Rails的ApplicationController繼承和路由自定義操作

我的第一個想法是直接路由到ApplicationController,因爲該方法不需要被任何子類覆蓋。但我不認爲Rails允許你再次路由到ApplicationController。

某些別有用心的人提出這樣的:

map.connect ":controller/:action", :controller => my_regex, :action => my_regex 

但我不知道是否該有或覆蓋其他路線相互衝突的潛力?或者如果通常有更好的方法?謝謝!

回答

0

最後我決定考慮我自己的js_form_builder資源,所以我有一個控制器來傳遞它。控制器採用可選的resource_name和id參數。如果提供,可以實例化,像這樣的對象:

@object = params[:resource_name].classify.constantize.find(params[:id]) 

然後,我只是發下來有載內的所有我js_form_builder善良一個js.erb模板。如果@object已被實例化,那麼我可以創建一個form_for @object,然後遍歷它的屬性並在javascript表單構建器對象上創建方法,該方法將使用Rails FormBuilder標記創建它們,從而爲每個屬性返回輸入。

例如:

window.FormBuilder = function() { 
    var builder = {}; 

    builder.form = function() { 
    var js = ""; 
    js += '<%= form_for @object do |f| %>'; 
    <% @object.attributes.each do |name, val| %> 
     var methodName = '<%= name.camelize(:lower) %>'; 
     <% if val.class == String %> 
     builder[methodName] = $('<%= f.text_field name.to_sym %>'); 
     <% end %> 
     <% if val.class == TrueClass || val.class == FalseClass %> 
     builder[methodName] = $('<%= f.check_box name.to_sym %> <%= f.label name.to_sym %>'); 
     <% end %>  
    <% end %> 
    js += '<% end %>'; 
    return $(js); 
    }; 

    builder.newForm = function() { 
    var js = ""; 
    js += '<%= form_for @object.class.new do |f| %>'; 
    js += '<% end %>'; 
    } 

    return builder; 
} 

我不能肯定目前這些投入將多麼有用,因爲我不認爲這樣一個場景,我不會只使用html.erb這些的。但它確實很有趣,使其工作! :)

0

我不認爲這是修改ApplicationController的情況,而是修改ActionDispatch::Routing中的代碼以包含您想要的新操作。這似乎是一件非常瘋狂的事情,因爲沒有標準的方法來增強或擴展通常的REST動作。我希望你有這樣做的好理由。

在查看代碼時,您可以看到默認操作的定義位置,並且您可能會引入一個新的操作。 Rails 3中有一個稍微不同的結構,但這個想法是一樣的:

class ActionDispatch::Routing::Mapper::Resources::Resource 
     ENHANCED_DEFAULT_ACTIONS = DEFAULT_ACTIONS + [ :myaction ] 

     def self.default_actions 
     ENHANCED_DEFAULT_ACTIONS 
     end 
    end 

你必須修改ActionDispatch::Routing::Mapper::Resources#resources表現不同,太多,但你沒有指定,如果你在談論的集合,新或成員類型的操作,因此您只需複製和修改例程以按照您的要求操作即可。

+0

我這樣做的原因是因爲我想我的application.js能夠吐出Rails窗體標籤。我的應用程序在AJAX和js中很繁重,我想要集中的方法,它們給了我Rails窗體,輸入等。基本上,我試圖創建一個JavaScript FormBuilder。 因此,在我的application.js中,我會對我的自定義操作進行AJAX調用,該操作會發送一個js.erb文件。這個文件會有一個FormBuilder「class」,其中的方法給了我由rails表單生成器標記生成的html。所以當我的application.js調用deleteWithAjax()時,我可以用Rails標籤生成Rails表單。 – Samo 2010-10-22 15:53:38

+0

這聽起來像一個非常有趣的想法,它可以很好地工作,但問題是爲什麼它需要從標準REST操作中分離出這麼多。您真正需要的是爲您的方法定義JavaScript響應器,以便正確處理表單。如果沒有找到模板,則可以通過截取並自動處理.js響應的生成,而不是通過引入新操作來更輕鬆地完成此操作。 – tadman 2010-10-22 16:25:46

+0

這是一個有趣的想法。你能否指點我一個這樣的例子?到目前爲止,在所有情況下,我對ajax調用的響應是js.erb模板或json對象。我希望返回的js.erb模板和json響應的處理程序都可以訪問我的js表單構建器。所以沒有模板發現的情況可能是不夠的。也許另一種選擇是將js_form_builder作爲只響應get的資源,並且我的application.js文件可以調用該控制器來加載表單構建器。 – Samo 2010-10-22 17:51:30

0

如果您將此控制器聲明爲諸如map.resource之類的資源,那麼您將必須使用默認操作或通過向該資源添加membercollection來創建您自己的控件。

map.resources :post, :member => {:update_live_boolean => :post }, :collection => {:get_all_live_posts => :get} 

否則,如果你有舊的路由格式,並沒有使用REST

map.connect ':controller/:action/:id' 
    map.connect ':controller/:action/:id.:format' 

然後,所有你需要做的鏈接到一個定製的控制器提供:controller' and:動作/:id`變量需要

<%= link_to "New Custom Controller", {:controller => "new_custom_controller", :action => "index"%> 
0

時,這是我關心你的文章的一部分:

我不想添加一個自定義路由到 每個控制器子類,其中 使用此操作。

對於不過度定義不必要的路線,rails社區正在越來越小心。它變得更經常可以看到這樣的事情:

map.resources :comments, :only => [:new, :create] 

在上面的例子中,只產生newcreate路線。這是更好的安全性和更簡潔的路由。雖然我沒有直接回答你如何爲每種資源提供新路線的問題,但我認爲鐵路最佳實踐會阻止它。只將自定義路由添加到實際使用它的資源。

+0

我理解您的關注,但如果我希望每個控制器使用這個自定義動作,那麼爲每個控制器顯式路由它似乎相當多餘,不是嗎? – Samo 2010-10-22 15:55:52

+0

老實說,我不這麼認爲。因爲我無法想象一個真實世界的應用程序,每個*資源都需要它。而且,應用程序中的路線數量有限,通常只有幾十個。相信我,我真的明白你希望保持代碼乾爽 - 我也是這樣。除非我對此感到強烈,否則我不會回答「無答案」。我確實懂得詢問某事的煩惱,並讓人們說「不要這樣做」:) – 2010-10-22 16:32:45