Ruby Mixins in Verbindung und Aufruf von super Methoden
-
08-06-2019 - |
Frage
Ok, also habe ich die Umgestaltung mein code in meiner kleinen Rails-app in einem Versuch zu entfernen, Vervielfältigung, und im Allgemeinen machen mein Leben leichter (als ich wie ein leichtes Leben).Teil dieser Umgestaltung wurde zum verschieben von code, die ist üblich, zwei meiner Modelle zu einem Modul, das kann ich zählen, wo ich Sie brauche.
So weit, So gut.Sieht aus wie es funktionieren wird, aber ich habe gerade ein problem, dass ich nicht sicher bin, wie man das umgehen kann.Das Modul (die ich genannt habe verschickbar), ist nur der code, der Griffe, Faxen, e-mailen oder drucken einer PDF-Datei des Dokuments.So, ich habe zum Beispiel eine Bestellung, und ich habe die Interne Aufträge (phantasievoll abgekürzt ISO).
Das problem, das ich habe, aufgefallen ist, ist, dass ich möchte einige Variablen initialisiert (initialisiert für Leute, die nicht buchstabieren richtig :P ), nachdem das Objekt geladen wurde, also habe ich mit der after_initialize Haken.Kein problem...bis ich starten Sie das hinzufügen einiger mehr Mixins in Verbindung.
Das problem, das ich habe, ist, dass ich eine after_initialize
in einem meiner Mixins in Verbindung, so dass ich brauchen, um ein super rufen Sie beim start, stellen Sie sicher, dass das andere mixin after_initialize
Anrufe aufgerufen.Das ist toll, bis ich am Ende dem Aufruf von super und ich bekomme einen Fehler, weil es ist keine super zu rufen.
Hier ein kleines Beispiel, im Fall ich noch nicht verwirrend genug:
class Iso < ActiveRecord::Base
include Shared::TracksSerialNumberExtension
include Shared::OrderLines
extend Shared::Filtered
include Sendable::Model
validates_presence_of :customer
validates_associated :lines
owned_by :customer
order_lines :despatched # Mixin
tracks_serial_numbers :items # Mixin
sendable :customer # Mixin
attr_accessor :address
def initialize( params = nil )
super
self.created_at ||= Time.now.to_date
end
end
Also, wenn jeder der Mixins in Verbindung eine after_initialize nennen, mit einem super aufrufen, wie kann ich verhindern, dass last super rufen Sie aus, das den Fehler?Wie kann ich testen, dass die super-Methode vorhanden ist, bevor ich es nennen?
Lösung
Sie können dies verwenden:
super if defined?(super)
Hier ist ein Beispiel:
class A
end
class B < A
def t
super if defined?(super)
puts "Hi from B"
end
end
B.new.t
Andere Tipps
Haben Sie versucht, alias_method_chain
?Grundsätzlich können Sie alle Ihre angekettet after_initialize
Anrufe.Es wirkt wie ein Dekorateur:jede neue Methode fügt eine neue Ebene von Funktion und übergibt die Kontrolle an die "außer Kraft gesetzt" - Methode, um den rest zu tun.
Die inklusive Klasse (die Sache, die erbt von ActiveRecord::Base
, die in diesem Fall ist Iso
) könnte definieren Sie Ihre eigenen after_initialize
, so dass jede andere Lösung als alias_method_chain
(oder andere aliasing-Effekt, spart das original) Risiken überschreiben code.@Orion Edwards' Lösung ist die beste, die ich mit oben kommen kann.Es gibt andere, aber Sie sind weit mehr hackish.
alias_method_chain
hat auch den Vorteil, erstellen genannten Versionen der after_initialize-Methode, das heißt, Sie können die Anruf, um in den seltenen Fällen, dass es darauf ankommt.Andernfalls bist du auf Gedeih und Verderb, was auch immer, um die inklusive Klasse umfasst die Mixins in Verbindung.
später:
Ich habe eine Frage zu dem ruby-on-rails-core-mailing-Liste, über die Erstellung von Standard -, leer-Implementierungen aller Rückrufe.Der Speichervorgang überprüft für Sie sowieso alle, also ich sehe nicht ein, warum Sie nicht da sein sollte.Der einzige Nachteil ist die Schaffung von zusätzlichen leeren stack-frames, aber das ist ziemlich Billig auf jede bekannte Umsetzung.
Sie können nur werfen eine schnelle bedingte es:
super if respond_to?('super')
und Sie sollten in Ordnung sein - kein hinzufügen von nutzlosen Methoden;schön und sauber.
Anstatt zu überprüfen, ob die super-Methode vorhanden ist, können Sie einfach definieren, es
class ActiveRecord::Base
def after_initialize
end
end
Dies funktioniert in meinen Tests, und sollte nicht Pause Ihre vorhandenen code, da alle anderen Klassen, die definieren, es wird einfach automatisch überschreiben dieser Methode sowieso