Ok, he estado refacturando mi código en mi pequeña aplicación Rails en un esfuerzo por eliminar la duplicación y, en general, hacer mi vida más fácil (ya que me gusta una vida fácil). Parte de esta refactorización ha sido mover el código que es común a dos de mis modelos a un módulo que puedo incluir donde lo necesito.Ruby mixins y super métodos de llamada
Hasta ahora, todo bien. Parece que va a funcionar, pero acabo de encontrar un problema que no estoy seguro de cómo moverme. El módulo (que llamé sendable), simplemente va a ser el código que maneja el envío de faxes, el envío de correos electrónicos o la impresión de un PDF del documento. Entonces, por ejemplo, tengo una orden de compra, y tengo Órdenes de Ventas Internas (imaginativamente abreviadas a ISO).
El problema que he llamó la atención, es que quiero algunas variables inicializado (inicializar para la gente que no explican correctamente: P) después de cargar el objeto, por lo que he estado usando el gancho after_initialize. No hay problema ... hasta que empiece a agregar más mixins.
El problema que tengo, es que puedo tener un after_initialize
en cualquiera de mis mixins, por lo que deberá incluir un súper llamada al principio para asegurarse de que la otra mixin after_initialize
llamadas consiguen llamados . Lo cual es genial, hasta que termino llamando súper y me sale un error porque no hay super para llamar.
He aquí un pequeño ejemplo, en caso de que no he sido lo suficientemente confuso:
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
Por lo tanto, si cada uno de los mixins tienen una llamada after_initialize, con una super llamada , ¿cómo puedo dejar que la última llamada super ¿ha provocado la aparición del error? ¿Cómo puedo probar que el súper método existe antes de que lo llame?
downvoted porque no es una solución general. El punto es que no se sabe si el súper existe o no, por lo que monopatching ActiveRecord :: Base # after_initialize en existencia, se crea un punto donde el código se romperá si/cuando ActiveRecord agrega un Base # after_initialize, o se cambia su arity ; es mucho mejor llamarlo condicionalmente si está definido. – yaauie
@yaauie - seguro, podría haber puesto un 'raise' oh no 'if methods.include? (: After_initialize) 'antes del monopatch, pero eso haría el ejemplo más difícil de entender ... Es tan fácil quedar atrapado al detallar todos los casos extremos, la lección real aquí (solo parchear un método base) se perdería en el ruido. –
monkeypatching no es una solución general y no debería, en general, ser alentado. Una respuesta que involucra un monekypatch de una sola vez que * puede * pasar a funcionar conduce a un código innecesariamente complejo y frágil, especialmente si no tiene control en toda la cadena de herencia. – yaauie