Caricamento automatico dei file lib in Rails 4


229

Uso la seguente riga in un inizializzatore per caricare automaticamente il codice nella mia /libdirectory durante lo sviluppo:

config / inizializzatori / custom.rb:

RELOAD_LIBS = Dir[Rails.root + 'lib/**/*.rb'] if Rails.env.development?

(da Rails 3 Quicktip: ricarica automaticamente le cartelle lib in modalità sviluppo )

Funziona benissimo, ma è troppo inefficiente da utilizzare in produzione. Invece di caricare librerie su ogni richiesta, voglio solo caricarle all'avvio. Lo stesso blog ha un altro articolo che descrive come eseguire questa operazione:

config / application.rb:

# Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]

Tuttavia, quando passo a quello, anche in fase di sviluppo, ottengo NoMethodErrors quando provo ad usare le funzioni lib.

Esempio di uno dei miei file lib:

lib / extensions.rb:

Time.class_eval do
  def self.milli_stamp
    Time.now.strftime('%Y%m%d%H%M%S%L').to_i
  end
end

La chiamata Time.milli_stampgenererà NoMethodError

Mi rendo conto che altri hanno risposto a domande simili su SO, ma tutti sembrano occuparsi di convenzioni di denominazione e di altri problemi di cui non dovevo preoccuparmi prima- Le mie classi lib già funzionavano per il caricamento per richiesta, voglio solo cambiarlo al caricamento all'avvio . Qual è il modo giusto per farlo?


La cartella config / initializer viene caricata automaticamente all'avvio di un'app Rails?
Jwan622,

Risposte:


548

Penso che questo possa risolvere il tuo problema:

  1. in config / application.rb :

    config.autoload_paths << Rails.root.join('lib')

    e mantenere la giusta convenzione di denominazione in lib .

    in lib / foo.rb :

    class Foo
    end
    

    in lib / foo / bar.rb :

    class Foo::Bar
    end
    
  2. se vuoi davvero fare alcune patch di scimmie in file come lib / extensions.rb , potresti richiederlo manualmente:

    in config / initializer / require.rb :

    require "#{Rails.root}/lib/extensions" 

PS


1
@ ifyouseewendy: hai ragione, perché extensions.rb non stava seguendo le convenzioni di denominazione di Rails, Rails non lo avrebbe incluso nel processo di caricamento. L'ho fatto funzionare richiedendolo manualmente.
Yarin,

@ifyouseewendy come posso includere i file prima che i modelli vengano caricati? aggiungere il percorso per il caricamento automatico è interessante, ma come si controlla l'ordine di inclusione? grazie
Matrix,

@Matrix "includi i file prima che i modelli vengano caricati", potresti richiedere manualmente il tuo file senza usare la funzione di caricamento automatico.
ifyouseewendy,

@ifyouseewendy se lo richiedo nell'inizializzatore ma il file si trova in autoload_path, verrà ricaricato (caricato 2 volte) o no? theire è un "require_once" come in php?
Matrix,

5
Questo non sembra funzionare nell'API di Rails 5 in produzione (ma nello sviluppo). Credo che tu debba usare config.eager_load_paths << Rails.root.join('lib'). Tuttavia, ciò ha un grande svantaggio in quanto eager_load_pathscarica tutto anche nelle attività. Penso che la soluzione di Lulalala sia migliore. Ecco un post sul blog con maggiori dettagli: blog.arkency.com/2014/11/…
hirowatari

33

Anche se questo non risponde direttamente alla domanda, ma penso che sia una buona alternativa per evitare del tutto la domanda.

Per evitare tutto il autoload_pathso eager_load_pathsfastidio, creare un "lib" o una directory "Misc" nella directory "app". Inserisci i codici come faresti normalmente lì, e Rails caricherà i file proprio come caricherà (e ricaricherà) i file modello.


3
Sono in Rails 4.2. e non carica automaticamente i file sotto app, devo farlo manualmente ...... o devo metterlo nel percorso di caricamento automatico ..
Arup Rakshit

6
Ti sbagli, Arup, tutte le sottodirectory della cartella app sei automaticamente nella matrice autoload_paths in Rails 4.2.See edgeguides.rubyonrails.org/...
Dr.Strangelove

Tranne la app/viewsdirectory che non viene aggiunta; o meglio viene esplicitamente rimosso.
James B. Byrne,

1
Bella risposta. L'unica cosa che ha funzionato per me su rotaie 5 / api.
jstafford,

6
Ricorda solo che libè pensato per il codice che può essere applicato a più progetti e che potrebbe essere estratto in una gemma. In caso contrario, crea una cartella più appropriata sotto la ricerca dell'app come services/o presenters/e anche sotto di questi.
PhilT

6

Questo potrebbe aiutare qualcuno come me che trova questa risposta durante la ricerca di soluzioni su come Rails gestisce il caricamento della classe ... Ho scoperto che dovevo definire un modulenome il cui nome corrisponde al mio nome file in modo appropriato, piuttosto che definire una classe:

Nel file lib / development_mail_interceptor.rb (Sì, sto usando il codice di un Railscast :))

module DevelopmentMailInterceptor
  class DevelopmentMailInterceptor
    def self.delivering_email(message)
      message.subject = "intercepted for: #{message.to} #{message.subject}"
      message.to = "myemail@mydomain.org"
    end
  end
end

funziona, ma non si carica se non avessi inserito la classe in un modulo.


1
In ruby ​​"corrispondenza appropriata" significa che il file si trova nel file system in LOAD_PATH/module/class.rb(sottolineato) dove si LOAD_PATHtrova nei percorsi di caricamento utilizzati dall'app Ruby (percorsi_autoload nel caso di Rails). libha oscillato dal caricamento automatico di Rails al mancato caricamento automatico e nelle versioni recenti (> = Rails 3.x) non è caricato automaticamente. Qualunque magia stia facendo questo lavoro per te non è raccomandato. Forse è un vecchio Railscast?
Peter H. Boling,

0

Usa config.to_prepare per caricare patch / estensioni di scimmie per ogni richiesta in modalità di sviluppo.

config.to_prepare do |action_dispatcher|
 # More importantly, will run upon every request in development, but only once (during boot-up) in production and test.
 Rails.logger.info "\n--- Loading extensions for #{self.class} "
 Dir.glob("#{Rails.root}/lib/extensions/**/*.rb").sort.each do |entry|
   Rails.logger.info "Loading extension(s): #{entry}"
   require_dependency "#{entry}"
 end
 Rails.logger.info "--- Loaded extensions for #{self.class}\n"

fine

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.