2011-11-29 13 views
8

Ho problemi con ottenere Rails (3.1.3) per caricare alcune sottoclassi ActiveRecord sull'inizializzazione dell'applicazione. Ecco la struttura di directory che ho:Caricamento sottoclassi su rotaia Inizializzazione

- models 
    - class1.rb # Class1 < ActiveRecord::Base 
    - class1s 
    - subclass1.rb # Subclass1 < Class1 
    - subclass2.rb # Subclass2 < Class1 

che sto cercando di fare uso di Class1.subclasses, ma continua a tornare []. L'aggiunta di #{config.root}/app/models/class1s a config.autoload_paths non è d'aiuto, perché tali clases sono caricati in modo pigro e nulla fa riferimento alle sottoclassi prima di effettuare una chiamata a subclasses, quindi sono ancora caricate. Anche l'aggiunta del percorso a config.eager_load_paths non sembra funzionare e il suo comportamento si basa sull'impostazione config.cache_classes che di solito è diversa per lo sviluppo e la produzione.

mi piacerebbe essere in grado di avviare la console rotaie e vedere:

> Class1.subclasses 
=> [Subclass1, Subclass2] 

In questo momento questo è il comportamento che vedo:

> Class1.subclasses 
=> [] 
> Subclass1 
=> Subclass1 
> Class1.subclasses 
=> [Subclass1] 
> Subclass2 
=> Subclass2 
> Class1.subclasses 
=> [Subclass1, Subclass2] 

In questo momento mi sono ridotto a mettere questo in fondo alla mia definizione Class1 per caricare tutte le sottoclassi da caricare quando accedo alla classe Class1:

ruby_files_pattern = File.join(Rails.application.config.root, "app", "models", "class1s", "**", "*.rb") 
Dir.glob(ruby_files_pattern).each do |file| 
    ActiveSupport::Dependencies.require_or_load(file) 
end 

Ha portato a termine il lavoro, ma mi sento sporco a farlo. Qualsiasi pensiero sarebbe molto apprezzato.

risposta

2

Il modo più semplice per farlo, è solo caricare tutte le classi utilizzando (> = 3.0):

Rails.application.eager_load! 

caricherà tutte le classi dalla tua app, motori, plugin. È lo stesso risultato del turno di caricamento lazy in config. Ma in questo approccio non hai bisogno di farlo semplicemente usando questo metodo.

2

Il problema con caricamento ansioso è che una volta che una classe cambia, le sottoclassi non verranno più caricate. Io uso un constantizer nel mio development.rb che rende costante tutte le mie sottoclassi (e.i. sottodirectory) per nome di file su ogni richiesta. Lo metto in lib come alcuni test hanno bisogno di contantilizzare anche le cose.

lib/constantizer.rb

class Constantizer 
    def self.path(path, include_current_path=true, namespace_prefix='') 
    dirs = Dir[Rails.root.join(path, '**', '**')].select { |f| File.directory?(f) && File.basename(f) != 'concerns'} 
    dirs << Rails.root.join(path) if include_current_path 
    dirs.each do |dir| 
     Dir["#{dir}/*.rb"].each do |file| 
     (namespace_prefix + file.chomp(".rb").split("/").last.camelize).constantize 
     end 
    end 
    end 
end 

app/ambiente/development.rb

class ConstantizeAllSubclasses 
    def initialize(app) 
    @app = app 
    end 

    def call(env) 
    Constantizer.path('app/models', false) 
    @app.call(env) 
    end 
end 

Project::Application.configure do 
    # Usual config items 
    config.middleware.insert_after Warden::Manager, ConstantizeAllSubclasses 
end 
0

Eager Loading è disattivata in ambiente di sviluppo per impostazione predefinita.

Attiva da config/environments/development.rb

config.eager_load = true