2013-05-15 8 views
8

Ho seguente configurazione:Richiede la dipendenza per ottenere Rails sottoclassi

app/modelli/my_module/service.rb

module MyModule 
    class Service < ActiveRecord::Base 
    def self.types 
     self.subclasses 
    end 

    def self.raw_types 
     self.types.map { |c| c.name.split("::").last } 
    end 
    end 
end 

require_dependency "my_module/service/rack" 
require_dependency "my_module/service/rails" 
require_dependency "my_module/service/sinatra" 

app/modelli/my_module/servizio/rack.rb:

module MyModule 
    class Service::Rack < Service 
    end 
end 

app/modelli/my_module/servizio/rails.rb:

module MyModule 
    class Service::Rails < Service 
    end 
end 

app/modelli/my_module/servizio/sinatra.rb:

module MyModule 
    class Service::Sinatra < Service 
    end 
end 

che funziona così, ma ora la mia domanda:

Perché devo aggiungere queste tre linee:

require_dependency "my_module/service/rack" 
require_dependency "my_module/service/rails" 
require_dependency "my_module/service/sinatra" 

nel mio file service.rb?

Se non aggiungo le tre linee:

MyModule::Service.raw_types 
=> [] 

Se aggiungo le tre linee:

MyModule::Service.raw_types 
=> ["Rack", "Rails", "Sinatra"] 

Anybody un'idea?

Btw: Io uso di Ruby 2.0.0-preview1, Rails 4.0.0.rc1 e creare un nuovo motore di Rails con

rails plugin new MyModule 
+0

fa MyModule :: Service.types lavoro? –

+0

La domanda è: perché è necessario richiedere i file o perché l'array viene popolato? Quando si richiedono i file si aggiungono 3 classi che fanno parte del sottoclasse Service, quindi 'Service.subclasses' restituisce quelle 3 classi. – Kris

+0

Idea: uno dei file di scimmia "sottoclasse" nella classe. – User

risposta

12

Per impostazione predefinita, nell'ambiente di sviluppo, Rails saranno costanti autoload nel solito sottodirectory di app, cercando nella posizione convenzionale (ad esempio, /app/models/my_module/service/rack.rb per MyModule::Service::Rack). Questo autoloading si verifica quando la costante viene referenziata per la prima volta, non sull'inizializzazione dell'app.

Ma ciò significa che prima che la costante venga referenziata, il file che lo definisce non viene caricato a meno che non sia esplicitamente richiesto.

Pertanto, quando si chiama MyModule::Service.raw_types, MyModule::Service viene caricato da app/models/my_module/service.rb se non è già definito. Tuttavia, se non è stato ancora fatto riferimento alle sue sottoclassi, tali costanti non saranno definite a meno che i file che li definiscono siano esplicitamente richiesti. Pertanto, richiedendo quei file nel file che è caricato automaticamente su quella chiamata di metodo, li rende disponibili.

Morale: se si vuole garantire che le sottoclassi di MyModule::Service sono sempre definite ogni volta MyModule::Service è, è necessario chiedere loro in /app/models/my_module/service.rb

+0

Okay, l'ho già pensato, ma speravo, che Rails risolva l'autoloading mentre il metodo viene chiamato, perché le classi sono necessarie attraverso una chiamata al metodo della classe genitore .. potrebbe essere un bug di Rails? Capisco il caricamento da una "vista rubino", ma non dalla "vista rotaie" .. – Mattherick

+2

Questo non è un bug in Rails. In che modo l'applicazione dovrebbe sapere che quelle costanti sono necessarie quando non sa nemmeno che esistono? Non penso che ci sia alcun danno nel richiedere le sottoclassi nel file che definisce la superclasse. In alternativa, puoi caricarli tutti in config/boot.rb in modo che siano lì sull'inizializzazione dell'app. – gregates

+0

Ma sarebbe davvero buono, se Rails ha un tale comportamento che cerca nella sottocartella che è chiamata come il modulo intorno alla classe genitore per verificare se ci sono sottoclassi definite. Sarebbe grandioso :). Ma comunque li caricherò tutti attraverso il processo di inizializzazione dei binari. – Mattherick

Problemi correlati