2009-07-02 64 views
1

基本上我想实现一个简单的Rails扩展来定义控制器中方法的严重性,以便我可以适当地限制它们的使用。比如我定义默认行为宁静作为这样的一个抽象超:Ruby on Rails模式用于设置类默认值并允许覆盖子类

view_methods :index, :show 
edit_methods :new, :create, :edit, :update 
destroy_methods :destroy 

我然后在非抽象控制器调用了下来:

edit_methods :sort 

在排序方法中添加在特定的控制器上作为编辑级别的方法。

然后,我可以使用before_filter来检查当前正在执行的操作的级别,如果我的逻辑确定当前用户无法执行操作,则中止它。

问题是,我在设置这种结构时遇到了问题。我试过这样的东西到目前为止:

class ApplicationController 

    @@view_methods = Array.new 
    @@edit_methods = Array.new 
    @@destroy_methods = Array.new 

    def self.view_methods(*view_methods) 
    class_variable_set(:@@view_methods, class_variable_get(:@@view_methods) << view_methods.to_a) 
    end 

    def self.edit_methods(*edit_methods) 
    class_variable_set(:@@edit_methods, self.class_variable_get(:@@edit_methods) << edit_methods.to_a) 
    end 

    def self.destroy_methods(*destroy_methods) 
    @@destroy_methods << destroy_methods.to_a 
    end 

    def self.testing 
    return @@edit_methods 
    end 


    view_methods :index, :show 
    edit_methods :new, :create, :edit, :update 
    destroy_methods :destroy 

end 

以上三种方法是有目的的不同,只是为了向你展示我试过的东西。第三个工作,但无论我测试什么控制器,都会返回相同的结果。可能是因为类变量存储在应用程序控制器中,因此全局更改。

任何帮助将不胜感激。

回答

3

问题是您的类变量是继承的,但指向Array的同一个实例。如果更新一个,它也将在所有继承Array的类上更新。

ActiveSupport通过扩展Class类的几种方法提供了solution这个问题定义可继承类属性。它们在Rails的内部使用。举例:

class ApplicationController 
    class_inheritable_array :view_method_list 
    self.view_method_list = [] 

    def self.view_methods(*view_methods) 
    self.view_method_list = view_methods # view_methods are added 
    end 

    view_methods :index, :show 
end 

现在您可以在ApplicationController中设置默认值,并在以后覆盖它们。

class MyController < ApplicationController 
    view_method :my_method 
end 

ApplicationController.view_method_list #=> [:index, :show] 
MyController.view_method_list #=> [:index, :show, :my_method] 

可以甚至使用view_method_list作为在控制器上(例如MyController.new.view_method_list)一个实例方法。

在你的榜样,你没有定义的方式来删除列表的方法,但这个想法是做类似如下(如果你需要它):

# given the code above... 
class MyController 
    self.view_method_list.delete :show 
end 
MyController.view_method_list #=> [:index, :my_method] 
+0

哇!这正是我所期待的。非常感谢你提供这些信息。我希望这也可以帮助其他人。这是一个困难的搜索,所以我很高兴你回答它:) – 2009-07-02 09:53:19

0

我把它变成一个像这样的插件:

module ThreatLevel 

    def self.included(base) 
    base.send :extend, ClassMethods 
    end 

    module ClassMethods 
    def roger_that! 
     class_inheritable_array :view_method_list, :edit_method_list, :destroy_method_list 

     self.view_method_list = Array.new 
     self.edit_method_list = Array.new 
     self.destroy_method_list = Array.new 

     def self.view_methods(*view_methods) 
     self.view_method_list = view_methods 
     end 

     def self.edit_methods(*edit_methods) 
     self.edit_method_list = edit_methods 
     end 

     def self.destroy_methods(*destroy_methods) 
     self.destroy_method_list = destroy_methods 
     end 

     view_methods :index, :show 
     edit_methods :new, :create, :edit, :update 
     destroy_methods :destroy 
    end 
    end 
end 

ActionController::Base.send :include, ThreatLevel 

调用roger_that!在超级控制器上你想让它生效就可以了。