2010-10-22 44 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