Patrón Ruby on Rails para establecer valores predeterminados de clase y permitir una anulación de subclases
-
21-08-2019 - |
Pregunta
Básicamente, quiero implementar una extensión Rails simple para definir la seriedad de los métodos en mi controlador para poder restringir su uso de manera adecuada.Por ejemplo, definiría las acciones de descanso predeterminadas así en una superclase abstracta:
view_methods :index, :show
edit_methods :new, :create, :edit, :update
destroy_methods :destroy
Luego hice una llamada de controlador no abstracta:
edit_methods :sort
para agregar el método de clasificación en ese controlador en particular como un método de nivel de edición.
Luego podría usar before_filter para verificar el nivel de la acción que se está realizando actualmente y cancelarla si mi lógica determina que el usuario actual no puede hacerlo.
El problema es que tengo problemas para saber cómo configurar este tipo de estructura.He probado algo como esto hasta ahora:
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
Los tres métodos anteriores son diferentes a propósito, sólo para mostrarte lo que he probado.El tercero funciona, pero arroja los mismos resultados sin importar qué controlador pruebe.Probablemente porque las variables de clase se almacenan en el controlador de la aplicación y se cambian globalmente.
Cualquier ayuda sería muy apreciada.
Solución
El problema es que las variables de tu clase se heredan, pero apuntan a la misma instancia de Array
.Si actualiza uno, también se actualizará en todas las clases que heredaron el Array
.
ActiveSupport
ofrece una solución a este problema ampliando el Class
clase con varios métodos para definir atributos de clase heredables.Se utilizan en todas partes internamente en Rails.Un ejemplo:
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
Ahora puedes establecer valores predeterminados en ApplicationController
y anularlos más tarde.
class MyController < ApplicationController
view_method :my_method
end
ApplicationController.view_method_list #=> [:index, :show]
MyController.view_method_list #=> [:index, :show, :my_method]
Incluso puedes usar el view_method_list
como un instancia método en los controladores (p. ej. MyController.new.view_method_list
).
En tu ejemplo no definiste una forma de eliminar métodos de las listas, pero la idea es hacer algo como lo siguiente (en caso de que lo necesites):
# given the code above...
class MyController
self.view_method_list.delete :show
end
MyController.view_method_list #=> [:index, :my_method]
Otros consejos
Me di vuelta en un plugin de este modo:
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
Llamando roger_that! en el super_controller en la que desea que entre en vigor hace el truco.