红宝石上用于设定默认值类和允许在子类的重写的Rails图案
-
21-08-2019 - |
题
基本上我想实现一个简单的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
上述这三种方法都在不同的目的,只是为了告诉你什么是我试过。第三个工作,但不管我考什么控制器返回相同的结果。可能是因为类变量被存储在应用控制器,以便在全球范围内发生变化。
任何帮助,将不胜感激。
解决方案
问题是,你的类变量是继承的,而是指向Array
的同一个实例。如果你更新一个,它也将上继承了Array
所有类更新。
ActiveSupport
提供href="http://github.com/rails/rails/blob/0d3c5f0a822cd1b6029b5f619774b7794a94f370/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb" rel="nofollow noreferrer">溶液通过与几种方法延伸的Class
类来定义这个问题的可继承类属性。它们被用来无处不在内部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]
其他提示
我把它变成一个插件,像这样:
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!你想上哪儿就生效super_controller是卓有成效的。