Ruby on Rails motif pour le réglage par défaut de la classe et en permettant un remplacement sur les sous-classes
-
21-08-2019 - |
Question
En fait, je veux mettre en œuvre une simple extension Rails pour définir la gravité des méthodes dans mon contrôleur afin que je puisse restreindre l'utilisation d'entre eux de façon appropriée. Par exemple, je voudrais définir les actions reposant par défaut comme si dans un résumé superclasse:
view_methods :index, :show
edit_methods :new, :create, :edit, :update
destroy_methods :destroy
Je puis dans un appel de commande non abstraite:
edit_methods :sort
pour ajouter dans la méthode de tri sur ce contrôleur particulier comme étant une méthode de niveau d'édition.
Je pourrais alors utiliser un before_filter pour vérifier le niveau de l'action actuellement en cours d'exécution, et l'annuler si ma logique détermine que l'utilisateur actuel ne peut pas le faire.
Le problème est, je vais avoir du mal à travailler sur la façon de mettre en place ce genre de structure. J'ai essayé quelque chose comme ça jusqu'à présent:
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
Les trois méthodes ci-dessus sont différentes sur le but, juste pour vous montrer ce que je l'ai essayé. La troisième marche, mais renvoie les mêmes résultats, peu importe ce que je commande test. Probablement parce que les variables de classe sont stockées dans le contrôleur d'application sont donc changé dans le monde.
Toute aide serait grandement appréciée.
La solution
Le problème est que vos variables de classe sont héritées, mais pointent vers la même instance de Array
. Si vous mettez à jour un, il sera également mis à jour sur toutes les classes qui ont hérité du ActiveSupport
.
Class
solution à ce problème en étendant la classe avec plusieurs méthodes ApplicationController
pour définir attributs de classe héritable . Ils sont utilisés partout en interne dans Rails. Un exemple:
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
Maintenant, vous pouvez définir des valeurs par défaut dans les remplacer et view_method_list
plus tard.
class MyController < ApplicationController
view_method :my_method
end
ApplicationController.view_method_list #=> [:index, :show]
MyController.view_method_list #=> [:index, :show, :my_method]
On peut même utiliser la MyController.new.view_method_list
comme méthode instance sur les contrôleurs (par exemple, <=>).
Dans votre exemple, vous n'avez pas défini un moyen de supprimer des méthodes des listes, mais l'idée est de faire quelque chose comme ce qui suit (en cas de besoin):
# given the code above...
class MyController
self.view_method_list.delete :show
end
MyController.view_method_list #=> [:index, :my_method]
Autres conseils
Je me suis tourné dans un plugin comme ceci:
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
Appel roger_that! sur le super_controller où vous voulez qu'elle prenne effet le tour est joué.