Domanda

Ok, così ho potuto refactoring del mio codice nel mio piccolo Rails, nel tentativo di rimuovere la duplicazione, e in generale rendere la vita più facile (come mi piace una vita facile).Parte di questo refactoring, è stato quello di spostare il codice che è comune a due dei miei modelli per un modulo che posso comprendere, se ne ho bisogno.

Così lontano, così buono.Guarda come sta andando a lavorare fuori, ma ho appena colpito un problema che non so come risolvere.Il modulo (che ho chiamato sendable), è solo andare a essere il codice che gestisce l'invio di fax, e-mail, o la stampa di un PDF del documento.Così, per esempio, ho un ordine di acquisto, e devo Interno di Ordini di Vendita (con la fantasia abbreviato ISO).

Il problema l'ho colpito, non è che voglio alcune variabili inizializzate (inizializzato per le persone che non magia correttamente :P ) dopo che l'oggetto è stato caricato, ho usato il after_initialize hook.Nessun problema...fino a quando ho iniziare ad aggiungere alcuni più mixins.

Il problema che ho, è che posso avere un after_initialize in uno dei miei mixins, quindi ho bisogno di includere un super chiamata all'inizio per assicurarsi che le altre mixin after_initialize chiamate chiamato.Che è grande, fino a quando alla fine l'ho chiamata super e ho un errore perché non c'è nessun super chiamare.

Ecco un piccolo esempio, nel caso in cui non sono stato abbastanza 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

Così, se ogni uno dei mixins hanno un after_initialize chiamata, con un super chiamata, come posso impedire che lo scorso super chiamata da generare l'errore?Come si può verificare che il super esiste un metodo prima di chiamare?

È stato utile?

Soluzione

È possibile utilizzare questo:

super if defined?(super)

Ecco un esempio:

class A
end

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

B.new.t

Altri suggerimenti

Hai provato alias_method_chain?Si può sostanzialmente incatenati tutti i tuoi after_initialize le chiamate.Esso agisce come un decoratore:ogni nuovo metodo aggiunge un nuovo livello di funzionalità e passa il controllo sul "override" metodo per fare il resto.

L'compresa la classe (la cosa che eredita da ActiveRecord::Base, che, in questo caso è Iso) potrebbe definire il proprio after_initialize, in modo che qualsiasi soluzione diversa alias_method_chain (o altri aliasing che salva originale) rischi di sovrascrivere il codice.@Orion Edwards soluzione è il meglio che posso venire con.Ci sono altri, ma sono lontano più hackish.

alias_method_chain ha anche il vantaggio di creare versioni con nomi di after_initialize metodo, significa che è possibile personalizzare l'ordine di chiamata in quei rari casi che conta.In caso contrario, sei in balia di qualunque ordine e il classe include i mixins.

più tardi:

Ho postato una domanda per il ruby-on-rails-core mailing list sulla creazione di vuoto di default implementazioni di tutte le richiamate.Il processo di salvataggio dei controlli per tutti, comunque, quindi non vedo perché non dovrebbero essere lì.L'unico aspetto negativo è la creazione di extra vuoto stack frame, ma questo è abbastanza a buon mercato su ogni nota implementazione.

Si può solo gettare un rapido condizionale in là:

super if respond_to?('super')

e non dovrebbero esserci problemi, senza aggiunta di inutili metodi;bella e pulita.

Invece di controllare se il super metodo esiste, si può solo definire

class ActiveRecord::Base
    def after_initialize
    end
end

Questo funziona nel mio test, e non rompono le tue codice esistente, perché tutte le altre classi che definiscono sarà solo silenzio l'override di questo metodo comunque

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top