Pregunta

Bien, he estado refactorizando 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 la vida fácil).Parte de esta refactorización ha consistido en mover el código que es común a dos de mis modelos a un módulo que puedo incluir donde lo necesito.

Hasta ahora, todo bien.Parece que va a funcionar, pero acabo de encontrarme con un problema que no estoy seguro de cómo solucionar.El módulo (al que he llamado envíable) será simplemente el código que maneja el envío por fax, el correo electrónico o la impresión de un PDF del documento.Entonces, por ejemplo, tengo una orden de compra y órdenes de venta internas (imaginativamente abreviadas como ISO).

El problema que he encontrado es que quiero que se inicialicen algunas variables (inicializadas para personas que no escriben correctamente :P) después de cargar el objeto, así que he estado usando el después_inicializar gancho.Ningún problema...hasta que empiece a agregar algunos mixins más.

El problema que tengo es que puedo tener un after_initialize en cualquiera de mis mixins, por lo que necesito incluir un súper Llame al principio para asegurarse de que el otro mixin after_initialize las llamadas son llamadas.Lo cual es genial, hasta que termino llamando al super y aparece un error porque no hay ningún super al que llamar.

Aquí hay un pequeño ejemplo, en caso de que no haya 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

Entonces, si cada uno de los mixins tiene una llamada after_initialize, con un súper Llama, ¿cómo puedo detener eso último? súper ¿Llamar para que no genere el error?¿Cómo puedo probar que el supermétodo existe antes de llamarlo?

¿Fue útil?

Solución

Puedes usar esto:

super if defined?(super)

Aquí hay un ejemplo:

class A
end

class B < A
  def t
    super if defined?(super)
    puts "Hi from B"
  end
end

B.new.t

Otros consejos

Has probado alias_method_chain?Básicamente puedes encadenar todos tus after_initialize llamadas.Actúa como un decorador:Cada nuevo método agrega una nueva capa de funcionalidad y pasa el control al método "anulado" para hacer el resto.

La clase inclusiva (lo que hereda de ActiveRecord::Base, que en este caso es Iso) podría definir el suyo propio after_initialize, por lo que cualquier solución que no sea alias_method_chain (u otro alias que guarde el original) corre el riesgo de sobrescribir el código.La solución de @Orion Edwards es la mejor que se me ocurre.Hay otros, pero son lejos más pirateado.

alias_method_chain también tiene la ventaja de crear versiones con nombre del método after_initialize, lo que significa que puede personalizar el orden de las llamadas en aquellos raros casos en los que sea importante.De lo contrario, estará a merced del orden en que la clase incluida incluya los mixins.

más tarde:

Publiqué una pregunta en la lista de correo de Ruby-on-rails-core sobre la creación de implementaciones vacías predeterminadas de todas las devoluciones de llamada.El proceso de guardado los busca todos de todos modos, así que no veo por qué no deberían estar allí.El único inconveniente es crear marcos de pila vacíos adicionales, pero eso es bastante económico en todas las implementaciones conocidas.

Puedes simplemente lanzar un condicional rápido allí:

super if respond_to?('super')

y deberías estar bien, sin agregar métodos inútiles;bonito y limpio.

En lugar de comprobar si el supermétodo existe, puedes simplemente definirlo

class ActiveRecord::Base
    def after_initialize
    end
end

Esto funciona en mis pruebas y no debería romper nada de su código existente, porque todas las demás clases que lo definen anularán silenciosamente este método de todos modos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top