Ruby on Rails Muster für Klasse Standardwerte einstellen und damit eine Überschreibung auf Subklassen
-
21-08-2019 - |
Frage
Grundsätzlich mag ich eine einfache Rails-Erweiterung implementieren, um die Schwere der Methoden in meinem Controller zu definieren, so dass ich den Gebrauch von ihnen in geeigneter Weise einschränken. Zum Beispiel würde ich die Standard geruhsamen Aktionen wie so in einer abstrakten Superklasse definieren:
view_methods :index, :show
edit_methods :new, :create, :edit, :update
destroy_methods :destroy
Ich würde dann nach unten in einem nicht-abstrakten Controller Aufruf:
edit_methods :sort
in der Sortiermethode auf diesem speziellen Controller hinzuzufügen, als eine Editlevel Methode zu sein.
Ich konnte dann eine before_filter verwenden, um die Ebene der Maßnahme überprüfen zur Zeit durchgeführt wird, und breche es, wenn meine Logik bestimmt, dass der aktuelle Benutzer kann es nicht tun.
Das Problem ist, ich habe Probleme, herauszufinden, wie diese Art von Struktur einzurichten. Ich habe so etwas wie dies versucht, so weit:
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
Die drei oben genannten Methoden sind unterschiedlich absichtlich, nur um Ihnen zu zeigen, was ich versucht habe. Der dritte funktioniert, aber liefert die gleichen Ergebnisse, egal was ich Controller testen. Wahrscheinlich, weil die Klassenvariablen in der Applikationssteuerung gespeichert sind, werden global so geändert wird.
Jede Hilfe wäre sehr geschätzt.
Lösung
Das Problem ist, dass Ihre Klassenvariablen vererbt werden, sondern auf die gleiche Instanz von Array
. Wenn Sie ein Update, wird es auch auf allen Klassen aktualisiert werden, die die Array
vererbt.
ActiveSupport
bietet eine Lösung rel="nofollow für dieses Problem, indem die Class
Klasse mit mehreren Methoden erstreckt zu definieren vererbbare Klasse Attribute . Sie werden überall intern in Rails verwendet. Ein Beispiel:
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
Jetzt können Sie die Standardwerte in ApplicationController
gesetzt und überschreiben sie später.
class MyController < ApplicationController
view_method :my_method
end
ApplicationController.view_method_list #=> [:index, :show]
MyController.view_method_list #=> [:index, :show, :my_method]
Sie können sogar die view_method_list
als Instanz Methode auf dem Controller verwenden (z MyController.new.view_method_list
).
In Ihrem Beispiel Sie nicht definierten eine Möglichkeit, Methoden aus den Listen zu entfernen, aber die Idee ist so etwas wie die folgende tun (im Fall müssen Sie es):
# given the code above...
class MyController
self.view_method_list.delete :show
end
MyController.view_method_list #=> [:index, :my_method]
Andere Tipps
Ich drehte ihn in ein Plugin wie folgt:
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
Beim roger_that! auf dem super_controller, wo Sie es wollen Effekt funktioniert der Trick nehmen.